From 5335ab22e1cb5b196a62270d3bfc11575c683ec0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 11 Oct 2011 00:58:16 +0200 Subject: [PATCH 1/6] Introduced bitfield header struct --- TightDB.vcproj | 5 +- src/AllocSlab.h | 6 +- src/Array.cpp | 1675 +++++++++++++++++++++--------------------- src/ArrayString.cpp | 20 +- src/Column.cpp | 15 +- src/alloc.cpp | 36 +- src/alloc.h | 30 +- src/ctightdb.cpp | 4 +- src/ctightdb.h | 4 +- src/win32/inttypes.h | 305 ++++++++ 10 files changed, 1194 insertions(+), 906 deletions(-) create mode 100644 src/win32/inttypes.h diff --git a/TightDB.vcproj b/TightDB.vcproj index 4d9a8162254..4033c1672b1 100644 --- a/TightDB.vcproj +++ b/TightDB.vcproj @@ -44,11 +44,12 @@ (parent)), m_parentNdx(pndx), m_alloc(alloc) { - Create(ref); + Create(ref); } Array::Array(ColumnDef type, Array* parent, size_t pndx, Allocator& alloc) : m_data(NULL), m_len(0), m_capacity(0), m_width(0), m_isNode(false), m_hasRefs(false), m_parent(parent), m_parentNdx(pndx), m_alloc(alloc) { - if (type == COLUMN_NODE) m_isNode = m_hasRefs = true; - else if (type == COLUMN_HASREFS) m_hasRefs = true; + if (type == COLUMN_NODE) m_isNode = m_hasRefs = true; + else if (type == COLUMN_HASREFS) m_hasRefs = true; - Alloc(0, 0); - SetWidth(0); + Alloc(0, 0); + SetWidth(0); } // Copy-constructor // Note that this array now own the ref. Should only be used when // the source array goes away right after (like return values from functions) Array::Array(const Array& src) : m_parent(src.m_parent), m_parentNdx(src.m_parentNdx), m_alloc(src.m_alloc) { - const size_t ref = src.GetRef(); - Create(ref); + const size_t ref = src.GetRef(); + Create(ref); } void Array::Create(size_t ref) { - assert(ref); - uint8_t* const header = (uint8_t*)m_alloc.Translate(ref); + assert(ref); - // Parse the 8byte header - m_isNode = (header[0] & 0x80) != 0; - m_hasRefs = (header[0] & 0x40) != 0; - m_width = (1 << (header[0] & 0x07)) >> 1; // 0, 1, 2, 4, 8, 16, 32, 64 - m_len = (header[1] << 16) + (header[2] << 8) + header[3]; - m_capacity = (header[4] << 16) + (header[5] << 8) + header[6]; + MemRef::Header* const header = (MemRef::Header*)m_alloc.Translate(ref); + m_isNode = header->isNode; + m_hasRefs = header->hasRefs; + m_width = 1 << (header->width) >> 1; // 0, 1, 2, 4, 8, 16, 32, 64 + m_len = header->count; + m_capacity = header->capacity; - m_ref = ref; - m_data = header + 8; + m_ref = ref; + m_data = (uint8_t*)header + MEMREF_HEADER_SIZE; - SetWidth(m_width); + SetWidth(m_width); } void Array::SetType(ColumnDef type) { - if (type == COLUMN_NODE) m_isNode = m_hasRefs = true; - else if (type == COLUMN_HASREFS) m_hasRefs = true; - else m_isNode = m_hasRefs = false; + if (type == COLUMN_NODE) m_isNode = m_hasRefs = true; + else if (type == COLUMN_HASREFS) m_hasRefs = true; + else m_isNode = m_hasRefs = false; } bool Array::operator==(const Array& a) const { - return m_data == a.m_data; + return m_data == a.m_data; } void Array::UpdateRef(size_t ref) { - Create(ref); + Create(ref); - // Update ref in parent - if (m_parent) m_parent->Set(m_parentNdx, ref); + // Update ref in parent + if (m_parent) m_parent->Set(m_parentNdx, ref); } /** @@ -71,975 +70,963 @@ void Array::UpdateRef(size_t ref) { * Posssible results {0, 1, 2, 4, 8, 16, 32, 64} */ static unsigned int BitWidth(int64_t v) { - if ((v >> 4) == 0) { - static const int8_t bits[] = {0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; - return bits[(int8_t)v]; - } + if ((v >> 4) == 0) { + static const int8_t bits[] = {0, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}; + return bits[(int8_t)v]; + } - // First flip all bits if bit 63 is set (will now always be zero) - if (v < 0) v = ~v; + // First flip all bits if bit 63 is set (will now always be zero) + if (v < 0) v = ~v; - // Then check if bits 15-31 used (32b), 7-31 used (16b), else (8b) - return v >> 31 ? 64 : v >> 15 ? 32 : v >> 7 ? 16 : 8; -} - -static void SetRefSize(void* ref, size_t len) { - uint8_t* const header = (uint8_t*)(ref); - header[1] = ((len >> 16) & 0x000000FF); - header[2] = (len >> 8) & 0x000000FF; - header[3] = len & 0x000000FF; + // Then check if bits 15-31 used (32b), 7-31 used (16b), else (8b) + return (v >> 31) ? 64 : ((v >> 15) ? 32 : ((v >> 7) ? 16 : 8)); } void Array::SetParent(Array* parent, size_t pndx) { - m_parent = parent; - m_parentNdx = pndx; + m_parent = parent; + m_parentNdx = pndx; } Array Array::GetSubArray(size_t ndx) { - assert(ndx < m_len); - assert(m_hasRefs); + assert(ndx < m_len); + assert(m_hasRefs); - const size_t ref = (size_t)Get(ndx); - assert(ref); + const size_t ref = (size_t)Get(ndx); + assert(ref); - return Array(ref, this, ndx, m_alloc); + return Array(ref, this, ndx, m_alloc); } const Array Array::GetSubArray(size_t ndx) const { - assert(ndx < m_len); - assert(m_hasRefs); + assert(ndx < m_len); + assert(m_hasRefs); - return Array((size_t)Get(ndx), this, ndx, m_alloc); + return Array((size_t)Get(ndx), this, ndx, m_alloc); } void Array::Destroy() { - if (!m_data) return; - - if (m_hasRefs) { - for (size_t i = 0; i < Size(); ++i) { - const size_t ref = (size_t)Get(i); - Array sub(ref, this, i, m_alloc); - sub.Destroy(); - } - } - - void* ref = m_data-8; - m_alloc.Free(m_ref, ref); - m_data = NULL; + if (!m_data) return; + + if (m_hasRefs) { + for (size_t i = 0; i < Size(); ++i) { + const size_t ref = (size_t)Get(i); + Array sub(ref, this, i, m_alloc); + sub.Destroy(); + } + } + + m_alloc.Free(m_ref, MEMREF_GET_HEADER(m_data)); + m_data = NULL; } void Array::Clear() { - // Make sure we don't have any dangling references - if (m_hasRefs) { - for (size_t i = 0; i < Size(); ++i) { - Array sub((size_t)Get(i), this, i); - sub.Destroy(); - } - } - - // Truncate size to zero (but keep capacity) - m_len = 0; - SetWidth(0); + // Make sure we don't have any dangling references + if (m_hasRefs) { + for (size_t i = 0; i < Size(); ++i) { + Array sub((size_t)Get(i), this, i); + sub.Destroy(); + } + } + + // Truncate size to zero (but keep capacity) + m_len = 0; + SetWidth(0); } void Array::Delete(size_t ndx) { - assert(ndx < m_len); - - // Move values below deletion up - if (m_width < 8) { - for (size_t i = ndx+1; i < m_len; ++i) { - const int64_t v = (this->*m_getter)(i); - (this->*m_setter)(i-1, v); - } - } - else if (ndx < m_len-1) { - // when byte sized, use memmove - const size_t w = (m_width == 64) ? 8 : (m_width == 32) ? 4 : (m_width == 16) ? 2 : 1; - unsigned char* dst = m_data + (ndx * w); - unsigned char* src = dst + w; - const size_t count = (m_len - ndx - 1) * w; - memmove(dst, src, count); - } - - // Update length (also in header) - --m_len; - SetRefSize(m_data-8, m_len); + assert(ndx < m_len); + + // Move values below deletion up + if (m_width < 8) { + for (size_t i = ndx+1; i < m_len; ++i) { + const int64_t v = (this->*m_getter)(i); + (this->*m_setter)(i-1, v); + } + } + else if (ndx < m_len-1) { + // when byte sized, use memmove + const size_t w = (m_width == 64) ? 8 : (m_width == 32) ? 4 : (m_width == 16) ? 2 : 1; + unsigned char* dst = m_data + (ndx * w); + unsigned char* src = dst + w; + const size_t count = (m_len - ndx - 1) * w; + memmove(dst, src, count); + } + + // Update length (also in header) + --m_len; + MEMREF_GET_HEADER(m_data)->count = m_len; } int64_t Array::Get(size_t ndx) const { - assert(ndx < m_len); - return (this->*m_getter)(ndx); + assert(ndx < m_len); + return (this->*m_getter)(ndx); } int64_t Array::Back() const { - assert(m_len); - return (this->*m_getter)(m_len-1); + assert(m_len); + return (this->*m_getter)(m_len-1); } bool Array::Set(size_t ndx, int64_t value) { - assert(ndx < m_len); - - // Make room for the new value - const size_t width = BitWidth(value); - if (width > m_width) { - Getter oldGetter = m_getter; - if (!Alloc(m_len, width)) return false; - SetWidth(width); - - // Expand the old values - int k = (int)m_len; - while (--k >= 0) { - const int64_t v = (this->*oldGetter)(k); - (this->*m_setter)(k, v); - } - } - - // Set the value - (this->*m_setter)(ndx, value); - - return true; + assert(ndx < m_len); + + // Make room for the new value + const size_t width = BitWidth(value); + if (width > m_width) { + Getter oldGetter = m_getter; + if (!Alloc(m_len, width)) return false; + SetWidth(width); + + // Expand the old values + int k = (int)m_len; + while (--k >= 0) { + const int64_t v = (this->*oldGetter)(k); + (this->*m_setter)(k, v); + } + } + + // Set the value + (this->*m_setter)(ndx, value); + + return true; } bool Array::Insert(size_t ndx, int64_t value) { - assert(ndx <= m_len); - - Getter getter = m_getter; - - // Make room for the new value - const size_t width = BitWidth(value); - const bool doExpand = (width > m_width); - if (doExpand) { - if (!Alloc(m_len+1, width)) return false; - SetWidth(width); - } - else { - if (!Alloc(m_len+1, m_width)) return false; - } - - // Move values below insertion (may expand) - if (doExpand || m_width < 8) { - int k = (int)m_len; - while (--k >= (int)ndx) { - const int64_t v = (this->*getter)(k); - (this->*m_setter)(k+1, v); - } - } - else if (ndx != m_len) { - // when byte sized and no expansion, use memmove - const size_t w = (m_width == 64) ? 8 : (m_width == 32) ? 4 : (m_width == 16) ? 2 : 1; - unsigned char* src = m_data + (ndx * w); - unsigned char* dst = src + w; - const size_t count = (m_len - ndx) * w; - memmove(dst, src, count); - } - - // Insert the new value - (this->*m_setter)(ndx, value); - - // Expand values above insertion - if (doExpand) { - int k = (int)ndx; - while (--k >= 0) { - const int64_t v = (this->*getter)(k); - (this->*m_setter)(k, v); - } - } - - // Update length - // (no need to do it in header as it has been done by Alloc) - ++m_len; - - return true; + assert(ndx <= m_len); + + Getter getter = m_getter; + + // Make room for the new value + const size_t width = BitWidth(value); + const bool doExpand = (width > m_width); + if (doExpand) { + if (!Alloc(m_len+1, width)) return false; + SetWidth(width); + } + else { + if (!Alloc(m_len+1, m_width)) return false; + } + + // Move values below insertion (may expand) + if (doExpand || m_width < 8) { + int k = (int)m_len; + while (--k >= (int)ndx) { + const int64_t v = (this->*getter)(k); + (this->*m_setter)(k+1, v); + } + } + else if (ndx != m_len) { + // when byte sized and no expansion, use memmove + const size_t w = (m_width == 64) ? 8 : (m_width == 32) ? 4 : (m_width == 16) ? 2 : 1; + unsigned char* src = m_data + (ndx * w); + unsigned char* dst = src + w; + const size_t count = (m_len - ndx) * w; + memmove(dst, src, count); + } + + // Insert the new value + (this->*m_setter)(ndx, value); + + // Expand values above insertion + if (doExpand) { + int k = (int)ndx; + while (--k >= 0) { + const int64_t v = (this->*getter)(k); + (this->*m_setter)(k, v); + } + } + + // Update length + // (no need to do it in header as it has been done by Alloc) + ++m_len; + + return true; } bool Array::Add(int64_t value) { - return Insert(m_len, value); + return Insert(m_len, value); } void Array::Resize(size_t count) { - assert(count <= m_len); + assert(count <= m_len); - // Update length (also in header) - m_len = count; - SetRefSize(m_data-8, m_len); + // Update length (also in header) + m_len = count; + MEMREF_GET_HEADER(m_data)->count = m_len; } bool Array::Increment(int64_t value, size_t start, size_t end) { - if (end == -1) end = m_len; - assert(start < m_len); - assert(end >= start && end <= m_len); - - // Increment range - for (size_t i = start; i < end; ++i) { - Set(i, Get(i) + value); - } - return true; + if (end == -1) end = m_len; + assert(start < m_len); + assert(end >= start && end <= m_len); + + // Increment range + for (size_t i = start; i < end; ++i) { + Set(i, Get(i) + value); + } + return true; } bool Array::IncrementIf(int64_t limit, int64_t value) { - // Update (incr or decrement) values bigger or equal to the limit - for (size_t i = 0; i < m_len; ++i) { - const int64_t v = Get(i); - if (v >= limit) Set(i, v + value); - } - return true; + // Update (incr or decrement) values bigger or equal to the limit + for (size_t i = 0; i < m_len; ++i) { + const int64_t v = Get(i); + if (v >= limit) Set(i, v + value); + } + return true; } size_t Array::FindPos(int64_t target) const { - int low = -1; - int high = (int)m_len; - - // Binary search based on: - // http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary - // Finds position of largest value SMALLER than the target (for lookups in - // nodes) - while (high - low > 1) { - const size_t probe = ((unsigned int)low + (unsigned int)high) >> 1; - const int64_t v = (this->*m_getter)(probe); - - if (v > target) high = (int)probe; - else low = (int)probe; - } - if (high == (int)m_len) return (size_t)-1; - else return high; + int low = -1; + int high = (int)m_len; + + // Binary search based on: + // http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary + // Finds position of largest value SMALLER than the target (for lookups in + // nodes) + while (high - low > 1) { + const size_t probe = ((unsigned int)low + (unsigned int)high) >> 1; + const int64_t v = (this->*m_getter)(probe); + + if (v > target) high = (int)probe; + else low = (int)probe; + } + if (high == (int)m_len) return (size_t)-1; + else return high; } size_t Array::FindPos2(int64_t target) const { - int low = -1; - int high = (int)m_len; - - // Binary search based on: - // http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary - // Finds position of closest value BIGGER OR EQUAL to the target (for - // lookups in indexes) - while (high - low > 1) { - const size_t probe = ((unsigned int)low + (unsigned int)high) >> 1; - const int64_t v = (this->*m_getter)(probe); - - if (v < target) low = (int)probe; - else high = (int)probe; - } - if (high == (int)m_len) return (size_t)-1; - else return high; + int low = -1; + int high = (int)m_len; + + // Binary search based on: + // http://www.tbray.org/ongoing/When/200x/2003/03/22/Binary + // Finds position of closest value BIGGER OR EQUAL to the target (for + // lookups in indexes) + while (high - low > 1) { + const size_t probe = ((unsigned int)low + (unsigned int)high) >> 1; + const int64_t v = (this->*m_getter)(probe); + + if (v < target) low = (int)probe; + else high = (int)probe; + } + if (high == (int)m_len) return (size_t)-1; + else return high; } size_t Array::Find(int64_t value, size_t start, size_t end) const { - if (IsEmpty()) return (size_t)-1; - if (end == -1) end = m_len; - if (start == end) return (size_t)-1; - - assert(start < m_len && end <= m_len && start < end); - - // If the value is wider than the column - // then we know it can't be there - const size_t width = BitWidth(value); - if (width > m_width) return (size_t)-1; - - // Do optimized search based on column width - if (m_width == 0) { - return start; // value can only be zero - } - else if (m_width == 2) { - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0x3 * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 32; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x5555555555555555UL) & ~v2 - & 0xAAAAAAAAAAAAAAAAUL; - if (hasZeroByte) break; - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 32; - - // Manually check the rest - while (i < end) { - const size_t offset = i >> 2; - const int64_t v = (m_data[offset] >> ((i & 3) << 1)) & 0x03; - if (v == value) return i; - ++i; - } - } - else if (m_width == 4) { - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xF * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 16; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x1111111111111111UL) & ~v2 - & 0x8888888888888888UL; - if (hasZeroByte) break; - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 16; - - // Manually check the rest - while (i < end) { - const size_t offset = i >> 1; - const int64_t v = (m_data[offset] >> ((i & 1) << 2)) & 0xF; - if (v == value) return i; - ++i; - } - } + if (IsEmpty()) return (size_t)-1; + if (end == -1) end = m_len; + if (start == end) return (size_t)-1; + + assert(start < m_len && end <= m_len && start < end); + + // If the value is wider than the column + // then we know it can't be there + const size_t width = BitWidth(value); + if (width > m_width) return (size_t)-1; + + // Do optimized search based on column width + if (m_width == 0) { + return start; // value can only be zero + } + else if (m_width == 2) { + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0x3 * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 32; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x5555555555555555UL) & ~v2 + & 0xAAAAAAAAAAAAAAAAUL; + if (hasZeroByte) break; + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 32; + + // Manually check the rest + while (i < end) { + const size_t offset = i >> 2; + const int64_t v = (m_data[offset] >> ((i & 3) << 1)) & 0x03; + if (v == value) return i; + ++i; + } + } + else if (m_width == 4) { + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0xF * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 16; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x1111111111111111UL) & ~v2 + & 0x8888888888888888UL; + if (hasZeroByte) break; + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 16; + + // Manually check the rest + while (i < end) { + const size_t offset = i >> 1; + const int64_t v = (m_data[offset] >> ((i & 1) << 2)) & 0xF; + if (v == value) return i; + ++i; + } + } else if (m_width == 8) { - // TODO: Handle partial searches - - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFF * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 8; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x0101010101010101ULL) & ~v2 - & 0x8080808080808080ULL; - if (hasZeroByte) break; - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 8; - const int8_t* d = (const int8_t*)m_data; - - // Manually check the rest - while (i < end) { - if (value == d[i]) return i; - ++i; - } - } - else if (m_width == 16) { - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFFFF * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 4; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x0001000100010001UL) & ~v2 - & 0x8000800080008000UL; - if (hasZeroByte) break; - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 4; - const int16_t* d = (const int16_t*)m_data; - - // Manually check the rest - while (i < end) { - if (value == d[i]) return i; - ++i; - } - } - else if (m_width == 32) { - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFFFFFFFF * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 2; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x0000000100000001UL) & ~v2 - & 0x8000800080000000UL; - if (hasZeroByte) break; - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 2; - const int32_t* d = (const int32_t*)m_data; - - // Manually check the rest - while (i < end) { - if (value == d[i]) return i; - ++i; - } - } - else if (m_width == 64) { - const int64_t v = (int64_t)value; - const int64_t* p = (const int64_t*)m_data + start; - const int64_t* const e = (const int64_t*)m_data + end; - while (p < e) { - if (*p == v) return p - (const int64_t*)m_data; - ++p; - } - } - else { - // Naive search - for (size_t i = start; i < end; ++i) { - const int64_t v = (this->*m_getter)(i); - if (v == value) return i; - } - } - - return (size_t)-1; // not found + // TODO: Handle partial searches + + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0xFF * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 8; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x0101010101010101ULL) & ~v2 + & 0x8080808080808080ULL; + if (hasZeroByte) break; + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 8; + const int8_t* d = (const int8_t*)m_data; + + // Manually check the rest + while (i < end) { + if (value == d[i]) return i; + ++i; + } + } + else if (m_width == 16) { + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0xFFFF * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 4; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x0001000100010001UL) & ~v2 + & 0x8000800080008000UL; + if (hasZeroByte) break; + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 4; + const int16_t* d = (const int16_t*)m_data; + + // Manually check the rest + while (i < end) { + if (value == d[i]) return i; + ++i; + } + } + else if (m_width == 32) { + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0xFFFFFFFF * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 2; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x0000000100000001UL) & ~v2 + & 0x8000800080000000UL; + if (hasZeroByte) break; + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 2; + const int32_t* d = (const int32_t*)m_data; + + // Manually check the rest + while (i < end) { + if (value == d[i]) return i; + ++i; + } + } + else if (m_width == 64) { + const int64_t v = (int64_t)value; + const int64_t* p = (const int64_t*)m_data + start; + const int64_t* const e = (const int64_t*)m_data + end; + while (p < e) { + if (*p == v) return p - (const int64_t*)m_data; + ++p; + } + } + else { + // Naive search + for (size_t i = start; i < end; ++i) { + const int64_t v = (this->*m_getter)(i); + if (v == value) return i; + } + } + + return (size_t)-1; // not found } void Array::FindAll(Column& result, int64_t value, size_t colOffset, - size_t start, size_t end) const { - if (IsEmpty()) return; - if (end == -1) end = m_len; - if (start == end) return; - - assert(start < m_len && end <= m_len && start < end); - - // If the value is wider than the column - // then we know it can't be there - const size_t width = BitWidth(value); - if (width > m_width) return; - - // Do optimized search based on column width - if (m_width == 0) { - for(size_t i = start; i < end; i++){ - result.Add(i + colOffset); // All values can only be zero. - } - } - else if (m_width == 2) { - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0x3 * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 32; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x5555555555555555UL) & ~v2 - & 0xAAAAAAAAAAAAAAAAUL; - if (hasZeroByte){ - // Element number at start of block - size_t i = (p - (const int64_t*)m_data) * 32; - // Last element of block - size_t j = i + 32; - - // check block - while (i < j) { - const size_t offset = i >> 2; - const int64_t v = (m_data[offset] >> ((i & 3) << 1)) & 0x03; - if (v == value) result.Add(i + colOffset); - ++i; - } - } - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 32; - - // Manually check the rest - while (i < end) { - const size_t offset = i >> 2; - const int64_t v = (m_data[offset] >> ((i & 3) << 1)) & 0x03; - if (v == value) result.Add(i + colOffset); - ++i; - } - } - else if (m_width == 4) { - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xF * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 16; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x1111111111111111UL) & ~v2 - & 0x8888888888888888UL; - if (hasZeroByte){ - // Element number at start of block - size_t i = (p - (const int64_t*)m_data) * 16; - // Last element of block - size_t j = i + 16; - - // check block - while (i < j) { - const size_t offset = i >> 1; - const int64_t v = (m_data[offset] >> ((i & 1) << 2)) & 0xF; - if (v == value) result.Add(i + colOffset); - ++i; - } - } - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 16; - - // Manually check the rest - while (i < end) { - const size_t offset = i >> 1; - const int64_t v = (m_data[offset] >> ((i & 1) << 2)) & 0xF; - if (v == value) result.Add(i + colOffset); - ++i; - } - } - else if (m_width == 8) { - // TODO: Handle partial searches - - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFF * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 8; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x0101010101010101ULL) & ~v2 - & 0x8080808080808080ULL; - if (hasZeroByte){ - // Element number at start of block - size_t i = (p - (const int64_t*)m_data) * 8; - // Last element of block - size_t j = i + 8; - // Data pointer - const int8_t* d = (const int8_t*)m_data; - - // check block - while (i < j) { - if (value == d[i]) result.Add(i + colOffset); - ++i; - } - } - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 8; - const int8_t* d = (const int8_t*)m_data; - - // Manually check the rest - while (i < end) { - if (value == d[i]) result.Add(i + colOffset); - ++i; - } - } - else if (m_width == 16) { - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFFFF * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 4; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x0001000100010001UL) & ~v2 - & 0x8000800080008000UL; - if (hasZeroByte){ - // Element number at start of block - size_t i = (p - (const int64_t*)m_data) * 4; - // Last element of block - size_t j = i + 4; - // Data pointer - const int16_t* d = (const int16_t*)m_data; - - // check block - while (i < j) { - if (value == d[i]) result.Add(i + colOffset); - ++i; - } - } - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 4; - const int16_t* d = (const int16_t*)m_data; - - // Manually check the rest - while (i < end) { - if (value == d[i]) result.Add(i + colOffset); - ++i; - } - } - else if (m_width == 32) { - // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFFFFFFFF * value; - - const int64_t* p = (const int64_t*)m_data + start; - const size_t end64 = m_len / 2; - const int64_t* const e = (const int64_t*)m_data + end64; - - // Check 64bits at a time for match - while (p < e) { - const uint64_t v2 = *p ^ v; // zero matching bit segments - const uint64_t hasZeroByte = (v2 - 0x0000000100000001UL) & ~v2 - & 0x8000800080000000UL; - if (hasZeroByte){ - // Element number at start of block - size_t i = (p - (const int64_t*)m_data) * 2; - // Last element of block - size_t j = i + 2; - // Data pointer - const int32_t* d = (const int32_t*)m_data; - - // check block - while (i < j) { - if (value == d[i]) result.Add(i + colOffset); - ++i; - } - } - ++p; - } - - // Position of last chunk (may be partial) - size_t i = (p - (const int64_t*)m_data) * 2; - const int32_t* d = (const int32_t*)m_data; - - // Manually check the rest - while (i < end) { - if (value == d[i]) result.Add(i + colOffset); - ++i; - } - } - else if (m_width == 64) { - const int64_t v = (int64_t)value; - const int64_t* p = (const int64_t*)m_data + start; - const int64_t* const e = (const int64_t*)m_data + end; - while (p < e) { - if (*p == v) result.Add((p - (const int64_t*)m_data) + colOffset); - ++p; - } - } - else { - // Naive search - for (size_t i = start; i < end; ++i) { - const int64_t v = (this->*m_getter)(i); - if (v == value) result.Add(i + colOffset); - } - } + size_t start, size_t end) const { + if (IsEmpty()) return; + if (end == -1) end = m_len; + if (start == end) return; + + assert(start < m_len && end <= m_len && start < end); + + // If the value is wider than the column + // then we know it can't be there + const size_t width = BitWidth(value); + if (width > m_width) return; + + // Do optimized search based on column width + if (m_width == 0) { + for(size_t i = start; i < end; i++){ + result.Add(i + colOffset); // All values can only be zero. + } + } + else if (m_width == 2) { + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0x3 * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 32; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x5555555555555555UL) & ~v2 + & 0xAAAAAAAAAAAAAAAAUL; + if (hasZeroByte){ + // Element number at start of block + size_t i = (p - (const int64_t*)m_data) * 32; + // Last element of block + size_t j = i + 32; + + // check block + while (i < j) { + const size_t offset = i >> 2; + const int64_t v = (m_data[offset] >> ((i & 3) << 1)) & 0x03; + if (v == value) result.Add(i + colOffset); + ++i; + } + } + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 32; + + // Manually check the rest + while (i < end) { + const size_t offset = i >> 2; + const int64_t v = (m_data[offset] >> ((i & 3) << 1)) & 0x03; + if (v == value) result.Add(i + colOffset); + ++i; + } + } + else if (m_width == 4) { + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0xF * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 16; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x1111111111111111UL) & ~v2 + & 0x8888888888888888UL; + if (hasZeroByte){ + // Element number at start of block + size_t i = (p - (const int64_t*)m_data) * 16; + // Last element of block + size_t j = i + 16; + + // check block + while (i < j) { + const size_t offset = i >> 1; + const int64_t v = (m_data[offset] >> ((i & 1) << 2)) & 0xF; + if (v == value) result.Add(i + colOffset); + ++i; + } + } + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 16; + + // Manually check the rest + while (i < end) { + const size_t offset = i >> 1; + const int64_t v = (m_data[offset] >> ((i & 1) << 2)) & 0xF; + if (v == value) result.Add(i + colOffset); + ++i; + } + } + else if (m_width == 8) { + // TODO: Handle partial searches + + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0xFF * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 8; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x0101010101010101ULL) & ~v2 + & 0x8080808080808080ULL; + if (hasZeroByte){ + // Element number at start of block + size_t i = (p - (const int64_t*)m_data) * 8; + // Last element of block + size_t j = i + 8; + // Data pointer + const int8_t* d = (const int8_t*)m_data; + + // check block + while (i < j) { + if (value == d[i]) result.Add(i + colOffset); + ++i; + } + } + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 8; + const int8_t* d = (const int8_t*)m_data; + + // Manually check the rest + while (i < end) { + if (value == d[i]) result.Add(i + colOffset); + ++i; + } + } + else if (m_width == 16) { + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0xFFFF * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 4; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x0001000100010001UL) & ~v2 + & 0x8000800080008000UL; + if (hasZeroByte){ + // Element number at start of block + size_t i = (p - (const int64_t*)m_data) * 4; + // Last element of block + size_t j = i + 4; + // Data pointer + const int16_t* d = (const int16_t*)m_data; + + // check block + while (i < j) { + if (value == d[i]) result.Add(i + colOffset); + ++i; + } + } + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 4; + const int16_t* d = (const int16_t*)m_data; + + // Manually check the rest + while (i < end) { + if (value == d[i]) result.Add(i + colOffset); + ++i; + } + } + else if (m_width == 32) { + // Create a pattern to match 64bits at a time + const int64_t v = ~0ULL/0xFFFFFFFF * value; + + const int64_t* p = (const int64_t*)m_data + start; + const size_t end64 = m_len / 2; + const int64_t* const e = (const int64_t*)m_data + end64; + + // Check 64bits at a time for match + while (p < e) { + const uint64_t v2 = *p ^ v; // zero matching bit segments + const uint64_t hasZeroByte = (v2 - 0x0000000100000001UL) & ~v2 + & 0x8000800080000000UL; + if (hasZeroByte){ + // Element number at start of block + size_t i = (p - (const int64_t*)m_data) * 2; + // Last element of block + size_t j = i + 2; + // Data pointer + const int32_t* d = (const int32_t*)m_data; + + // check block + while (i < j) { + if (value == d[i]) result.Add(i + colOffset); + ++i; + } + } + ++p; + } + + // Position of last chunk (may be partial) + size_t i = (p - (const int64_t*)m_data) * 2; + const int32_t* d = (const int32_t*)m_data; + + // Manually check the rest + while (i < end) { + if (value == d[i]) result.Add(i + colOffset); + ++i; + } + } + else if (m_width == 64) { + const int64_t v = (int64_t)value; + const int64_t* p = (const int64_t*)m_data + start; + const int64_t* const e = (const int64_t*)m_data + end; + while (p < e) { + if (*p == v) result.Add((p - (const int64_t*)m_data) + colOffset); + ++p; + } + } + else { + // Naive search + for (size_t i = start; i < end; ++i) { + const int64_t v = (this->*m_getter)(i); + if (v == value) result.Add(i + colOffset); + } + } } void Array::FindAllHamming(Column& result, uint64_t value, size_t maxdist, size_t offset) const { - // Only implemented for 64bit values - if (m_width != 64) { - assert(false); - return; - } + // Only implemented for 64bit values + if (m_width != 64) { + assert(false); + return; + } - const uint64_t* p = (const uint64_t*)m_data; - const uint64_t* const e = (const uint64_t*)m_data + m_len; + const uint64_t* p = (const uint64_t*)m_data; + const uint64_t* const e = (const uint64_t*)m_data + m_len; - // static values needed for population count - const uint64_t m1 = 0x5555555555555555; - const uint64_t m2 = 0x3333333333333333; - const uint64_t m4 = 0x0f0f0f0f0f0f0f0f; - const uint64_t h01 = 0x0101010101010101; + // static values needed for population count + const uint64_t m1 = 0x5555555555555555; + const uint64_t m2 = 0x3333333333333333; + const uint64_t m4 = 0x0f0f0f0f0f0f0f0f; + const uint64_t h01 = 0x0101010101010101; - while (p < e) { - uint64_t x = *p ^ value; + while (p < e) { + uint64_t x = *p ^ value; - // population count + // population count #if defined(WIN32) && defined(SSE42) - x = _mm_popcnt_u64(x); // msvc sse4.2 intrinsic + x = _mm_popcnt_u64(x); // msvc sse4.2 intrinsic #elif defined(GCC) - x = __builtin_popcountll(x); // gcc intrinsic + x = __builtin_popcountll(x); // gcc intrinsic #else - x -= (x >> 1) & m1; - x = (x & m2) + ((x >> 2) & m2); - x = (x + (x >> 4)) & m4; - x = (x * h01)>>56; + x -= (x >> 1) & m1; + x = (x & m2) + ((x >> 2) & m2); + x = (x + (x >> 4)) & m4; + x = (x * h01)>>56; #endif - if (x < maxdist) { - const size_t pos = p - (const uint64_t*)m_data; - result.Add64(offset + pos); - } + if (x < maxdist) { + const size_t pos = p - (const uint64_t*)m_data; + result.Add64(offset + pos); + } - ++p; - } + ++p; + } } bool Array::Alloc(size_t count, size_t width) { - // Calculate size in bytes - size_t len = 8; // always need room for header - switch (width) { - case 0: - break; - case 1: - len += count >> 3; - if (count & 0x07) ++len; - break; - case 2: - len += count >> 2; - if (count & 0x03) ++len; - break; - case 4: - len += count >> 1; - if (count & 0x01) ++len; - break; - default: - assert(width == 8 || width == 16 || width == 32 || width == 64); - len += count * (width >> 3); - } - - if (len > m_capacity) { - // Try to expand with 50% to avoid to many reallocs - size_t new_capacity = m_capacity ? m_capacity + m_capacity / 2 : 128; - if (new_capacity < len) new_capacity = len; - - // Allocate the space - MemRef mref; - if (m_data) mref = m_alloc.ReAlloc(m_data-8, new_capacity); - else mref = m_alloc.Alloc(new_capacity); - - if (!mref.pointer) return false; - - m_ref = mref.ref; - m_data = (unsigned char*)mref.pointer + 8; - m_capacity = new_capacity; - - // Update ref in parent - if (m_parent) m_parent->Set(m_parentNdx, mref.ref); //TODO: ref - } - - // Pack width in 3 bits (log2) - unsigned int w = 0; - unsigned int b = (unsigned int)width; - while (b) {++w; b >>= 1;} - assert(0 <= w && w < 8); - - // Update 8-byte header - // isNode 1 bit, hasRefs 1 bit, 3 bits unused, width 3 bits, len 3 bytes, - // capacity 3 bytes - uint8_t* const header = (uint8_t*)(m_data-8); - header[0] = m_isNode << 7; - header[0] += m_hasRefs << 6; - header[0] += (uint8_t)w; - header[1] = (count >> 16) & 0x000000FF; - header[2] = (count >> 8) & 0x000000FF; - header[3] = count & 0x000000FF; - header[4] = (m_capacity >> 16) & 0x000000FF; - header[5] = (m_capacity >> 8) & 0x000000FF; - header[6] = m_capacity & 0x000000FF; - - return true; + // Calculate size in bytes + size_t len = MEMREF_HEADER_SIZE; // always need room for header + switch (width) { + case 0: + break; + case 1: + len += count >> 3; + if (count & 0x07) ++len; + break; + case 2: + len += count >> 2; + if (count & 0x03) ++len; + break; + case 4: + len += count >> 1; + if (count & 0x01) ++len; + break; + default: + assert(width == 8 || width == 16 || width == 32 || width == 64); + len += count * (width >> 3); + } + + if (len > m_capacity) { + // Try to expand with 50% to avoid to many reallocs + size_t new_capacity = m_capacity ? m_capacity + m_capacity / 2 : 128; + if (new_capacity < len) new_capacity = len; + + // Allocate the space + MemRef mref; + if (m_data) mref = m_alloc.ReAlloc(MEMREF_GET_HEADER(m_data), new_capacity); + else mref = m_alloc.Alloc(new_capacity); + + if (!mref.pointer) return false; + + m_ref = mref.ref; + m_data = (unsigned char*)mref.pointer + MEMREF_HEADER_SIZE; + m_capacity = new_capacity; + + // Update ref in parent + if (m_parent) m_parent->Set(m_parentNdx, mref.ref); //TODO: ref + } + + // Pack width in 3 bits (log2) + unsigned int w = 0; + unsigned int b = (unsigned int)width; + while (b) {++w; b >>= 1;} + assert(0 <= w && w < 8); + + // Update 8-byte header + // isNode 1 bit, hasRefs 1 bit, 3 bits unused, width 3 bits, len 3 bytes, + // capacity 3 bytes + MemRef::Header* const header = MEMREF_GET_HEADER(m_data); + header->isNode = m_isNode; + header->hasRefs = m_hasRefs; + header->width = w; + header->count = count; + header->capacity = m_capacity; + + return true; } void Array::SetWidth(size_t width) { - if (width == 0) { - m_getter = &Array::Get_0b; - m_setter = &Array::Set_0b; - } - else if (width == 1) { - m_getter = &Array::Get_1b; - m_setter = &Array::Set_1b; - } - else if (width == 2) { - m_getter = &Array::Get_2b; - m_setter = &Array::Set_2b; - } - else if (width == 4) { - m_getter = &Array::Get_4b; - m_setter = &Array::Set_4b; - } - else if (width == 8) { - m_getter = &Array::Get_8b; - m_setter = &Array::Set_8b; - } - else if (width == 16) { - m_getter = &Array::Get_16b; - m_setter = &Array::Set_16b; - } - else if (width == 32) { - m_getter = &Array::Get_32b; - m_setter = &Array::Set_32b; - } - else if (width == 64) { - m_getter = &Array::Get_64b; - m_setter = &Array::Set_64b; - } - else { - assert(false); - } - - m_width = width; + if (width == 0) { + m_getter = &Array::Get_0b; + m_setter = &Array::Set_0b; + } + else if (width == 1) { + m_getter = &Array::Get_1b; + m_setter = &Array::Set_1b; + } + else if (width == 2) { + m_getter = &Array::Get_2b; + m_setter = &Array::Set_2b; + } + else if (width == 4) { + m_getter = &Array::Get_4b; + m_setter = &Array::Set_4b; + } + else if (width == 8) { + m_getter = &Array::Get_8b; + m_setter = &Array::Set_8b; + } + else if (width == 16) { + m_getter = &Array::Get_16b; + m_setter = &Array::Set_16b; + } + else if (width == 32) { + m_getter = &Array::Get_32b; + m_setter = &Array::Set_32b; + } + else if (width == 64) { + m_getter = &Array::Get_64b; + m_setter = &Array::Set_64b; + } + else { + assert(false); + } + + m_width = width; } int64_t Array::Get_0b(size_t) const { - return 0; + return 0; } int64_t Array::Get_1b(size_t ndx) const { - const size_t offset = ndx >> 3; - return (m_data[offset] >> (ndx & 7)) & 0x01; + const size_t offset = ndx >> 3; + return (m_data[offset] >> (ndx & 7)) & 0x01; } int64_t Array::Get_2b(size_t ndx) const { - const size_t offset = ndx >> 2; - return (m_data[offset] >> ((ndx & 3) << 1)) & 0x03; + const size_t offset = ndx >> 2; + return (m_data[offset] >> ((ndx & 3) << 1)) & 0x03; } int64_t Array::Get_4b(size_t ndx) const { - const size_t offset = ndx >> 1; - return (m_data[offset] >> ((ndx & 1) << 2)) & 0x0F; + const size_t offset = ndx >> 1; + return (m_data[offset] >> ((ndx & 1) << 2)) & 0x0F; } int64_t Array::Get_8b(size_t ndx) const { - return *((const signed char*)(m_data + ndx)); + return *((const signed char*)(m_data + ndx)); } int64_t Array::Get_16b(size_t ndx) const { - const size_t offset = ndx * 2; - return *(const int16_t*)(m_data + offset); + const size_t offset = ndx * 2; + return *(const int16_t*)(m_data + offset); } int64_t Array::Get_32b(size_t ndx) const { - const size_t offset = ndx * 4; - return *(const int32_t*)(m_data + offset); + const size_t offset = ndx * 4; + return *(const int32_t*)(m_data + offset); } int64_t Array::Get_64b(size_t ndx) const { - const size_t offset = ndx * 8; - return *(const int64_t*)(m_data + offset); + const size_t offset = ndx * 8; + return *(const int64_t*)(m_data + offset); } void Array::Set_0b(size_t, int64_t) { } void Array::Set_1b(size_t ndx, int64_t value) { - const size_t offset = ndx >> 3; - ndx &= 7; + const size_t offset = ndx >> 3; + ndx &= 7; - uint8_t* p = &m_data[offset]; - *p = (*p &~ (1 << ndx)) | (((uint8_t)value & 1) << ndx); + uint8_t* p = &m_data[offset]; + *p = (*p &~ (1 << ndx)) | (((uint8_t)value & 1) << ndx); } void Array::Set_2b(size_t ndx, int64_t value) { - const size_t offset = ndx >> 2; - const uint8_t n = (ndx & 3) << 1; + const size_t offset = ndx >> 2; + const uint8_t n = (ndx & 3) << 1; - uint8_t* p = &m_data[offset]; - *p = (*p &~ (0x03 << n)) | (((uint8_t)value & 0x03) << n); + uint8_t* p = &m_data[offset]; + *p = (*p &~ (0x03 << n)) | (((uint8_t)value & 0x03) << n); } void Array::Set_4b(size_t ndx, int64_t value) { - const size_t offset = ndx >> 1; - const uint8_t n = (ndx & 1) << 2; + const size_t offset = ndx >> 1; + const uint8_t n = (ndx & 1) << 2; - uint8_t* p = &m_data[offset]; - *p = (*p &~ (0x0F << n)) | (((uint8_t)value & 0x0F) << n); + uint8_t* p = &m_data[offset]; + *p = (*p &~ (0x0F << n)) | (((uint8_t)value & 0x0F) << n); } void Array::Set_8b(size_t ndx, int64_t value) { - *((char*)m_data + ndx) = (char)value; + *((char*)m_data + ndx) = (char)value; } void Array::Set_16b(size_t ndx, int64_t value) { - const size_t offset = ndx * 2; - *(int16_t*)(m_data + offset) = (int16_t)value; + const size_t offset = ndx * 2; + *(int16_t*)(m_data + offset) = (int16_t)value; } void Array::Set_32b(size_t ndx, int64_t value) { - const size_t offset = ndx * 4; - *(int32_t*)(m_data + offset) = (int32_t)value; + const size_t offset = ndx * 4; + *(int32_t*)(m_data + offset) = (int32_t)value; } void Array::Set_64b(size_t ndx, int64_t value) { - const size_t offset = ndx * 8; - *(int64_t*)(m_data + offset) = value; + const size_t offset = ndx * 8; + *(int64_t*)(m_data + offset) = value; } void Array::Sort() { - DoSort(0, m_len-1); + DoSort(0, m_len-1); } void Array::DoSort(size_t lo, size_t hi) { - // Quicksort based on - // http://www.inf.fh-flensburg.de/lang/algorithmen/sortieren/quick/quicken.htm - int i = (int)lo; - int j = (int)hi; - - // comparison element x - const size_t ndx = (lo + hi)/2; - const int64_t x = (size_t)Get(ndx); - - // partition - do { - while (Get(i) < x) i++; - while (Get(j) > x) j--; - if (i <= j) { - const int64_t h = Get(i); - Set(i, Get(j)); - Set(j, h); - i++; j--; - } - } while (i <= j); - - // recursion - if ((int)lo < j) DoSort(lo, j); - if (i < (int)hi) DoSort(i, hi); + // Quicksort based on + // http://www.inf.fh-flensburg.de/lang/algorithmen/sortieren/quick/quicken.htm + int i = (int)lo; + int j = (int)hi; + + // comparison element x + const size_t ndx = (lo + hi)/2; + const int64_t x = (size_t)Get(ndx); + + // partition + do { + while (Get(i) < x) i++; + while (Get(j) > x) j--; + if (i <= j) { + const int64_t h = Get(i); + Set(i, Get(j)); + Set(j, h); + i++; j--; + } + } while (i <= j); + + // recursion + if ((int)lo < j) DoSort(lo, j); + if (i < (int)hi) DoSort(i, hi); } #ifdef _DEBUG #include "stdio.h" void Array::Print() const { - printf("%zx: (%zu) ", GetRef(), Size()); - for (size_t i = 0; i < Size(); ++i) { - if (i) printf(", "); - printf("%d", (int)Get(i)); - } - printf("\n"); + printf("%zx: (%zu) ", GetRef(), Size()); + for (size_t i = 0; i < Size(); ++i) { + if (i) printf(", "); + printf("%d", (int)Get(i)); + } + printf("\n"); } void Array::Verify() const { - assert(m_width == 0 || m_width == 1 || m_width == 2 || m_width == 4 || m_width == 8 || m_width == 16 || m_width == 32 || m_width == 64); + assert(m_width == 0 || m_width == 1 || m_width == 2 || m_width == 4 || m_width == 8 || m_width == 16 || m_width == 32 || m_width == 64); } void Array::ToDot(FILE* f, bool) const{ - const size_t ref = GetRef(); - - fprintf(f, "n%zx [label=\"", ref); - - //if (!horizontal) fprintf(f, "{"); - for (size_t i = 0; i < m_len; ++i) { - if (i > 0) fprintf(f, " | "); - - if (m_hasRefs) fprintf(f, "<%zu>",i); - else fprintf(f, "%lld", Get(i)); - } - //if (!horizontal) fprintf(f, "}"); - - fprintf(f, "\"];\n"); - - if (m_hasRefs) { - for (size_t i = 0; i < m_len; ++i) { - fprintf(f, "n%zx:%zu -> n%lld\n", ref, i, Get(i)); - } - } - fprintf(f, "\n"); + const size_t ref = GetRef(); + + fprintf(f, "n%zx [label=\"", ref); + + //if (!horizontal) fprintf(f, "{"); + for (size_t i = 0; i < m_len; ++i) { + if (i > 0) fprintf(f, " | "); + + if (m_hasRefs) fprintf(f, "<%zu>",i); + else fprintf(f, "%lld", Get(i)); + } + //if (!horizontal) fprintf(f, "}"); + + fprintf(f, "\"];\n"); + + if (m_hasRefs) { + for (size_t i = 0; i < m_len; ++i) { + fprintf(f, "n%zx:%zu -> n%lld\n", ref, i, Get(i)); + } + } + fprintf(f, "\n"); } #endif //_DEBUG diff --git a/src/ArrayString.cpp b/src/ArrayString.cpp index a14ad0cddcb..60074fd96c2 100644 --- a/src/ArrayString.cpp +++ b/src/ArrayString.cpp @@ -182,7 +182,7 @@ bool ArrayString::Alloc(size_t count, size_t width) { if (width < m_width) width = m_width; // width can only expand // Calculate size in bytes - const size_t len = 8 + (count * width); // always need room for header + const size_t len = MEMREF_HEADER_SIZE + (count * width); // always need room for header if (len > m_capacity) { // Try to expand with 50% to avoid to many reallocs @@ -191,7 +191,7 @@ bool ArrayString::Alloc(size_t count, size_t width) { // Allocate the space MemRef mref; - if (m_data) mref = m_alloc.ReAlloc(m_data-8, new_capacity); + if (m_data) mref = m_alloc.ReAlloc(MEMREF_GET_HEADER(m_data), new_capacity); else mref = m_alloc.Alloc(new_capacity); if (!mref.pointer) return false; @@ -212,16 +212,12 @@ bool ArrayString::Alloc(size_t count, size_t width) { // Update 8-byte header // isNode 1 bit, hasRefs 1 bit, 3 bits unused, width 3 bits, len 3 bytes, capacity 3 bytes - uint8_t* const header = (uint8_t*)(m_data-8); - header[0] = m_isNode << 7; - header[0] += m_hasRefs << 6; - header[0] += (uint8_t)w; - header[1] = (count >> 16) & 0x000000FF; - header[2] = (count >> 8) & 0x000000FF; - header[3] = count & 0x000000FF; - header[4] = (m_capacity >> 16) & 0x000000FF; - header[5] = (m_capacity >> 8) & 0x000000FF; - header[6] = m_capacity & 0x000000FF; + MemRef::Header* const header = MEMREF_GET_HEADER(m_data); + header->isNode = m_isNode; + header->hasRefs = m_hasRefs; + header->width = w; + header->count = count; + header->capacity = m_capacity; m_width = width; return true; diff --git a/src/Column.cpp b/src/Column.cpp index 4b3f8bfa087..1307d7db075 100644 --- a/src/Column.cpp +++ b/src/Column.cpp @@ -17,9 +17,6 @@ #define MAX_LIST_SIZE 1000 #endif -// Pre-declare local functions -void SetRefSize(void* ref, size_t len); - Column::Column(Allocator& alloc) : m_array(COLUMN_NORMAL, NULL, 0, alloc), m_index(NULL) { Create(); } @@ -306,16 +303,8 @@ Column::NodeChange Column::DoInsert(size_t ndx, int64_t value) { } size_t Column::GetRefSize(size_t ref) const { - // parse the length part of 8byte header - const uint8_t* const header = (uint8_t*)m_array.GetAllocator().Translate(ref); - return (header[1] << 16) + (header[2] << 8) + header[3]; -} - -void SetRefSize(void* ref, size_t len) { - uint8_t* const header = (uint8_t*)(ref); - header[1] = ((len >> 16) & 0x000000FF); - header[2] = (len >> 8) & 0x000000FF; - header[3] = len & 0x000000FF; + MemRef::Header* const header = (MemRef::Header*)m_array.GetAllocator().Translate(ref); + return header->count; } bool Column::NodeInsert(size_t ndx, size_t ref) { diff --git a/src/alloc.cpp b/src/alloc.cpp index 27f5880f31a..1e6698a7e45 100644 --- a/src/alloc.cpp +++ b/src/alloc.cpp @@ -1,11 +1,6 @@ #include "AllocSlab.h" #include -// Pre-declare local functions -size_t GetSizeFromHeader(void* p); - -SlabAlloc::SlabAlloc() : m_shared(NULL), m_baseline(10) {} - SlabAlloc::~SlabAlloc() { #ifdef _DEBUG assert(IsAllFree()); @@ -63,16 +58,9 @@ MemRef SlabAlloc::Alloc(size_t size) { return MemRef(slab, slabsBack); } -// Support function -size_t GetSizeFromHeader(void* p) { - // parse the capacity part of 8byte header - const uint8_t* const header = (uint8_t*)p; - return (header[4] << 16) + (header[5] << 8) + header[6]; -} - -void SlabAlloc::Free(size_t ref, void* p) { +void SlabAlloc::Free(size_t ref, MemRef::Header* header) { // Get size from segment - const size_t size = GetSizeFromHeader(p); + const size_t size = header->count; const size_t refEnd = ref + size; bool isMerged = false; @@ -92,7 +80,7 @@ void SlabAlloc::Free(size_t ref, void* p) { const size_t count = m_freeSpace.GetSize(); for (size_t i = 0; i < count; ++i) { FreeSpace::Cursor c = m_freeSpace[i]; - const size_t end = c.ref + c.size; + const size_t end = (size_t)(c.ref + c.size); if (ref == end) { if (isMerged) { c.size += m_freeSpace[n].size; @@ -109,7 +97,7 @@ void SlabAlloc::Free(size_t ref, void* p) { if (!isMerged) m_freeSpace.Add(ref, size); } -MemRef SlabAlloc::ReAlloc(size_t ref, void* p, size_t size, bool doCopy=true) { +MemRef SlabAlloc::ReAlloc(size_t ref, MemRef::Header* header, size_t size, bool doCopy=true) { //TODO: Check if we can extend current space // Allocate new space @@ -118,13 +106,13 @@ MemRef SlabAlloc::ReAlloc(size_t ref, void* p, size_t size, bool doCopy=true) { if (doCopy) { // Get size of old segment - const size_t oldsize = GetSizeFromHeader(p); + const size_t oldsize = header->count; // Copy existing segment - memcpy(space.pointer, p, oldsize); + memcpy(space.pointer, header, oldsize); // Add old segment to freelist - Free(ref, p); + Free(ref, header); } return space; @@ -150,13 +138,13 @@ bool SlabAlloc::IsAllFree() const { size_t ref = m_baseline; for (size_t i = 0; i < m_slabs.GetSize(); ++i) { const Slabs::Cursor c = m_slabs[i]; - const size_t size = c.offset - ref; + const size_t size = (size_t)(c.offset - ref); const size_t r = m_freeSpace.ref.Find(ref); if (r == (size_t)-1) return false; if (size != (size_t)m_freeSpace[r].size) return false; - ref = c.offset; + ref = (size_t)c.offset; } return true; } @@ -165,13 +153,13 @@ void SlabAlloc::Verify() const { // Make sure that all free blocks fit within a slab for (size_t i = 0; i < m_freeSpace.GetSize(); ++i) { const FreeSpace::Cursor c = m_freeSpace[i]; - const size_t ref = c.ref; + const size_t ref = (size_t)c.ref; const size_t ndx = m_slabs.offset.FindPos(ref); assert(ndx != -1); - const size_t slab_end = m_slabs[ndx].offset; - const size_t free_end = ref + c.size; + const size_t slab_end = (size_t)m_slabs[ndx].offset; + const size_t free_end = (size_t)(ref + c.size); assert(free_end <= slab_end); } diff --git a/src/alloc.h b/src/alloc.h index d1322404cc4..9702f98896d 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -9,19 +9,41 @@ #include // unint8_t etc #endif +#define MEMREF_HEADER_SIZE sizeof(MemRef::Header) +#define MEMREF_GET_HEADER(p) ((MemRef::Header*)((uint8_t*)(p)-MEMREF_HEADER_SIZE)) + struct MemRef { MemRef() : pointer(NULL), ref(0) {} MemRef(void* p, size_t r) : pointer(p), ref(r) {} void* pointer; size_t ref; + + struct Header { // 64 bit + uint32_t width : 3; + uint32_t unused1 : 3; + uint32_t hasRefs : 1; + uint32_t isNode : 1; + uint32_t count : 24; + uint32_t capacity : 24; + uint32_t unused2 : 8; + }; }; class Allocator { public: - virtual MemRef Alloc(size_t size) {void* p = malloc(size); return MemRef(p,(size_t)p);} - virtual MemRef ReAlloc(void* p, size_t size) {void* p2 = realloc(p, size); return MemRef(p2,(size_t)p2);} - virtual void Free(size_t, void* p) {return free(p);} - virtual void* Translate(size_t ref) const {return (void*)ref;} + + virtual MemRef Alloc(size_t size) { + void* p = malloc(size); return MemRef(p,(size_t)p); + } + virtual MemRef ReAlloc(MemRef::Header* header, size_t size) { + void* p = realloc(header, size); return MemRef(p,(size_t)p); + } + virtual void Free(size_t, MemRef::Header* header) { + return free(header); + } + virtual void* Translate(size_t ref) const { + return (void*)ref; + } #ifdef _DEBUG virtual void Verify() const {}; diff --git a/src/ctightdb.cpp b/src/ctightdb.cpp index 762697bcfb6..68430c247ee 100644 --- a/src/ctightdb.cpp +++ b/src/ctightdb.cpp @@ -4,7 +4,7 @@ #include // Pre-declare local functions -void table_insert_impl(Table* t, size_t ndx, va_list ap); +// extern "C" { @@ -109,7 +109,7 @@ void table_insert_impl(Table* t, size_t ndx, va_list ap) { case COLUMN_TYPE_BOOL: { const int v = va_arg(ap, int); - t->InsertBool(i, ndx, v); + t->InsertBool(i, ndx, v != 0); } break; case COLUMN_TYPE_DATE: diff --git a/src/ctightdb.h b/src/ctightdb.h index bb1f0e46127..f81395d6f23 100644 --- a/src/ctightdb.h +++ b/src/ctightdb.h @@ -16,8 +16,8 @@ extern "C" { #endif typedef enum ColumnType ColumnType; -typedef struct Table Table; -typedef struct TableView TableView; +typedef class Table Table; +typedef class TableView TableView; /*** Table ************************************/ diff --git a/src/win32/inttypes.h b/src/win32/inttypes.h new file mode 100644 index 00000000000..4b3828a2162 --- /dev/null +++ b/src/win32/inttypes.h @@ -0,0 +1,305 @@ +// ISO C9x compliant inttypes.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. The name of the author may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_INTTYPES_H_ // [ +#define _MSC_INTTYPES_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdint.h" + +// 7.8 Format conversion of integer types + +typedef struct { + intmax_t quot; + intmax_t rem; +} imaxdiv_t; + +// 7.8.1 Macros for format specifiers + +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 + +// The fprintf macros for signed integers are: +#define PRId8 "d" +#define PRIi8 "i" +#define PRIdLEAST8 "d" +#define PRIiLEAST8 "i" +#define PRIdFAST8 "d" +#define PRIiFAST8 "i" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIdLEAST16 "hd" +#define PRIiLEAST16 "hi" +#define PRIdFAST16 "hd" +#define PRIiFAST16 "hi" + +#define PRId32 "I32d" +#define PRIi32 "I32i" +#define PRIdLEAST32 "I32d" +#define PRIiLEAST32 "I32i" +#define PRIdFAST32 "I32d" +#define PRIiFAST32 "I32i" + +#define PRId64 "I64d" +#define PRIi64 "I64i" +#define PRIdLEAST64 "I64d" +#define PRIiLEAST64 "I64i" +#define PRIdFAST64 "I64d" +#define PRIiFAST64 "I64i" + +#define PRIdMAX "I64d" +#define PRIiMAX "I64i" + +#define PRIdPTR "Id" +#define PRIiPTR "Ii" + +// The fprintf macros for unsigned integers are: +#define PRIo8 "o" +#define PRIu8 "u" +#define PRIx8 "x" +#define PRIX8 "X" +#define PRIoLEAST8 "o" +#define PRIuLEAST8 "u" +#define PRIxLEAST8 "x" +#define PRIXLEAST8 "X" +#define PRIoFAST8 "o" +#define PRIuFAST8 "u" +#define PRIxFAST8 "x" +#define PRIXFAST8 "X" + +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" +#define PRIoLEAST16 "ho" +#define PRIuLEAST16 "hu" +#define PRIxLEAST16 "hx" +#define PRIXLEAST16 "hX" +#define PRIoFAST16 "ho" +#define PRIuFAST16 "hu" +#define PRIxFAST16 "hx" +#define PRIXFAST16 "hX" + +#define PRIo32 "I32o" +#define PRIu32 "I32u" +#define PRIx32 "I32x" +#define PRIX32 "I32X" +#define PRIoLEAST32 "I32o" +#define PRIuLEAST32 "I32u" +#define PRIxLEAST32 "I32x" +#define PRIXLEAST32 "I32X" +#define PRIoFAST32 "I32o" +#define PRIuFAST32 "I32u" +#define PRIxFAST32 "I32x" +#define PRIXFAST32 "I32X" + +#define PRIo64 "I64o" +#define PRIu64 "I64u" +#define PRIx64 "I64x" +#define PRIX64 "I64X" +#define PRIoLEAST64 "I64o" +#define PRIuLEAST64 "I64u" +#define PRIxLEAST64 "I64x" +#define PRIXLEAST64 "I64X" +#define PRIoFAST64 "I64o" +#define PRIuFAST64 "I64u" +#define PRIxFAST64 "I64x" +#define PRIXFAST64 "I64X" + +#define PRIoMAX "I64o" +#define PRIuMAX "I64u" +#define PRIxMAX "I64x" +#define PRIXMAX "I64X" + +#define PRIoPTR "Io" +#define PRIuPTR "Iu" +#define PRIxPTR "Ix" +#define PRIXPTR "IX" + +// The fscanf macros for signed integers are: +#define SCNd8 "d" +#define SCNi8 "i" +#define SCNdLEAST8 "d" +#define SCNiLEAST8 "i" +#define SCNdFAST8 "d" +#define SCNiFAST8 "i" + +#define SCNd16 "hd" +#define SCNi16 "hi" +#define SCNdLEAST16 "hd" +#define SCNiLEAST16 "hi" +#define SCNdFAST16 "hd" +#define SCNiFAST16 "hi" + +#define SCNd32 "ld" +#define SCNi32 "li" +#define SCNdLEAST32 "ld" +#define SCNiLEAST32 "li" +#define SCNdFAST32 "ld" +#define SCNiFAST32 "li" + +#define SCNd64 "I64d" +#define SCNi64 "I64i" +#define SCNdLEAST64 "I64d" +#define SCNiLEAST64 "I64i" +#define SCNdFAST64 "I64d" +#define SCNiFAST64 "I64i" + +#define SCNdMAX "I64d" +#define SCNiMAX "I64i" + +#ifdef _WIN64 // [ +# define SCNdPTR "I64d" +# define SCNiPTR "I64i" +#else // _WIN64 ][ +# define SCNdPTR "ld" +# define SCNiPTR "li" +#endif // _WIN64 ] + +// The fscanf macros for unsigned integers are: +#define SCNo8 "o" +#define SCNu8 "u" +#define SCNx8 "x" +#define SCNX8 "X" +#define SCNoLEAST8 "o" +#define SCNuLEAST8 "u" +#define SCNxLEAST8 "x" +#define SCNXLEAST8 "X" +#define SCNoFAST8 "o" +#define SCNuFAST8 "u" +#define SCNxFAST8 "x" +#define SCNXFAST8 "X" + +#define SCNo16 "ho" +#define SCNu16 "hu" +#define SCNx16 "hx" +#define SCNX16 "hX" +#define SCNoLEAST16 "ho" +#define SCNuLEAST16 "hu" +#define SCNxLEAST16 "hx" +#define SCNXLEAST16 "hX" +#define SCNoFAST16 "ho" +#define SCNuFAST16 "hu" +#define SCNxFAST16 "hx" +#define SCNXFAST16 "hX" + +#define SCNo32 "lo" +#define SCNu32 "lu" +#define SCNx32 "lx" +#define SCNX32 "lX" +#define SCNoLEAST32 "lo" +#define SCNuLEAST32 "lu" +#define SCNxLEAST32 "lx" +#define SCNXLEAST32 "lX" +#define SCNoFAST32 "lo" +#define SCNuFAST32 "lu" +#define SCNxFAST32 "lx" +#define SCNXFAST32 "lX" + +#define SCNo64 "I64o" +#define SCNu64 "I64u" +#define SCNx64 "I64x" +#define SCNX64 "I64X" +#define SCNoLEAST64 "I64o" +#define SCNuLEAST64 "I64u" +#define SCNxLEAST64 "I64x" +#define SCNXLEAST64 "I64X" +#define SCNoFAST64 "I64o" +#define SCNuFAST64 "I64u" +#define SCNxFAST64 "I64x" +#define SCNXFAST64 "I64X" + +#define SCNoMAX "I64o" +#define SCNuMAX "I64u" +#define SCNxMAX "I64x" +#define SCNXMAX "I64X" + +#ifdef _WIN64 // [ +# define SCNoPTR "I64o" +# define SCNuPTR "I64u" +# define SCNxPTR "I64x" +# define SCNXPTR "I64X" +#else // _WIN64 ][ +# define SCNoPTR "lo" +# define SCNuPTR "lu" +# define SCNxPTR "lx" +# define SCNXPTR "lX" +#endif // _WIN64 ] + +#endif // __STDC_FORMAT_MACROS ] + +// 7.8.2 Functions for greatest-width integer types + +// 7.8.2.1 The imaxabs function +#define imaxabs _abs64 + +// 7.8.2.2 The imaxdiv function + +// This is modified version of div() function from Microsoft's div.c found +// in %MSVC.NET%\crt\src\div.c +#ifdef STATIC_IMAXDIV // [ +static +#else // STATIC_IMAXDIV ][ +_inline +#endif // STATIC_IMAXDIV ] +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) +{ + imaxdiv_t result; + + result.quot = numer / denom; + result.rem = numer % denom; + + if (numer < 0 && result.rem > 0) { + // did division wrong; must fix up + ++result.quot; + result.rem -= denom; + } + + return result; +} + +// 7.8.2.3 The strtoimax and strtoumax functions +#define strtoimax _strtoi64 +#define strtoumax _strtoui64 + +// 7.8.2.4 The wcstoimax and wcstoumax functions +#define wcstoimax _wcstoi64 +#define wcstoumax _wcstoui64 + + +#endif // _MSC_INTTYPES_H_ ] From 51acacbf8a0bc350aaf15501c7133eb04127cb19 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Oct 2011 23:43:12 +0200 Subject: [PATCH 2/6] Review commit 2 --- TightDB.vcproj | 4 +++ src/AllocSlab.h | 2 +- src/Array.cpp | 69 ++++++++++++++++++++-------------------- src/Array.h | 20 +++++++++--- src/ArrayString.cpp | 42 ++++++++++-------------- src/Column.cpp | 2 +- src/alloc.cpp | 18 ++++++++--- src/alloc.h | 2 +- test/testarraystring.cpp | 15 +++++++++ 9 files changed, 103 insertions(+), 71 deletions(-) diff --git a/TightDB.vcproj b/TightDB.vcproj index 4033c1672b1..24ad6eec23a 100644 --- a/TightDB.vcproj +++ b/TightDB.vcproj @@ -43,6 +43,7 @@ /> isNode; m_hasRefs = header->hasRefs; m_width = 1 << (header->width) >> 1; // 0, 1, 2, 4, 8, 16, 32, 64 - m_len = header->count; + m_len = header->length; m_capacity = header->capacity; m_ref = ref; @@ -130,6 +130,7 @@ void Array::Clear() { // Truncate size to zero (but keep capacity) m_len = 0; + MEMREF_GET_HEADER(m_data)->length = m_len; SetWidth(0); } @@ -146,15 +147,15 @@ void Array::Delete(size_t ndx) { else if (ndx < m_len-1) { // when byte sized, use memmove const size_t w = (m_width == 64) ? 8 : (m_width == 32) ? 4 : (m_width == 16) ? 2 : 1; - unsigned char* dst = m_data + (ndx * w); - unsigned char* src = dst + w; + uint8_t* dst = m_data + (ndx * w); + uint8_t* src = dst + w; const size_t count = (m_len - ndx - 1) * w; memmove(dst, src, count); } // Update length (also in header) --m_len; - MEMREF_GET_HEADER(m_data)->count = m_len; + MEMREF_GET_HEADER(m_data)->length = m_len; } int64_t Array::Get(size_t ndx) const { @@ -206,33 +207,36 @@ bool Array::Insert(size_t ndx, int64_t value) { else { if (!Alloc(m_len+1, m_width)) return false; } + + // Load setter to local stack variable (saves 1 instruction in move-loop) + Setter setter = m_setter; // Move values below insertion (may expand) if (doExpand || m_width < 8) { int k = (int)m_len; while (--k >= (int)ndx) { const int64_t v = (this->*getter)(k); - (this->*m_setter)(k+1, v); + (this->*setter)(k+1, v); } } else if (ndx != m_len) { // when byte sized and no expansion, use memmove const size_t w = (m_width == 64) ? 8 : (m_width == 32) ? 4 : (m_width == 16) ? 2 : 1; - unsigned char* src = m_data + (ndx * w); - unsigned char* dst = src + w; + uint8_t* src = m_data + (ndx * w); + uint8_t* dst = src + w; const size_t count = (m_len - ndx) * w; memmove(dst, src, count); } // Insert the new value - (this->*m_setter)(ndx, value); + (this->*setter)(ndx, value); // Expand values above insertion if (doExpand) { int k = (int)ndx; while (--k >= 0) { const int64_t v = (this->*getter)(k); - (this->*m_setter)(k, v); + (this->*setter)(k, v); } } @@ -243,16 +247,12 @@ bool Array::Insert(size_t ndx, int64_t value) { return true; } -bool Array::Add(int64_t value) { - return Insert(m_len, value); -} - void Array::Resize(size_t count) { assert(count <= m_len); // Update length (also in header) m_len = count; - MEMREF_GET_HEADER(m_data)->count = m_len; + MEMREF_GET_HEADER(m_data)->length = m_len; } bool Array::Increment(int64_t value, size_t start, size_t end) { @@ -332,7 +332,7 @@ size_t Array::Find(int64_t value, size_t start, size_t end) const { } else if (m_width == 2) { // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0x3 * value; + const int64_t v = (~0ULL/0x3) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 32; @@ -360,7 +360,7 @@ size_t Array::Find(int64_t value, size_t start, size_t end) const { } else if (m_width == 4) { // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xF * value; + const int64_t v = (~0ULL/0xF) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 16; @@ -390,7 +390,7 @@ size_t Array::Find(int64_t value, size_t start, size_t end) const { // TODO: Handle partial searches // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFF * value; + const int64_t v = (~0ULL/0xFF) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 8; @@ -417,7 +417,7 @@ size_t Array::Find(int64_t value, size_t start, size_t end) const { } else if (m_width == 16) { // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFFFF * value; + const int64_t v = (~0ULL/0xFFFF) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 4; @@ -444,7 +444,7 @@ size_t Array::Find(int64_t value, size_t start, size_t end) const { } else if (m_width == 32) { // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFFFFFFFF * value; + const int64_t v = (~0ULL/0xFFFFFFFF) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 2; @@ -479,7 +479,7 @@ size_t Array::Find(int64_t value, size_t start, size_t end) const { } } else { - // Naive search + // Naive search (MP: For one bit searches - could be optimized) for (size_t i = start; i < end; ++i) { const int64_t v = (this->*m_getter)(i); if (v == value) return i; @@ -510,7 +510,7 @@ void Array::FindAll(Column& result, int64_t value, size_t colOffset, } else if (m_width == 2) { // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0x3 * value; + const int64_t v = (~0ULL/0x3) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 32; @@ -551,7 +551,7 @@ void Array::FindAll(Column& result, int64_t value, size_t colOffset, } else if (m_width == 4) { // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xF * value; + const int64_t v = (~0ULL/0xF) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 16; @@ -594,7 +594,7 @@ void Array::FindAll(Column& result, int64_t value, size_t colOffset, // TODO: Handle partial searches // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFF * value; + const int64_t v = (~0ULL/0xFF) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 8; @@ -634,7 +634,7 @@ void Array::FindAll(Column& result, int64_t value, size_t colOffset, } else if (m_width == 16) { // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFFFF * value; + const int64_t v = (~0ULL/0xFFFF) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 4; @@ -674,7 +674,7 @@ void Array::FindAll(Column& result, int64_t value, size_t colOffset, } else if (m_width == 32) { // Create a pattern to match 64bits at a time - const int64_t v = ~0ULL/0xFFFFFFFF * value; + const int64_t v = (~0ULL/0xFFFFFFFF) * value; const int64_t* p = (const int64_t*)m_data + start; const size_t end64 = m_len / 2; @@ -722,7 +722,7 @@ void Array::FindAll(Column& result, int64_t value, size_t colOffset, } } else { - // Naive search + // Naive search (MP: For one bit searches - could be optimized) for (size_t i = start; i < end; ++i) { const int64_t v = (this->*m_getter)(i); if (v == value) result.Add(i + colOffset); @@ -770,8 +770,6 @@ void Array::FindAllHamming(Column& result, uint64_t value, size_t maxdist, size_ } } - - bool Array::Alloc(size_t count, size_t width) { // Calculate size in bytes size_t len = MEMREF_HEADER_SIZE; // always need room for header @@ -808,7 +806,7 @@ bool Array::Alloc(size_t count, size_t width) { if (!mref.pointer) return false; m_ref = mref.ref; - m_data = (unsigned char*)mref.pointer + MEMREF_HEADER_SIZE; + m_data = (uint8_t*)mref.pointer + MEMREF_HEADER_SIZE; m_capacity = new_capacity; // Update ref in parent @@ -828,7 +826,7 @@ bool Array::Alloc(size_t count, size_t width) { header->isNode = m_isNode; header->hasRefs = m_hasRefs; header->width = w; - header->count = count; + header->length = count; header->capacity = m_capacity; return true; @@ -972,13 +970,16 @@ void Array::DoSort(size_t lo, size_t hi) { const size_t ndx = (lo + hi)/2; const int64_t x = (size_t)Get(ndx); + // use local getter in loop + Getter get = m_getter; + // partition do { - while (Get(i) < x) i++; - while (Get(j) > x) j--; + while ((this->*get)(i) < x) i++; + while ((this->*get)(j) > x) j--; if (i <= j) { - const int64_t h = Get(i); - Set(i, Get(j)); + const int64_t h = (this->*get)(i); + Set(i, (this->*get)(j)); Set(j, h); i++; j--; } diff --git a/src/Array.h b/src/Array.h index a4655295a40..13bb99a6a27 100644 --- a/src/Array.h +++ b/src/Array.h @@ -13,6 +13,7 @@ #ifdef _DEBUG #include +#include #endif // Pre-definitions @@ -38,14 +39,25 @@ class Array { void SetParent(Array* parent, size_t pndx); void UpdateRef(size_t ref); - size_t Size() const {return m_len;} - bool IsEmpty() const {return m_len == 0;} + size_t Size() const { +#ifdef _DEBUG + assert(MEMREF_GET_HEADER(m_data)->length == m_len); +#endif + return m_len; + } + + bool IsEmpty() const {return m_len == 0;} bool Insert(size_t ndx, int64_t value); - bool Add(int64_t value); + + inline bool Add(int64_t value) { + return Insert(m_len, value); + } + bool Set(size_t ndx, int64_t value); int64_t Get(size_t ndx) const; - int64_t operator[](size_t ndx) const {return Get(ndx);} + + int64_t operator[](size_t ndx) const {return Get(ndx);} int64_t Back() const; void Delete(size_t ndx); void Clear(); diff --git a/src/ArrayString.cpp b/src/ArrayString.cpp index 60074fd96c2..928fe44cc61 100644 --- a/src/ArrayString.cpp +++ b/src/ArrayString.cpp @@ -5,6 +5,8 @@ #include "ArrayString.h" +// MP: What about wide strings (Unicode)? + ArrayString::ArrayString(Allocator& alloc) : Array(COLUMN_NORMAL, NULL, 0, alloc) { } @@ -53,25 +55,19 @@ bool ArrayString::Set(size_t ndx, const char* value, size_t len) { // Expand the old values int k = (int)m_len; while (--k >= 0) { - //const char* v = (const char*)m_data + (k * oldwidth); + const char* v = (const char*)m_data + (k * oldwidth); - // Move the value - char* data = (char*)m_data + (ndx * m_width); - char* const end = data + m_width; - memmove(data, value, oldwidth); - for (data += oldwidth; data < end; ++data) { - *data = '\0'; // pad with zeroes - } + // Move the value + char* data = (char*)m_data + (k * m_width); + memmove(data, v, oldwidth); + memset (data + oldwidth, '\0', (size_t)(m_width - oldwidth)); // pad with zeroes } } // Set the value char* data = (char*)m_data + (ndx * m_width); - char* const end = data + m_width; memmove(data, value, len); - for (data += len; data < end; ++data) { - *data = '\0'; // pad with zeroes - } + memset (data + len, '\0', (size_t)(m_width - len)); // pad with zeroes return true; } @@ -92,6 +88,7 @@ bool ArrayString::Insert(size_t ndx, const char* value, size_t len) { // Special case for lists of zero-length strings if (len == 0 && m_width == 0) { m_len += 1; + MEMREF_GET_HEADER(m_data)->length = m_len; return true; } @@ -119,11 +116,8 @@ bool ArrayString::Insert(size_t ndx, const char* value, size_t len) { // Move the value char* data = (char*)m_data + ((k+1) * m_width); - char* const end = data + m_width; memmove(data, v, oldwidth); - for (data += oldwidth; data < end; ++data) { - *data = '\0'; // pad with zeroes - } + memset (data + oldwidth, '\0', (size_t)(m_width - oldwidth)); // pad with zeroes } } else if (ndx != m_len) { @@ -136,11 +130,8 @@ bool ArrayString::Insert(size_t ndx, const char* value, size_t len) { // Set the value char* data = (char*)m_data + (ndx * m_width); - char* const end = data + m_width; memmove(data, value, len); - for (data += len; data < end; ++data) { - *data = '\0'; // pad with zeroes - } + memset (data + len, '\0', (size_t)(m_width - len)); // pad with zeroes // Expand values above insertion if (doExpand) { @@ -150,11 +141,8 @@ bool ArrayString::Insert(size_t ndx, const char* value, size_t len) { // Move the value char* data = (char*)m_data + (k * m_width); - char* const end = data + m_width; memmove(data, v, oldwidth); - for (data += oldwidth; data < end; ++data) { - *data = '\0'; // pad with zeroes - } + memset (data + oldwidth, '\0', (size_t)(m_width - oldwidth)); // pad with zeroes } } @@ -165,7 +153,9 @@ bool ArrayString::Insert(size_t ndx, const char* value, size_t len) { void ArrayString::Delete(size_t ndx) { assert(ndx < m_len); - --m_len; + // Update length (also in header) + --m_len; + MEMREF_GET_HEADER(m_data)->length = m_len; // move data under deletion up if (ndx < m_len) { @@ -216,7 +206,7 @@ bool ArrayString::Alloc(size_t count, size_t width) { header->isNode = m_isNode; header->hasRefs = m_hasRefs; header->width = w; - header->count = count; + header->length = count; header->capacity = m_capacity; m_width = width; diff --git a/src/Column.cpp b/src/Column.cpp index 1307d7db075..bdacd3776a9 100644 --- a/src/Column.cpp +++ b/src/Column.cpp @@ -304,7 +304,7 @@ Column::NodeChange Column::DoInsert(size_t ndx, int64_t value) { size_t Column::GetRefSize(size_t ref) const { MemRef::Header* const header = (MemRef::Header*)m_array.GetAllocator().Translate(ref); - return header->count; + return header->length; } bool Column::NodeInsert(size_t ndx, size_t ref) { diff --git a/src/alloc.cpp b/src/alloc.cpp index 1e6698a7e45..6a731fe8007 100644 --- a/src/alloc.cpp +++ b/src/alloc.cpp @@ -1,6 +1,14 @@ #include "AllocSlab.h" #include +#define ALLOC_SLAB_SIZE 256 +#define ALLOC_SLAB_BASELINE 10 + +// MP: This class is not ready for review + +SlabAlloc::SlabAlloc() : m_shared(NULL), m_baseline(ALLOC_SLAB_BASELINE) { +} + SlabAlloc::~SlabAlloc() { #ifdef _DEBUG assert(IsAllFree()); @@ -34,7 +42,7 @@ MemRef SlabAlloc::Alloc(size_t size) { } // Else, allocate new slab - const size_t multible = 256 * ((size / 256) + 1); + const size_t multible = ALLOC_SLAB_SIZE * ((size / ALLOC_SLAB_SIZE) + 1); const size_t slabsBack = m_slabs.IsEmpty() ? m_baseline : m_slabs.Back().offset; const size_t doubleLast = m_slabs.IsEmpty() ? 0 : (slabsBack - (m_slabs.GetSize() == 1) ? (size_t)0 : m_slabs[-2].offset) * 2; @@ -60,7 +68,7 @@ MemRef SlabAlloc::Alloc(size_t size) { void SlabAlloc::Free(size_t ref, MemRef::Header* header) { // Get size from segment - const size_t size = header->count; + const size_t size = header->capacity; const size_t refEnd = ref + size; bool isMerged = false; @@ -98,7 +106,8 @@ void SlabAlloc::Free(size_t ref, MemRef::Header* header) { } MemRef SlabAlloc::ReAlloc(size_t ref, MemRef::Header* header, size_t size, bool doCopy=true) { - //TODO: Check if we can extend current space + //TODO: Check if we can extend current space + //MP: Not reviewed (not unit tested) // Allocate new space const MemRef space = Alloc(size); @@ -106,7 +115,7 @@ MemRef SlabAlloc::ReAlloc(size_t ref, MemRef::Header* header, size_t size, bool if (doCopy) { // Get size of old segment - const size_t oldsize = header->count; + const size_t oldsize = header->length; // Copy existing segment memcpy(space.pointer, header, oldsize); @@ -119,6 +128,7 @@ MemRef SlabAlloc::ReAlloc(size_t ref, MemRef::Header* header, size_t size, bool } void* SlabAlloc::Translate(size_t ref) const { + //MP: Not reviewed - m_baseline arbitrary and m_shared is undefined if (ref < m_baseline) return m_shared + ref; else { const size_t ndx = m_slabs.offset.FindPos(ref); diff --git a/src/alloc.h b/src/alloc.h index 9702f98896d..91420b651a0 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -23,7 +23,7 @@ struct MemRef { uint32_t unused1 : 3; uint32_t hasRefs : 1; uint32_t isNode : 1; - uint32_t count : 24; + uint32_t length : 24; uint32_t capacity : 24; uint32_t unused2 : 8; }; diff --git a/test/testarraystring.cpp b/test/testarraystring.cpp index 699cae2f461..e5a9a7522fa 100644 --- a/test/testarraystring.cpp +++ b/test/testarraystring.cpp @@ -191,6 +191,21 @@ TEST_FIXTURE(db_setup_string, ArrayStringInsert3) { CHECK_EQUAL(6, c.Size()); } +TEST_FIXTURE(db_setup_string, ArrayStringSet2) { + // Create new list + c.Clear(); + c.Add("aaaa"); + c.Set(0, "bbbbbbbb"); + + CHECK_EQUAL("bbbbbbbb", c.Get(0)); + + c.Add("cccc"); + c.Set(1, "dddddddddddddddd"); + + CHECK_EQUAL("bbbbbbbb", c.Get(0)); + CHECK_EQUAL("dddddddddddddddd", c.Get(1)); +} + TEST_FIXTURE(db_setup_string, ArrayStringFind1) { // Create new list c.Clear(); From 54d38decadeb230ac60de1de770eac637a88165f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 18 Oct 2011 00:03:13 +0200 Subject: [PATCH 3/6] Review --- src/ArrayString.cpp | 4 ++-- src/Column.cpp | 26 ++++++++++++++++++-------- src/Column.h | 7 +++++-- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/ArrayString.cpp b/src/ArrayString.cpp index 928fe44cc61..682a03a199a 100644 --- a/src/ArrayString.cpp +++ b/src/ArrayString.cpp @@ -176,7 +176,7 @@ bool ArrayString::Alloc(size_t count, size_t width) { if (len > m_capacity) { // Try to expand with 50% to avoid to many reallocs - size_t new_capacity = m_capacity ? m_capacity + m_capacity / 2 : 128; + size_t new_capacity = m_capacity ? (m_capacity + (m_capacity / 2)) : 128; if (new_capacity < len) new_capacity = len; // Allocate the space @@ -187,7 +187,7 @@ bool ArrayString::Alloc(size_t count, size_t width) { if (!mref.pointer) return false; m_ref = mref.ref; - m_data = (unsigned char*)mref.pointer + 8; + m_data = (unsigned char*)mref.pointer + MEMREF_HEADER_SIZE; m_capacity = new_capacity; // Update ref in parent diff --git a/src/Column.cpp b/src/Column.cpp index bdacd3776a9..9ba8366b9a1 100644 --- a/src/Column.cpp +++ b/src/Column.cpp @@ -53,6 +53,7 @@ bool Column::operator==(const Column& column) const { } Column::~Column() { + // MP: Shouldn't arrays and index be destroyed here? We could leek if object goes out of scope and destroy is not called delete m_index; // does not destroy index! } @@ -109,13 +110,19 @@ const Column Column::GetSubColumn(size_t ndx) const { }*/ void Column::Clear() { - m_array.Clear(); - if (m_array.IsNode()) m_array.SetType(COLUMN_NORMAL); + if (m_array.IsNode()) { + m_array.GetSubArray(0).Clear(); + m_array.GetSubArray(1).Clear(); + } + else { + m_array.Clear(); + } } int64_t Column::Get64(size_t ndx) const { if (IsNode()) { - // Get subnode table + // Get subnode table + // MP: Should be refactored to Column class holding 'offset' and 'refs' arrays as members const Array offsets = m_array.GetSubArray(0); const Array refs = m_array.GetSubArray(1); @@ -138,8 +145,9 @@ bool Column::Set64(size_t ndx, int64_t value) { if (IsNode()) { // Get subnode table + // MP: Should be refactored to Column class holding 'offset' and 'refs' arrays as members const Array offsets = m_array.GetSubArray(0); - Array refs = m_array.GetSubArray(1); + const Array refs = m_array.GetSubArray(1); // Find the subnode containing the item const size_t node_ndx = offsets.FindPos(ndx); @@ -164,10 +172,6 @@ bool Column::Set64(size_t ndx, int64_t value) { return true; } -bool Column::Add64(int64_t value) { - return Insert64(Size(), value); -} - bool Column::Insert64(size_t ndx, int64_t value) { assert(ndx <= Size()); @@ -222,6 +226,7 @@ bool Column::Insert64(size_t ndx, int64_t value) { Column::NodeChange Column::DoInsert(size_t ndx, int64_t value) { if (IsNode()) { // Get subnode table + // MP: Should be refactored to Column class holding 'offset' and 'refs' arrays as members Array offsets = m_array.GetSubArray(0); Array refs = m_array.GetSubArray(1); @@ -311,6 +316,7 @@ bool Column::NodeInsert(size_t ndx, size_t ref) { assert(ref); assert(IsNode()); + // MP: Should be refactored to Column class holding 'offset' and 'refs' arrays as members Array offsets = m_array.GetSubArray(0); Array refs = m_array.GetSubArray(1); assert(ndx <= offsets.Size()); @@ -330,6 +336,7 @@ bool Column::NodeAdd(size_t ref) { assert(ref); assert(IsNode()); + // MP: Should be refactored to Column class holding 'offset' and 'refs' arrays as members Array offsets = m_array.GetSubArray(0); Array refs = m_array.GetSubArray(1); const Column col(ref); @@ -342,6 +349,7 @@ bool Column::NodeAdd(size_t ref) { bool Column::NodeUpdateOffsets(size_t ndx) { assert(IsNode()); + // MP: Should be refactored to Column class holding 'offset' and 'refs' arrays as members Array offsets = m_array.GetSubArray(0); Array refs = m_array.GetSubArray(1); assert(ndx < offsets.Size()); @@ -357,6 +365,7 @@ bool Column::NodeInsertSplit(size_t ndx, size_t newRef) { assert(IsNode()); assert(newRef); + // MP: Should be refactored to Column class holding 'offset' and 'refs' arrays as members Array offsets = m_array.GetSubArray(0); Array refs = m_array.GetSubArray(1); assert(ndx < offsets.Size()); @@ -387,6 +396,7 @@ void Column::Delete(size_t ndx) { if (!IsNode()) m_array.Delete(ndx); else { // Get subnode table + // MP: Should be refactored to Column class holding 'offset' and 'refs' arrays as members Array offsets = m_array.GetSubArray(0); Array refs = m_array.GetSubArray(1); diff --git a/src/Column.h b/src/Column.h index ffebbbdbf8e..18926c68956 100644 --- a/src/Column.h +++ b/src/Column.h @@ -75,8 +75,11 @@ class Column : public ColumnBase { // At the core all integers are 64bit int64_t Get64(size_t ndx) const; bool Set64(size_t ndx, int64_t value); - bool Insert64(size_t ndx, int64_t value); - bool Add64(int64_t value); + bool Insert64(size_t ndx, int64_t value); + + inline bool Add64(int64_t value) { + return Insert64(Size(), value); + } intptr_t GetPtr(size_t ndx) const {return (intptr_t)Get64(ndx);} From cc6dc9cecdb88e94d3b2ba472a5bc2caae1dc328 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 23 Oct 2011 21:58:49 +0200 Subject: [PATCH 4/6] Commit --- TightDB.vcproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TightDB.vcproj b/TightDB.vcproj index 24ad6eec23a..05431f50845 100644 --- a/TightDB.vcproj +++ b/TightDB.vcproj @@ -43,7 +43,7 @@ /> Date: Mon, 24 Oct 2011 23:46:32 +0200 Subject: [PATCH 5/6] Review --- src/Group.cpp | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/Group.cpp diff --git a/src/Group.cpp b/src/Group.cpp new file mode 100644 index 00000000000..160e26b3c75 --- /dev/null +++ b/src/Group.cpp @@ -0,0 +1,126 @@ +#include "Group.h" +#include +#include +#include + +Group::Group() : m_top(COLUMN_HASREFS, NULL, 0, m_alloc), m_tables(COLUMN_HASREFS, NULL, 0, m_alloc), m_tableNames(NULL, 0, m_alloc) +{ + m_top.Add(m_tableNames.GetRef()); + m_top.Add(m_tables.GetRef()); + + m_tableNames.SetParent(&m_top, 0); + m_tables.SetParent(&m_top, 1); +} + +Group::Group(const char* filename) : m_top(m_alloc), m_tables(m_alloc), m_tableNames(m_alloc) +{ + // Memory map file + m_alloc.SetShared(filename); + + // Get ref for table top array + const size_t top_ref = m_alloc.GetTopRef(); + + // Instantiate top arrays + m_top.UpdateRef(top_ref); + assert(m_top.Size() == 2); + + m_tableNames.UpdateRef((size_t)m_top.Get(0)); + m_tables.UpdateRef((size_t)m_top.Get(1)); + m_tableNames.SetParent(&m_top, 0); + m_tables.SetParent(&m_top, 1); + + // Make room for pointers to cached tables + for (size_t i = 0; i < m_tables.Size(); ++i) { + m_cachedtables.Add(0); + } +} + +Group::~Group() { + for (size_t i = 0; i < m_tables.Size(); ++i) { + Table* const t = (Table*)m_cachedtables.Get(i); + t->Invalidate(); // don't destroy subtree yet + delete t; + } + m_cachedtables.Destroy(); + + // Recursively deletes entire tree + m_top.Destroy(); +} + +Table& Group::GetTable(const char* name) { + const size_t n = m_tableNames.Find(name); + if (n == -1) { + // Create new table + Table* const t = new Table(m_alloc); + t->SetParent(&m_tables, m_tables.Size()); + + m_tables.Add(t->GetRef()); + m_tableNames.Add(name); + m_cachedtables.Add((intptr_t)t); + + return *t; + } + else { + // Get table from cache if exists, else create + Table* t = (Table*)m_cachedtables.Get(n); + if (!t) { + const size_t ref = (size_t)m_tables.Get(n); + t = new Table(m_alloc, ref, &m_tables, n); + m_cachedtables.Set(n, (intptr_t)t); + } + return *t; + } +} + +void Group::Write(const char* filepath) { + std::ofstream out(filepath, std::ios_base::out|std::ios_base::binary); + Write(out); + out.close(); +} + +void Group::Write(std::ostream &out) { + // Space for ref to top array + out.write("\0\0\0\0\0\0\0\0", 8); + size_t pos = 8; + + // Write tables + Array tables(COLUMN_HASREFS); + for (size_t i = 0; i < m_tables.Size(); ++i) { + // Instantiate table if not in cache + Table* t = (Table*)m_cachedtables.Get(i); + if (!t) { + const size_t ref = (size_t)m_tables.Get(i); + t = new Table(m_alloc, ref, &m_tables, i); + m_cachedtables.Set(i, (intptr_t)t); + } + + // Write the table + const size_t tablePos = t->Write(out, pos); + tables.Add(tablePos); + } + + // Write table names + const size_t tableNamesPos = pos; + pos += m_tableNames.Write(out); + + // Write list of tables + const size_t tablesPos = pos; + pos += tables.Write(out); + + // Write top + Array top(COLUMN_HASREFS); + top.Add(tableNamesPos); + top.Add(tablesPos); + const size_t topPos = pos; + pos += top.Write(out); + + // top ref + out.seekp(0); + out.write((const char*)&topPos, 8); + + // Clean-up + tables.SetType(COLUMN_NORMAL); // avoid recursive del + top.SetType(COLUMN_NORMAL); + tables.Destroy(); + top.Destroy(); +} From 1bbccb903271e038db813aa37a188d9947ed6122 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Oct 2011 00:30:27 +0200 Subject: [PATCH 6/6] Changed inline to __inline --- src/Column.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Column.h b/src/Column.h index c7d9eaf783e..bc5593ba19e 100644 --- a/src/Column.h +++ b/src/Column.h @@ -77,7 +77,7 @@ class Column : public ColumnBase { bool Set64(size_t ndx, int64_t value); bool Insert64(size_t ndx, int64_t value); - inline bool Add64(int64_t value) { + __inline bool Add64(int64_t value) { return Insert64(Size(), value); }