diff --git a/TightDB.vcxproj b/TightDB.vcxproj
index 48ef777c353..ca315a9dead 100644
--- a/TightDB.vcxproj
+++ b/TightDB.vcxproj
@@ -1,4 +1,4 @@
-
+
@@ -222,7 +222,7 @@
Level3
ProgramDatabase
CompileAsCpp
- /DPTW32_STATIC_LIB /DTIGHTDB_DEBUG %(AdditionalOptions)
+ /DPTW32_STATIC_LIB /DTIGHTDB_DEBUG /DMAX_LIST_SIZE=1000 %(AdditionalOptions)
false
false
4355;4996
@@ -277,6 +277,7 @@
ProgramDatabase
/DPTW32_STATIC_LIB %(AdditionalOptions)
4355;4996
+ true
Release\UnitTest++.lib;%(AdditionalDependencies)
@@ -287,6 +288,9 @@
MachineX86
WS2_32.lib %(AdditionalOptions)
+
+ true
+
@@ -439,6 +443,7 @@
true
/DUSE_SSE42 %(AdditionalOptions)
+
true
true
@@ -457,6 +462,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
true
@@ -481,6 +492,9 @@
true
true
+
+ true
+
true
true
@@ -541,8 +555,18 @@
true
true
-
-
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
@@ -551,6 +575,10 @@
+
+
+ CppHeader
+
@@ -558,7 +586,10 @@
+
+
+
@@ -620,4 +651,4 @@
-
+
\ No newline at end of file
diff --git a/TightDB.vcxproj.filters b/TightDB.vcxproj.filters
index 8ca0f85538c..067a6a11565 100644
--- a/TightDB.vcxproj.filters
+++ b/TightDB.vcxproj.filters
@@ -109,18 +109,12 @@
src
-
- src
-
src
src
-
- src
-
src
@@ -148,9 +142,6 @@
src
-
- src
-
test
@@ -160,9 +151,22 @@
test
+
+ test
+
+
+ test
+
test
+
+ src
+
+
+
+ test
+
@@ -210,9 +214,6 @@
src\include
-
- src\include
-
src\include
@@ -282,12 +283,6 @@
src\include
-
- src\include
-
-
- src\include
-
src\include
@@ -342,6 +337,21 @@
test
+
+ src\include
+
+
+ src\include
+
+
+ src\include
+
+
+ src\include
+
+
+ src\include
+
@@ -360,4 +370,4 @@
{4436af4e-59db-4e36-9b8c-acb6e5d85aea}
-
+
\ No newline at end of file
diff --git a/changelog.txt b/changelog.txt
index 8dfe84db8f9..903b8b523e3 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -25,7 +25,6 @@ Format:
- Group::set_shared() removed.
- SharedGroup::is_valid() removed. Errors are now reported as exceptions from the constructor.
-
2013-01-11 (Kristian Spangsege)
+ Simplified open-mode for Group constructor.
- Group::is_valid() removed. Errors are now reported as exceptions from the constructor.
@@ -38,6 +37,9 @@ Format:
+ Mixed::set_int() added (same for other value types except subtables).
+ Removed two-argument Mixed constructor for binary data since its signature is expected to be used for strings that are not zero-terminated.
+2013-01-08 (Brian Munkholm)
+----------
++ New: Added a bunch of methods to support two new column types: float and double.
2012-12-16 (Kristian Spangsege)
----------
diff --git a/doc/development/query_engine.docx b/doc/development/query_engine.docx
new file mode 100644
index 00000000000..f98b1bba0a3
Binary files /dev/null and b/doc/development/query_engine.docx differ
diff --git a/doc/development/query_engine.pdf b/doc/development/query_engine.pdf
new file mode 100644
index 00000000000..b3f3227d930
Binary files /dev/null and b/doc/development/query_engine.pdf differ
diff --git a/src/tightdb/alloc_slab.cpp b/src/tightdb/alloc_slab.cpp
index 1aeddcf37dc..0e7463962e8 100644
--- a/src/tightdb/alloc_slab.cpp
+++ b/src/tightdb/alloc_slab.cpp
@@ -27,7 +27,6 @@ size_t GetSizeFromHeader(void* p)
const size_t count = (header[1] << 16) + (header[2] << 8) + header[3];
const size_t wt = (header[0] & 0x18) >> 3; // Array::WidthType
- // Calculate bytes used by array
size_t bytes = 0;
if (wt == 0) { // TDB_BITS
const size_t bits = (count * width);
diff --git a/src/tightdb/alloc_slab.hpp b/src/tightdb/alloc_slab.hpp
index f8f2e32173d..36656e2907e 100644
--- a/src/tightdb/alloc_slab.hpp
+++ b/src/tightdb/alloc_slab.hpp
@@ -147,7 +147,7 @@ inline SlabAlloc::SlabAlloc()
inline bool SlabAlloc::is_attached() const TIGHTDB_NOEXCEPT
{
- return m_data;
+ return (m_data != NULL);
}
} // namespace tightdb
diff --git a/src/tightdb/array.cpp b/src/tightdb/array.cpp
index 55c2ccf4ca7..05b9ed8eecc 100644
--- a/src/tightdb/array.cpp
+++ b/src/tightdb/array.cpp
@@ -18,103 +18,9 @@
using namespace std;
-namespace {
-
-const size_t initial_capacity = 128;
-
-inline void set_header_isnode(bool value, void* header)
-{
- uint8_t* const header2 = reinterpret_cast(header);
- header2[0] = (header2[0] & ~0x80) | uint8_t(value << 7);
-}
-
-inline void set_header_hasrefs(bool value, void* header)
-{
- uint8_t* const header2 = reinterpret_cast(header);
- header2[0] = (header2[0] & ~0x40) | uint8_t(value << 6);
-}
-
-inline void set_header_indexflag(bool value, void* header)
-{
- uint8_t* const header2 = reinterpret_cast(header);
- header2[0] = (header2[0] & ~0x20) | uint8_t(value << 5);
-}
-
-inline void set_header_wtype(int value, void* header)
-{
- // Indicates how to calculate size in bytes based on width
- // 0: bits (width/8) * length
- // 1: multiply width * length
- // 2: ignore 1 * length
- uint8_t* const header2 = reinterpret_cast(header);
- header2[0] = (header2[0] & ~0x18) | uint8_t(value << 3);
-}
-
-inline void set_header_width(size_t value, void* header)
-{
- // Pack width in 3 bits (log2)
- size_t w = 0;
- size_t b = size_t(value);
- while (b) {++w; b >>= 1;}
- TIGHTDB_ASSERT(w < 8);
-
- uint8_t* const header2 = reinterpret_cast(header);
- header2[0] = (header2[0] & ~0x7) | uint8_t(w);
-}
-
-inline void set_header_len(size_t value, void* header)
-{
- TIGHTDB_ASSERT(value <= 0xFFFFFF);
- uint8_t* const header2 = reinterpret_cast(header);
- header2[1] = (value >> 16) & 0x000000FF;
- header2[2] = (value >> 8) & 0x000000FF;
- header2[3] = value & 0x000000FF;
-}
-
-inline void set_header_capacity(size_t value, void* header)
-{
- TIGHTDB_ASSERT(value <= 0xFFFFFF);
- uint8_t* const header2 = reinterpret_cast(header);
- header2[4] = (value >> 16) & 0x000000FF;
- header2[5] = (value >> 8) & 0x000000FF;
- header2[6] = value & 0x000000FF;
-}
-
-
-inline void init_header(void* header, bool is_node, bool has_refs, int width_type,
- size_t width, size_t length, size_t capacity)
-{
- // Note: Since the header layout contains unallocated
- // bit and/or bytes, it is important that we put the
- // entire 8 byte header into a well defined state
- // initially. Note also: The C++ standard does not
- // guarantee that int64_t is extactly 8 bytes wide. It
- // may be more, and it may be less. That is why we
- // need the static assert.
- TIGHTDB_STATIC_ASSERT(sizeof(int64_t) == 8,
- "Trouble if int64_t is not 8 bytes wide");
- *reinterpret_cast(header) = 0;
- set_header_isnode(is_node, header);
- set_header_hasrefs(has_refs, header);
- set_header_wtype(width_type, header);
- set_header_width(width, header);
- set_header_len(length, header);
- set_header_capacity(capacity, header);
-}
-
-
-} // anonymous namespace
-
-
namespace tightdb {
-bool tightdb_dummy (int64_t t)
-{
- (void)t;
- return true;
-}
-
// Header format (8 bytes):
// |--------|--------|--------|--------|--------|--------|--------|--------|
// |12344555| length | capacity |reserved|
@@ -130,37 +36,37 @@ bool IsArrayIndexNode(size_t ref, const Allocator& alloc)
void Array::set_header_isnode(bool value)
{
- ::set_header_isnode(value, m_data - 8);
+ set_header_isnode(value, m_data - 8);
}
void Array::set_header_hasrefs(bool value)
{
- ::set_header_hasrefs(value, m_data - 8);
+ set_header_hasrefs(value, m_data - 8);
}
void Array::set_header_indexflag(bool value)
{
- ::set_header_indexflag(value, m_data - 8);
+ set_header_indexflag(value, m_data - 8);
}
void Array::set_header_wtype(WidthType value)
{
- ::set_header_wtype(value, m_data - 8);
+ set_header_wtype(value, m_data - 8);
}
void Array::set_header_width(size_t value)
{
- ::set_header_width(value, m_data - 8);
+ set_header_width(value, m_data - 8);
}
void Array::set_header_len(size_t value)
{
- ::set_header_len(value, m_data - 8);
+ set_header_len(value, m_data - 8);
}
void Array::set_header_capacity(size_t value)
{
- ::set_header_capacity(value, m_data - 8);
+ set_header_capacity(value, m_data - 8);
}
bool Array::get_header_isnode(const void* header) const TIGHTDB_NOEXCEPT
@@ -351,7 +257,7 @@ void Array::Preset(int64_t min, int64_t max, size_t count)
Preset(w, count);
}
-void Array::SetParent(ArrayParent *parent, size_t pndx)
+void Array::SetParent(ArrayParent *parent, size_t pndx) TIGHTDB_NOEXCEPT
{
m_parent = parent;
m_parentNdx = pndx;
@@ -713,6 +619,81 @@ size_t Array::FindPos2(int64_t target) const
return high;
}
+// return first element E for which E >= target or return -1 if none. Array must be sorted
+size_t Array::FindGTE(int64_t target, size_t start) const
+{
+#if TIGHTDB_DEBUG
+ // Reference implementation to illustrate and test behaviour
+ size_t ref = 0;
+ size_t idx;
+ for (idx = start; idx < m_len; ++idx) {
+ if (Get(idx) >= target) {
+ ref = idx;
+ break;
+ }
+ }
+ if (idx == m_len)
+ ref = not_found;
+#endif
+
+ size_t ret;
+
+ if (start >= m_len) {ret = not_found; goto exit;}
+
+ if (start + 2 < m_len) {
+ if (Get(start) >= target) {ret = start; goto exit;} else ++start;
+ if (Get(start) >= target) {ret = start; goto exit;} else ++start;
+ }
+
+ // Todo, use templated Get from this point for performance
+ if (target > Get(m_len - 1)) {ret = not_found; goto exit;}
+
+ size_t add;
+ add = 1;
+
+ for(;;) {
+ if (start + add < m_len && Get(start + add) < target)
+ start += add;
+ else
+ break;
+ add *= 2;
+ }
+
+ size_t high;
+ high = start + add + 1;
+
+ if (high > m_len)
+ high = m_len;
+
+ // if (start > 0)
+ start--;
+
+ //start og high
+
+ size_t orig_high;
+ orig_high = high;
+
+ while (high - start > 1) {
+ const size_t probe = (start + high) / 2;
+ const int64_t v = Get(probe);
+ if (v < target)
+ start = probe;
+ else
+ high = probe;
+ }
+ if (high == orig_high)
+ ret = not_found;
+ else
+ ret = high;
+
+exit:
+
+#if TIGHTDB_DEBUG
+ TIGHTDB_ASSERT(ref == ret);
+#endif
+
+ return ret;
+}
size_t Array::FirstSetBit(unsigned int v) const
{
@@ -852,7 +833,7 @@ template bool Array::minmax(int64_t& result, size_t st
++start;
#ifdef TIGHTDB_COMPILER_SSE
- if(cpuid_sse<42>()) {
+ if (cpuid_sse<42>()) {
// Test manually until 128 bit aligned
for (; (start < end) && ((((size_t)m_data & 0xf) * 8 + start * w) % (128) != 0); start++) {
if (find_max ? Get(start) > m : Get(start) < m)
@@ -862,7 +843,7 @@ template bool Array::minmax(int64_t& result, size_t st
if ((w == 8 || w == 16 || w == 32) && end - start > 2 * sizeof(__m128i) * 8 / NO0(w)) {
__m128i *data = (__m128i *)(m_data + start * w / 8);
__m128i state = data[0];
- __m128i state2; // FIXME: gcc-4.7 says that this one is undedfined if chunks is zero - can chunks ever be zero?
+ __m128i state2;
size_t chunks = (end - start) * w / 8 / sizeof(__m128i);
for (size_t t = 0; t < chunks; t++) {
@@ -877,7 +858,7 @@ template bool Array::minmax(int64_t& result, size_t st
}
// prevent taking address of 'state' to make the compiler keep it in SSE register in above loop (vc2010/gcc4.6)
- state2 = state;
+ state2 = state;
for (size_t t = 0; t < sizeof(__m128i) * 8 / NO0(w); ++t) {
const int64_t v = GetUniversal(((const char *)&state2), t);
if (find_max ? v > m : v < m) {
@@ -985,7 +966,7 @@ template int64_t Array::sum(size_t start, size_t end) const
}
#ifdef TIGHTDB_COMPILER_SSE
- if(cpuid_sse<42>()) {
+ if (cpuid_sse<42>()) {
// 2000 items summed 500000 times, 8/16/32 bits, miliseconds:
// Naive, templated Get<>: 391 371 374
@@ -1086,7 +1067,7 @@ size_t Array::count(int64_t value) const
const size_t end = m_len;
size_t i = 0;
- // staiic values needed for fast population count
+ // static values needed for fast population count
const uint64_t m1 = 0x5555555555555555ULL;
const uint64_t m2 = 0x3333333333333333ULL;
const uint64_t m4 = 0x0f0f0f0f0f0f0f0fULL;
@@ -1269,7 +1250,7 @@ size_t Array::GetByteSize(bool align) const
size_t Array::CalcByteLen(size_t count, size_t width) const
{
- // FIXME: This arithemtic could overflow. Consider using
+ // FIXME: This arithemtic could overflow. Consider using
const size_t bits = count * width;
const size_t bytes = (bits+7) / 8; // round up
return bytes + 8; // add room for 8 byte header
@@ -1367,12 +1348,15 @@ bool Array::CopyOnWrite()
size_t Array::create_empty_array(ColumnDef type, WidthType width_type, Allocator& alloc)
{
bool is_node = false, has_refs = false;
- if (type == COLUMN_NODE) is_node = has_refs = true;
- else if (type == COLUMN_HASREFS) has_refs = true;
+ if (type == COLUMN_NODE)
+ is_node = has_refs = true;
+ else if (type == COLUMN_HASREFS)
+ has_refs = true;
const size_t capacity = initial_capacity;
- MemRef mem_ref = alloc.Alloc(capacity);
- if (!mem_ref.pointer) return 0;
+ const MemRef mem_ref = alloc.Alloc(capacity);
+ if (!mem_ref.pointer)
+ return 0;
init_header(mem_ref.pointer, is_node, has_refs, width_type, 0, 0, capacity);
@@ -1408,9 +1392,9 @@ bool Array::Alloc(size_t count, size_t width)
else {
mem_ref = m_alloc.ReAlloc(m_ref, m_data-8, capacity_bytes);
if (!mem_ref.pointer) return false;
- ::set_header_width(width, mem_ref.pointer);
- ::set_header_len(count, mem_ref.pointer);
- ::set_header_capacity(capacity_bytes, mem_ref.pointer);
+ set_header_width(width, mem_ref.pointer);
+ set_header_len(count, mem_ref.pointer);
+ set_header_capacity(capacity_bytes, mem_ref.pointer);
}
// Update wrapper objects
@@ -2060,141 +2044,119 @@ size_t FindPos2Direct_32(const uint8_t* const header, const char* const data, in
namespace tightdb {
-void Array::state_init(ACTION action, state_state *state, Array* akku)
-{
- if (action == TDB_MAX) {
- state->state = -0x7fffffffffffffffLL - 1LL;
- state->match_count = 0;
- }
- if (action == TDB_MIN) {
- state->state = 0x7fffffffffffffffLL;
- state->match_count = 0;
- }
- if (action == TDB_RETURN_FIRST)
- state->state = not_found;
- if (action == TDB_SUM) {
- state->state = 0;
- state->match_count = 0;
- }
- if (action == TDB_COUNT)
- state->state = 0;
- if (action == TDB_FINDALL)
- state->state = (int64_t)akku;
-}
-
void Array::find_all(Array& result, int64_t value, size_t colOffset, size_t start, size_t end) const
{
if (end == (size_t)-1) end = m_len;
TIGHTDB_ASSERT(start < m_len && end <= m_len && start < end);
- state_state state;
+ QueryState state;
state.state = (int64_t)&result;
- TEMPEX3(find, EQUAL, TDB_FINDALL, m_width, (value, start, end, colOffset, &state, &tightdb_dummy));
+ TEMPEX3(find, EQUAL, TDB_FINDALL, m_width, (value, start, end, colOffset, &state, CallbackDummy()));
return;
}
-void Array::find(int cond, ACTION action, int64_t value, size_t start, size_t end, size_t baseindex, state_state *state) const
+void Array::find(int cond, ACTION action, int64_t value, size_t start, size_t end, size_t baseindex, QueryState *state) const
{
if (cond == COND_EQUAL) {
if (action == TDB_SUM) {
- TEMPEX3(find, EQUAL, TDB_SUM, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, EQUAL, TDB_SUM, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MIN) {
- TEMPEX3(find, EQUAL, TDB_MIN, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, EQUAL, TDB_MIN, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MAX) {
- TEMPEX3(find, EQUAL, TDB_MAX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, EQUAL, TDB_MAX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_COUNT) {
- TEMPEX3(find, EQUAL, TDB_COUNT, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, EQUAL, TDB_COUNT, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_FINDALL) {
- TEMPEX3(find, EQUAL, TDB_FINDALL, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, EQUAL, TDB_FINDALL, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_CALLBACK_IDX) {
- TEMPEX3(find, EQUAL, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, EQUAL, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
}
if (cond == COND_NOTEQUAL) {
if (action == TDB_SUM) {
- TEMPEX3(find, NOTEQUAL, TDB_SUM, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NOTEQUAL, TDB_SUM, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MIN) {
- TEMPEX3(find, NOTEQUAL, TDB_MIN, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NOTEQUAL, TDB_MIN, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MAX) {
- TEMPEX3(find, NOTEQUAL, TDB_MAX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NOTEQUAL, TDB_MAX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_COUNT) {
- TEMPEX3(find, NOTEQUAL, TDB_COUNT, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NOTEQUAL, TDB_COUNT, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_FINDALL) {
- TEMPEX3(find, NOTEQUAL, TDB_FINDALL, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NOTEQUAL, TDB_FINDALL, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_CALLBACK_IDX) {
- TEMPEX3(find, NOTEQUAL, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NOTEQUAL, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
}
if (cond == COND_GREATER) {
if (action == TDB_SUM) {
- TEMPEX3(find, GREATER, TDB_SUM, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, GREATER, TDB_SUM, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MIN) {
- TEMPEX3(find, GREATER, TDB_MIN, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, GREATER, TDB_MIN, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MAX) {
- TEMPEX3(find, GREATER, TDB_MAX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, GREATER, TDB_MAX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_COUNT) {
- TEMPEX3(find, GREATER, TDB_COUNT, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, GREATER, TDB_COUNT, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_FINDALL) {
- TEMPEX3(find, GREATER, TDB_FINDALL, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, GREATER, TDB_FINDALL, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_CALLBACK_IDX) {
- TEMPEX3(find, GREATER, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, GREATER, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
}
if (cond == COND_LESS) {
if (action == TDB_SUM) {
- TEMPEX3(find, LESS, TDB_SUM, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, LESS, TDB_SUM, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MIN) {
- TEMPEX3(find, LESS, TDB_MIN, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, LESS, TDB_MIN, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MAX) {
- TEMPEX3(find, LESS, TDB_MAX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, LESS, TDB_MAX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_COUNT) {
- TEMPEX3(find, LESS, TDB_COUNT, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, LESS, TDB_COUNT, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_FINDALL) {
- TEMPEX3(find, LESS, TDB_FINDALL, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, LESS, TDB_FINDALL, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_CALLBACK_IDX) {
- TEMPEX3(find, LESS, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, LESS, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
}
if (cond == COND_NONE) {
if (action == TDB_SUM) {
- TEMPEX3(find, NONE, TDB_SUM, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NONE, TDB_SUM, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MIN) {
- TEMPEX3(find, NONE, TDB_MIN, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NONE, TDB_MIN, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_MAX) {
- TEMPEX3(find, NONE, TDB_MAX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NONE, TDB_MAX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_COUNT) {
- TEMPEX3(find, NONE, TDB_COUNT, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NONE, TDB_COUNT, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_FINDALL) {
- TEMPEX3(find, NONE, TDB_FINDALL, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NONE, TDB_FINDALL, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
else if (action == TDB_CALLBACK_IDX) {
- TEMPEX3(find, NONE, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, &tightdb_dummy))
+ TEMPEX3(find, NONE, TDB_CALLBACK_IDX, m_width, (value, start, end, baseindex, state, CallbackDummy()))
}
}
}
@@ -2296,6 +2258,7 @@ int64_t Array::ColumnGet(size_t ndx) const TIGHTDB_NOEXCEPT
return GetDirect(data, width, ndx);
}
+// FIXME: Shouldn't ColumnStringGet() be locaterd in ColumnString?
const char* Array::ColumnStringGet(size_t ndx) const TIGHTDB_NOEXCEPT
{
const char* data = reinterpret_cast(m_data);
diff --git a/src/tightdb/array.hpp b/src/tightdb/array.hpp
index 76f7f8c27ff..c49a7afdcf3 100644
--- a/src/tightdb/array.hpp
+++ b/src/tightdb/array.hpp
@@ -20,15 +20,15 @@
/*
Searching: The main finding function is:
- template void find(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const
+ template void find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState *state, Callback callback) const
cond: One of EQUAL, NOTEQUAL, GREATER, etc. classes
ACTION: One of TDB_RETURN_FIRST, TDB_FINDALL, TDB_MAX, TDB_CALLBACK_IDX, etc, constants
Callback: Optional function to call for each search result. Will be called if action == TDB_CALLBACK_IDX
-
- find() will call FIND_ACTION_PATTERN() or FIND_ACTION() that again calls state_match() for each search result which optionally calls callback():
-
- find() -> FIND_ACTION() -------> bool state_match() -> bool callback()
+
+ find() will call FIND_ACTION_PATTERN() or FIND_ACTION() that again calls match() for each search result which optionally calls callback():
+
+ find() -> FIND_ACTION() -------> bool match() -> bool callback()
| ^
+-> FIND_ACTION_PATTERN()----+
@@ -50,6 +50,7 @@ Searching: The main finding function is:
#include
#include
#include
+#include
/*
MMX: mmintrin.h
@@ -61,7 +62,6 @@ Searching: The main finding function is:
SSE4.1: smmintrin.h
SSE4.2: nmmintrin.h
*/
-
#ifdef TIGHTDB_COMPILER_SSE
#include // SSE2
#include // SSE42
@@ -81,8 +81,6 @@ enum ACTION {TDB_RETURN_FIRST, TDB_SUM, TDB_MAX, TDB_MIN, TDB_COUNT, TDB_FINDALL
namespace tightdb {
-bool tightdb_dummy (int64_t t);
-
#define NO0(v) ((v) == 0 ? 1 : (v))
const size_t not_found = size_t(-1);
@@ -137,11 +135,9 @@ const size_t not_found = size_t(-1);
class Array;
class AdaptiveStringColumn;
class GroupWriter;
+class Column;
+template class QueryState;
-struct state_state {
- int64_t state;
- size_t match_count;
-};
#ifdef TIGHTDB_DEBUG
class MemStats {
@@ -175,6 +171,7 @@ enum ColumnDef {
bool IsArrayIndexNode(size_t ref, const Allocator& alloc);
+
class ArrayParent
{
public:
@@ -204,8 +201,8 @@ class ArrayParent
class Array: public ArrayParent {
public:
-// void state_init(int action, state_state *state);
-// bool state_match(int action, size_t index, int64_t value, state_state *state);
+// void state_init(int action, QueryState *state);
+// bool match(int action, size_t index, int64_t value, QueryState *state);
/// Create a new array, and if \a parent and \a ndx_in_parent are
/// specified, update the parent to point to this new array.
@@ -223,8 +220,8 @@ class Array: public ArrayParent {
Array(const Array&) TIGHTDB_NOEXCEPT;
// Fastest way to instantiate an array, if you just want to utilize its methods
- // FIXME: Using a type tag here instead of a boolean argument would be a lot safer.
- explicit Array(bool);
+ struct no_prealloc_tag {};
+ explicit Array(no_prealloc_tag) TIGHTDB_NOEXCEPT;
virtual ~Array() TIGHTDB_NOEXCEPT {}
@@ -252,7 +249,7 @@ class Array: public ArrayParent {
// Parent tracking
bool HasParent() const TIGHTDB_NOEXCEPT {return m_parent != NULL;}
- void SetParent(ArrayParent *parent, size_t ndx_in_parent);
+ void SetParent(ArrayParent *parent, size_t ndx_in_parent) TIGHTDB_NOEXCEPT;
void UpdateParentNdx(int diff) {m_parentNdx += diff;}
ArrayParent *GetParent() const TIGHTDB_NOEXCEPT {return m_parent;}
size_t GetParentNdx() const {return m_parentNdx;}
@@ -299,6 +296,7 @@ class Array: public ArrayParent {
size_t FindPos(int64_t value) const TIGHTDB_NOEXCEPT;
size_t FindPos2(int64_t value) const;
+ size_t FindGTE(int64_t target, size_t start) const;
void Preset(int64_t min, int64_t max, size_t count);
void Preset(size_t bitwidth, size_t count);
@@ -330,33 +328,29 @@ class Array: public ArrayParent {
/// Compare two arrays for equality.
bool Compare(const Array&) const;
- // Main finding function - used for find_first, find_all, sum, max, min, etc.
- void find(int cond, ACTION action, int64_t value, size_t start, size_t end, size_t baseindex, state_state *state) const;
-
- template
- void find(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const;
-
- template
- void find(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state) const;
-
- template
- void find(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const;
-
+ // Main finding function - used for find_first, find_all, sum, max, min, etc.
+ void find(int cond, ACTION action, int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state) const;
+
+ template
+ void find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, Callback callback) const;
+
+ template
+ void find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state) const;
+
+ template
+ void find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, Callback callback) const;
+
// Optimized implementation for release mode
template
- void find_optimized(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const;
+ void find_optimized(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, Callback callback) const;
// Reference implementation of find() - verifies result from optimized version if debug mode
template
- int64_t find_reference(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const;
-
- // Initialize state before calling find()
- void state_init(ACTION action, state_state *state, Array* akku);
+ int64_t find_reference(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, Callback callback) const;
// Called for each search result
- template bool state_match(size_t index, uint64_t indexpattern, int64_t value, state_state *state, Callback callback) const;
- template bool FIND_ACTION(size_t index, int64_t value, state_state *state, Callback callback) const;
- template bool FIND_ACTION_PATTERN(size_t index, uint64_t pattern, state_state *state, Callback callback) const;
+ template bool FIND_ACTION(size_t index, int64_t value, QueryState* state, Callback callback) const;
+ template bool FIND_ACTION_PATTERN(size_t index, uint64_t pattern, QueryState* state, Callback callback) const;
// Wrappers for backwards compatibility and for simple use without setting up state initialization etc
template size_t find_first(int64_t value, size_t start = 0, size_t end = size_t(-1)) const;
@@ -365,25 +359,24 @@ class Array: public ArrayParent {
// Non-SSE find for the four functions EQUAL/NOTEQUAL/LESS/GREATER
template
- bool Compare(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const;
+ bool Compare(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, Callback callback) const;
// Non-SSE find for EQUAL/NOTEQUAL
template
- inline bool CompareEquality(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const;
+ inline bool CompareEquality(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, Callback callback) const;
// Non-SSE find for LESS/GREATER
template
- bool CompareRelation(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const;
+ bool CompareRelation(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, Callback callback) const;
// SSE find for the four functions EQUAL/NOTEQUAL/LESS/GREATER
#ifdef TIGHTDB_COMPILER_SSE
template
- size_t FindSSE(int64_t value, __m128i *data, size_t items, state_state *state, size_t baseindex, Callback callback) const;
+ size_t FindSSE(int64_t value, __m128i *data, size_t items, QueryState* state, size_t baseindex, Callback callback) const;
#endif
template inline bool TestZero(uint64_t value) const; // Tests value for 0-elements
template size_t FindZero(uint64_t v) const; // Finds position of 0/non-zero element
- template bool USES_VAL(void); // Helps compiler knowing that a Get()'ed value is unused
template uint64_t cascade(uint64_t a) const; // Sets uppermost bits of non-zero elements
template int64_t FindGTLT_Magic(int64_t v) const; // Compute magic constant needed for searching for value 'v' using bit hacks
template inline int64_t LowerBits(void) const; // Return chunk with lower bit set in each element
@@ -393,35 +386,12 @@ class Array: public ArrayParent {
// Find value greater/less in 64-bit chunk - only works for positive values
template
- bool FindGTLT_Fast(uint64_t chunk, uint64_t magic, state_state *state, size_t baseindex, Callback callback) const;
+ bool FindGTLT_Fast(uint64_t chunk, uint64_t magic, QueryState* state, size_t baseindex, Callback callback) const;
// Find value greater/less in 64-bit chunk - no constraints
template
- bool FindGTLT(int64_t v, uint64_t chunk, state_state *state, size_t baseindex, Callback callback) const;
+ bool FindGTLT(int64_t v, uint64_t chunk, QueryState* state, size_t baseindex, Callback callback) const;
-
- // popcount
- #if defined(_MSC_VER) && _MSC_VER >= 1500
- inline int fast_popcount32(uint32_t x);
- #if defined(_M_X64)
- inline int fast_popcount64(unsigned __int64 x) const;
- #else
- inline int fast_popcount64(unsigned __int64 x) const;
- #endif
- #elif defined(__GNUC__) && __GNUC__ >= 4 || defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 900
- #if ULONG_MAX == 0xffffffff
- inline int fast_popcount64(unsigned long long x) const;
- #else
- inline int fast_popcount64(unsigned long long x) const;
- #endif
- #else
- // Masking away bits might be faster than bit shifting (which can be slow). Note that the compiler may optimize this automatically. Todo, investigate.
- inline int fast_popcount32(uint32_t x) const;
-
- inline int fast_popcount64(uint64_t x) const;
- #endif // select best popcount implementations
-
-
// Debug
size_t GetBitWidth() const {return m_width;}
@@ -460,11 +430,6 @@ class Array: public ArrayParent {
void CreateFromHeaderDirect(uint8_t* header, size_t ref=0) TIGHTDB_NOEXCEPT;
void update_ref_in_parent();
- // Getters and Setters for adaptive-packed arrays
- typedef int64_t(Array::*Getter)(size_t) const; // Note: getters must not throw
- typedef void(Array::*Setter)(size_t, int64_t);
- typedef void (Array::*Finder)(int64_t, size_t, size_t, size_t, state_state*) const;
-
enum WidthType {
TDB_BITS = 0,
TDB_MULTIPLY = 1,
@@ -482,34 +447,41 @@ class Array: public ArrayParent {
void set_header_width(size_t value);
void set_header_len(size_t value);
void set_header_capacity(size_t value);
- bool get_header_isnode(const void* header=0) const TIGHTDB_NOEXCEPT;
- bool get_header_hasrefs(const void* header=0) const TIGHTDB_NOEXCEPT;
- bool get_header_indexflag(const void* header=0) const TIGHTDB_NOEXCEPT;
- WidthType get_header_wtype(const void* header=0) const TIGHTDB_NOEXCEPT;
- size_t get_header_width(const void* header=0) const TIGHTDB_NOEXCEPT;
- size_t get_header_len(const void* header=0) const TIGHTDB_NOEXCEPT;
- size_t get_header_capacity(const void* header=0) const TIGHTDB_NOEXCEPT;
-
- template void SetWidth() TIGHTDB_NOEXCEPT;
- void SetWidth(size_t) TIGHTDB_NOEXCEPT;
+
+ bool get_header_isnode(const void* header=NULL) const TIGHTDB_NOEXCEPT;
+ bool get_header_hasrefs(const void* header=NULL) const TIGHTDB_NOEXCEPT;
+ bool get_header_indexflag(const void* header=NULL) const TIGHTDB_NOEXCEPT;
+ WidthType get_header_wtype(const void* header=NULL) const TIGHTDB_NOEXCEPT;
+ size_t get_header_width(const void* header=NULL) const TIGHTDB_NOEXCEPT;
+ size_t get_header_len(const void* header=NULL) const TIGHTDB_NOEXCEPT;
+ size_t get_header_capacity(const void* header=NULL) const TIGHTDB_NOEXCEPT;
+
+ static void set_header_isnode(bool value, void* header);
+ static void set_header_hasrefs(bool value, void* header);
+ static void set_header_indexflag(bool value, void* header);
+ static void set_header_wtype(int value, void* header);
+ static void set_header_width(size_t value, void* header);
+ static void set_header_len(size_t value, void* header);
+ static void set_header_capacity(size_t value, void* header);
+ static void init_header(void* header, bool is_node, bool has_refs, int width_type,
+ size_t width, size_t length, size_t capacity);
+
+ template void SetWidth(void) TIGHTDB_NOEXCEPT;
+ void SetWidth(size_t width) TIGHTDB_NOEXCEPT;
bool Alloc(size_t count, size_t width);
bool CopyOnWrite();
- // Member variables
- Getter m_getter;
- Setter m_setter;
- Finder m_finder[COND_COUNT]; // one for each COND_XXX enum
-
private:
size_t m_ref;
template bool minmax(int64_t& result, size_t start, size_t end) const;
protected:
- size_t m_len;
- size_t m_capacity;
- size_t m_width; // FIXME: Should be an 'int'
- bool m_isNode;
- bool m_hasRefs;
+ size_t m_len; // items currently stored
+ size_t m_capacity; // max item capacity
+// FIXME: m_width Should be an 'int'
+ size_t m_width; // size of an item in bits or bytes depending on
+ bool m_isNode; // is it a Node or Leaf array
+ bool m_hasRefs; //
private:
ArrayParent *m_parent;
@@ -518,21 +490,169 @@ class Array: public ArrayParent {
Allocator& m_alloc;
protected:
- int64_t m_lbound;
- int64_t m_ubound;
-
+ static const size_t initial_capacity = 128;
static size_t create_empty_array(ColumnDef, WidthType, Allocator&);
// Overriding methods in ArrayParent
virtual void update_child_ref(size_t child_ndx, size_t new_ref);
virtual size_t get_child_ref(size_t child_ndx) const;
+// FIXME: below should be moved to a specific ArrayNumber class
+protected:
+ // Getters and Setters for adaptive-packed arrays
+ typedef int64_t(Array::*Getter)(size_t) const; // Note: getters must not throw
+ typedef void(Array::*Setter)(size_t, int64_t);
+ typedef void (Array::*Finder)(int64_t, size_t, size_t, size_t, QueryState*) const;
+
+ Getter m_getter;
+ Setter m_setter;
+ Finder m_finder[COND_COUNT]; // one for each COND_XXX enum
+
+ int64_t m_lbound; // min number that can be stored with current m_width
+ int64_t m_ubound; // max number that can be stored with current m_width
};
+
+
// Implementation:
-inline Array::Array(size_t ref, ArrayParent* parent, size_t pndx,
- Allocator& alloc) TIGHTDB_NOEXCEPT:
+class QueryStateParent {};
+
+template <> class QueryState : public QueryStateParent {
+public:
+
+ int64_t state;
+ size_t match_count;
+ size_t m_limit;
+
+ template bool uses_val(void)
+ {
+ if (action == TDB_MAX || action == TDB_MIN || action == TDB_SUM)
+ return true;
+ else
+ return false;
+ }
+
+ void init(ACTION action, Array* akku, size_t limit)
+ {
+ match_count = 0;
+ m_limit = limit;
+
+ if (action == TDB_MAX)
+ state = -0x7fffffffffffffffLL - 1LL;
+ else if (action == TDB_MIN)
+ state = 0x7fffffffffffffffLL;
+ else if (action == TDB_RETURN_FIRST)
+ state = not_found;
+ else if (action == TDB_SUM)
+ state = 0;
+ else if (action == TDB_COUNT)
+ state = 0;
+ else if (action == TDB_FINDALL)
+ state = (int64_t)akku;
+ else
+ TIGHTDB_ASSERT(false);
+ }
+
+ template
+ inline bool match(size_t index, uint64_t indexpattern, int64_t value, Callback callback)
+ {
+ if (pattern) {
+ if (action == TDB_COUNT) {
+ state += fast_popcount64(indexpattern);
+ match_count = size_t(state);
+ return true;
+ }
+ // Other aggregates cannot (yet) use bit pattern for anything. Make Array-finder call with pattern = false instead
+ return false;
+ }
+
+ ++match_count;
+
+ if (action == TDB_CALLBACK_IDX)
+ return callback(index);
+ else if (action == TDB_MAX) {
+ if(value > state)
+ state = value;
+ }
+ else if (action == TDB_MIN) {
+ if(value < state)
+ state = value;
+ }
+ else if (action == TDB_SUM)
+ state += value;
+ else if (action == TDB_COUNT) {
+ state++;
+ match_count = size_t(state);
+ }
+ else if (action == TDB_FINDALL)
+ ((Array*)state)->add(index);
+ else if (action == TDB_RETURN_FIRST) {
+ state = index;
+ return false;
+ }
+ else
+ TIGHTDB_ASSERT(false);
+ return true;
+ }
+
+};
+
+template class QueryState : public QueryStateParent {
+public:
+
+ T state;
+ size_t match_count;
+ size_t m_limit;
+
+ template bool uses_val(void)
+ {
+ return (action == TDB_MAX || action == TDB_MIN || action == TDB_SUM);
+ }
+
+ void init(ACTION action, Array*, size_t limit)
+ {
+ match_count = 0;
+ m_limit = limit;
+
+ if (action == TDB_MAX)
+ state = -std::numeric_limits::infinity();
+ else if (action == TDB_MIN)
+ state = std::numeric_limits::infinity();
+ else if (action == TDB_SUM)
+ state = 0.0;
+ else
+ TIGHTDB_ASSERT(false);
+ }
+
+ template
+ inline bool match(size_t /*index*/, uint64_t /*indexpattern*/, resulttype value, Callback /*callback*/)
+ {
+ if(pattern)
+ return false;
+
+ TIGHTDB_STATIC_ASSERT(action == TDB_SUM || action == TDB_MAX || action == TDB_MIN, "");
+ ++match_count;
+
+ if (action == TDB_MAX) {
+ if(value > state)
+ state = value;
+ }
+ else if (action == TDB_MIN) {
+ if(value < state)
+ state = value;
+ }
+ else if (action == TDB_SUM)
+ state += value;
+ else
+ TIGHTDB_ASSERT(false);
+ return true;
+ }
+};
+
+
+
+inline Array::Array(size_t ref, ArrayParent* parent, size_t pndx, Allocator& alloc) TIGHTDB_NOEXCEPT:
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), m_lbound(0), m_ubound(0)
{
@@ -568,7 +688,7 @@ inline Array::Array(const Array& src) TIGHTDB_NOEXCEPT:
// Fastest way to instantiate an Array. For use with GetDirect() that only fills out m_width, m_data
// and a few other basic things needed for read-only access. Or for use if you just want a way to call
// some methods written in Array.*
-inline Array::Array(bool) : m_alloc(Allocator::get_default()) {}
+inline Array::Array(no_prealloc_tag) TIGHTDB_NOEXCEPT: m_alloc(Allocator::get_default()) {}
inline int64_t Array::back() const TIGHTDB_NOEXCEPT
@@ -590,7 +710,94 @@ inline Array Array::GetSubArray(std::size_t ndx) const TIGHTDB_NOEXCEPT
}
-template inline size_t Array::Write(S& out, bool recurse, bool persist) const
+
+//-------------------------------------------------
+
+inline void Array::set_header_isnode(bool value, void* header)
+{
+ uint8_t* const header2 = reinterpret_cast(header);
+ header2[0] = (header2[0] & ~0x80) | uint8_t(value << 7);
+}
+
+inline void Array::set_header_hasrefs(bool value, void* header)
+{
+ uint8_t* const header2 = reinterpret_cast(header);
+ header2[0] = (header2[0] & ~0x40) | uint8_t(value << 6);
+}
+
+inline void Array::set_header_indexflag(bool value, void* header)
+{
+ uint8_t* const header2 = reinterpret_cast(header);
+ header2[0] = (header2[0] & ~0x20) | uint8_t(value << 5);
+}
+
+inline void Array::set_header_wtype(int value, void* header)
+{
+ // Indicates how to calculate size in bytes based on width
+ // 0: bits (width/8) * length
+ // 1: multiply width * length
+ // 2: ignore 1 * length
+ uint8_t* const header2 = reinterpret_cast(header);
+ header2[0] = (header2[0] & ~0x18) | uint8_t(value << 3);
+}
+
+inline void Array::set_header_width(size_t value, void* header)
+{
+ // Pack width in 3 bits (log2)
+ size_t w = 0;
+ size_t b = size_t(value);
+ while (b) {++w; b >>= 1;}
+ TIGHTDB_ASSERT(w < 8);
+
+ uint8_t* const header2 = reinterpret_cast(header);
+ header2[0] = (header2[0] & ~0x7) | uint8_t(w);
+}
+
+inline void Array::set_header_len(size_t value, void* header)
+{
+ TIGHTDB_ASSERT(value <= 0xFFFFFF);
+ uint8_t* const header2 = reinterpret_cast(header);
+ header2[1] = (value >> 16) & 0x000000FF;
+ header2[2] = (value >> 8) & 0x000000FF;
+ header2[3] = value & 0x000000FF;
+}
+
+inline void Array::set_header_capacity(size_t value, void* header)
+{
+ TIGHTDB_ASSERT(value <= 0xFFFFFF);
+ uint8_t* const header2 = reinterpret_cast(header);
+ header2[4] = (value >> 16) & 0x000000FF;
+ header2[5] = (value >> 8) & 0x000000FF;
+ header2[6] = value & 0x000000FF;
+}
+
+
+inline void Array::init_header(void* header, bool is_node, bool has_refs, int width_type,
+ size_t width, size_t length, size_t capacity)
+{
+ // Note: Since the header layout contains unallocated
+ // bit and/or bytes, it is important that we put the
+ // entire 8 byte header into a well defined state
+ // initially. Note also: The C++ standard does not
+ // guarantee that int64_t is extactly 8 bytes wide. It
+ // may be more, and it may be less. That is why we
+ // need the static assert.
+ TIGHTDB_STATIC_ASSERT(sizeof(int64_t) == 8,
+ "Trouble if int64_t is not 8 bytes wide");
+ *reinterpret_cast(header) = 0;
+ set_header_isnode(is_node, header);
+ set_header_hasrefs(has_refs, header);
+ set_header_wtype(width_type, header);
+ set_header_width(width, header);
+ set_header_len(length, header);
+ set_header_capacity(capacity, header);
+}
+
+
+//-------------------------------------------------
+
+
+template size_t Array::Write(S& out, bool recurse, bool persist) const
{
TIGHTDB_ASSERT(IsValid());
@@ -733,980 +940,892 @@ inline size_t Array::get_child_ref(size_t child_ndx) const
- //*************************************************************************************
- // Finding code *
- //*************************************************************************************
+//*************************************************************************************
+// Finding code *
+//*************************************************************************************
- template int64_t Array::GetUniversal(const char* const data, const size_t ndx) const
- {
- if (w == 0) {
- return 0;
- }
- else if (w == 1) {
- const size_t offset = ndx >> 3;
- return (data[offset] >> (ndx & 7)) & 0x01;
- }
- else if (w == 2) {
- const size_t offset = ndx >> 2;
- return (data[offset] >> ((ndx & 3) << 1)) & 0x03;
- }
- else if (w == 4) {
- const size_t offset = ndx >> 1;
- return (data[offset] >> ((ndx & 1) << 2)) & 0x0F;
- }
- else if (w == 8) {
- return *((const signed char*)(data + ndx));
- }
- else if (w == 16) {
- const size_t offset = ndx * 2;
- return *(const int16_t*)(data + offset);
- }
- else if (w == 32) {
- const size_t offset = ndx * 4;
- return *(const int32_t*)(data + offset);
- }
- else if (w == 64) {
- const size_t offset = ndx * 8;
- return *((const int64_t*)(data + offset));
- }
- else {
- TIGHTDB_ASSERT(false);
- return int64_t(-1);
- }
+template int64_t Array::GetUniversal(const char* const data, const size_t ndx) const
+{
+ if (w == 0) {
+ return 0;
+ }
+ else if (w == 1) {
+ const size_t offset = ndx >> 3;
+ return (data[offset] >> (ndx & 7)) & 0x01;
+ }
+ else if (w == 2) {
+ const size_t offset = ndx >> 2;
+ return (data[offset] >> ((ndx & 3) << 1)) & 0x03;
+ }
+ else if (w == 4) {
+ const size_t offset = ndx >> 1;
+ return (data[offset] >> ((ndx & 1) << 2)) & 0x0F;
+ }
+ else if (w == 8) {
+ return *((const signed char*)(data + ndx));
+ }
+ else if (w == 16) {
+ const size_t offset = ndx * 2;
+ return *(const int16_t*)(data + offset);
+ }
+ else if (w == 32) {
+ const size_t offset = ndx * 4;
+ return *(const int32_t*)(data + offset);
}
+ else if (w == 64) {
+ const size_t offset = ndx * 8;
+ return *((const int64_t*)(data + offset));
+ }
+ else {
+ TIGHTDB_ASSERT(false);
+ return int64_t(-1);
+ }
+}
- /*
- find() (calls find_optimized()) will call state_match() for each search result.
+/*
+find() (calls find_optimized()) will call match() for each search result.
- If pattern == true:
- 'indexpattern' contains a 64-bit chunk of elements, each of 'width' bits in size where each element indicates a match if its lower bit is set, otherwise
- it indicates a non-match. 'index' tells the database row index of the first element. You must return true if you chose to 'consume' the chunk or false
- if not. If not, then Array-finder will afterwards call state_match() successive times with pattern == false.
+If pattern == true:
+ 'indexpattern' contains a 64-bit chunk of elements, each of 'width' bits in size where each element indicates a match if its lower bit is set, otherwise
+ it indicates a non-match. 'index' tells the database row index of the first element. You must return true if you chose to 'consume' the chunk or false
+ if not. If not, then Array-finder will afterwards call match() successive times with pattern == false.
- If pattern == false:
- 'index' tells the row index of a single match and 'value' tells its value. Return false to make Array-finder break its search or return true to let it continue until
- 'end' or 'limit'.
+If pattern == false:
+ 'index' tells the row index of a single match and 'value' tells its value. Return false to make Array-finder break its search or return true to let it continue until
+ 'end' or 'limit'.
- Array-finder decides itself if - and when - it wants to pass you an indexpattern. It depends on array bit width, match frequency, and wether the arithemetic and
- computations for the given search criteria makes it feasible to construct such a pattern.
- */
+Array-finder decides itself if - and when - it wants to pass you an indexpattern. It depends on array bit width, match frequency, and wether the arithemetic and
+computations for the given search criteria makes it feasible to construct such a pattern.
+*/
- template bool Array::state_match(size_t index, uint64_t indexpattern, int64_t value, state_state *state, Callback callback) const
- {
- if (pattern) {
- if (action == TDB_COUNT) {
- size_t c = fast_popcount64(indexpattern);
- state->state += c;
- state->match_count += c;
- return true;
- }
- // Other aggregates cannot (yet) use bit pattern for anything. Make Array-finder call with pattern = false instead
- return false;
- }
+// These wrapper functions only exist to enable a possibility to make the compiler see that 'value' and/or 'index' are unused, such that caller's
+// computation of these values will not be made. Only works if FIND_ACTION and FIND_ACTION_PATTERN rewritten as macros. Note: This problem has been fixed in
+// next upcoming array.hpp version
+template bool Array::FIND_ACTION(size_t index, int64_t value, QueryState* state, Callback callback) const
+{
+ return state->match(index, 0, value, callback);
+}
+template bool Array::FIND_ACTION_PATTERN(size_t index, uint64_t pattern, QueryState* state, Callback callback) const
+{
+ return state->match(index, pattern, 0, callback);
+}
- state->match_count++;
- if (action == TDB_CALLBACK_IDX)
- return callback(index);
- if (action == TDB_MAX && value > *(int64_t*)state)
- state->state = value;
- if (action == TDB_MIN && value < *(int64_t*)state)
- state->state = value;
- if (action == TDB_SUM)
- state->state += value;
- if (action == TDB_COUNT)
- state->state++;
- if (action == TDB_FINDALL)
- ((Array*)state->state)->add(index);
- if (action == TDB_RETURN_FIRST) {
- state->state = index;
- return false;
- }
- return true;
- }
+template uint64_t Array::cascade(uint64_t a) const
+{
+ // Takes a chunk of values as argument and sets the uppermost bit for each element which is 0. Example:
+ // width == 4 and v = 01000000 00001000 10000001 00001000 00000000 10100100 00001100 00111110 01110100 00010000 00000000 00000001 10000000 01111110
+ // will return: 00001000 00010000 00010000 00010000 00010001 00000000 00010000 00000000 00000000 00000001 00010001 00010000 00000001 00000000
- template bool Array::USES_VAL(void)
- {
- if (action == TDB_MAX || action == TDB_MIN || action == TDB_SUM)
- return true;
- else
- return false;
- }
+ // static values needed for fast population count
+ const uint64_t m1 = 0x5555555555555555ULL;
- // These wrapper functions only exist to enable a possibility to make the compiler see that 'value' and/or 'index' are unused, such that caller's
- // computation of these values will not be made. Only works if FIND_ACTION and FIND_ACTION_PATTERN rewritten as macros. Note: This problem has been fixed in
- // next upcoming array.hpp version
- template bool Array::FIND_ACTION(size_t index, int64_t value, state_state *state, Callback callback) const
- {
- return state_match(index, 0, value, state, callback);
- }
- template bool Array::FIND_ACTION_PATTERN(size_t index, uint64_t pattern, state_state *state, Callback callback) const
- {
- return state_match(index, pattern, 0, state, callback);
+ if (width == 1) {
+ return ~a;
}
+ else if (width == 2) {
+ // Masks to avoid spillover between segments in cascades
+ const uint64_t c1 = ~0ULL/0x3 * 0x1;
+ a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
+ a &= m1; // isolate single bit in each segment
+ a ^= m1; // reverse isolated bits
- template uint64_t Array::cascade(uint64_t a) const
- {
- // Takes a chunk of values as argument and sets the uppermost bit for each element which is 0. Example:
- // width == 4 and v = 01000000 00001000 10000001 00001000 00000000 10100100 00001100 00111110 01110100 00010000 00000000 00000001 10000000 01111110
- // will return: 00001000 00010000 00010000 00010000 00010001 00000000 00010000 00000000 00000000 00000001 00010001 00010000 00000001 00000000
-
- // static values needed for fast population count
- const uint64_t m1 = 0x5555555555555555ULL;
-
- if (width == 1) {
- return ~a;
- }
- else if (width == 2) {
- // Masks to avoid spillover between segments in cascades
- const uint64_t c1 = ~0ULL/0x3 * 0x1;
-
- a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
- a &= m1; // isolate single bit in each segment
- a ^= m1; // reverse isolated bits
-
- return a;
- }
- else if (width == 4) {
- const uint64_t m = ~0ULL/0xF * 0x1;
+ return a;
+ }
+ else if (width == 4) {
+ const uint64_t m = ~0ULL/0xF * 0x1;
- // Masks to avoid spillover between segments in cascades
- const uint64_t c1 = ~0ULL/0xF * 0x7;
- const uint64_t c2 = ~0ULL/0xF * 0x3;
+ // Masks to avoid spillover between segments in cascades
+ const uint64_t c1 = ~0ULL/0xF * 0x7;
+ const uint64_t c2 = ~0ULL/0xF * 0x3;
- a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
- a |= (a >> 2) & c2;
- a &= m; // isolate single bit in each segment
- a ^= m; // reverse isolated bits
+ a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
+ a |= (a >> 2) & c2;
+ a &= m; // isolate single bit in each segment
+ a ^= m; // reverse isolated bits
- return a;
- }
- else if (width == 8) {
- const uint64_t m = ~0ULL/0xFF * 0x1;
+ return a;
+ }
+ else if (width == 8) {
+ const uint64_t m = ~0ULL/0xFF * 0x1;
- // Masks to avoid spillover between segments in cascades
- const uint64_t c1 = ~0ULL/0xFF * 0x7F;
- const uint64_t c2 = ~0ULL/0xFF * 0x3F;
- const uint64_t c3 = ~0ULL/0xFF * 0x0F;
+ // Masks to avoid spillover between segments in cascades
+ const uint64_t c1 = ~0ULL/0xFF * 0x7F;
+ const uint64_t c2 = ~0ULL/0xFF * 0x3F;
+ const uint64_t c3 = ~0ULL/0xFF * 0x0F;
- a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
- a |= (a >> 2) & c2;
- a |= (a >> 4) & c3;
- a &= m; // isolate single bit in each segment
- a ^= m; // reverse isolated bits
+ a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
+ a |= (a >> 2) & c2;
+ a |= (a >> 4) & c3;
+ a &= m; // isolate single bit in each segment
+ a ^= m; // reverse isolated bits
- return a;
- }
- else if (width == 16) {
- const uint64_t m = ~0ULL/0xFFFF * 0x1;
-
- // Masks to avoid spillover between segments in cascades
- const uint64_t c1 = ~0ULL/0xFFFF * 0x7FFF;
- const uint64_t c2 = ~0ULL/0xFFFF * 0x3FFF;
- const uint64_t c3 = ~0ULL/0xFFFF * 0x0FFF;
- const uint64_t c4 = ~0ULL/0xFFFF * 0x00FF;
-
- a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
- a |= (a >> 2) & c2;
- a |= (a >> 4) & c3;
- a |= (a >> 8) & c4;
- a &= m; // isolate single bit in each segment
- a ^= m; // reverse isolated bits
-
- return a;
- }
+ return a;
+ }
+ else if (width == 16) {
+ const uint64_t m = ~0ULL/0xFFFF * 0x1;
+
+ // Masks to avoid spillover between segments in cascades
+ const uint64_t c1 = ~0ULL/0xFFFF * 0x7FFF;
+ const uint64_t c2 = ~0ULL/0xFFFF * 0x3FFF;
+ const uint64_t c3 = ~0ULL/0xFFFF * 0x0FFF;
+ const uint64_t c4 = ~0ULL/0xFFFF * 0x00FF;
+
+ a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
+ a |= (a >> 2) & c2;
+ a |= (a >> 4) & c3;
+ a |= (a >> 8) & c4;
+ a &= m; // isolate single bit in each segment
+ a ^= m; // reverse isolated bits
+
+ return a;
+ }
- else if (width == 32) {
- const uint64_t m = ~0ULL/0xFFFFFFFF * 0x1;
-
- // Masks to avoid spillover between segments in cascades
- const uint64_t c1 = ~0ULL/0xFFFFFFFF * 0x7FFFFFFF;
- const uint64_t c2 = ~0ULL/0xFFFFFFFF * 0x3FFFFFFF;
- const uint64_t c3 = ~0ULL/0xFFFFFFFF * 0x0FFFFFFF;
- const uint64_t c4 = ~0ULL/0xFFFFFFFF * 0x00FFFFFF;
- const uint64_t c5 = ~0ULL/0xFFFFFFFF * 0x0000FFFF;
-
- a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
- a |= (a >> 2) & c2;
- a |= (a >> 4) & c3;
- a |= (a >> 8) & c4;
- a |= (a >> 16) & c5;
- a &= m; // isolate single bit in each segment
- a ^= m; // reverse isolated bits
-
- return a;
- }
- else if (width == 64) {
- return a == 0 ? 1 : 0;
- }
- else {
- TIGHTDB_ASSERT(false);
- return uint64_t(-1);
- }
+ else if (width == 32) {
+ const uint64_t m = ~0ULL/0xFFFFFFFF * 0x1;
+
+ // Masks to avoid spillover between segments in cascades
+ const uint64_t c1 = ~0ULL/0xFFFFFFFF * 0x7FFFFFFF;
+ const uint64_t c2 = ~0ULL/0xFFFFFFFF * 0x3FFFFFFF;
+ const uint64_t c3 = ~0ULL/0xFFFFFFFF * 0x0FFFFFFF;
+ const uint64_t c4 = ~0ULL/0xFFFFFFFF * 0x00FFFFFF;
+ const uint64_t c5 = ~0ULL/0xFFFFFFFF * 0x0000FFFF;
+
+ a |= (a >> 1) & c1; // cascade ones in non-zeroed segments
+ a |= (a >> 2) & c2;
+ a |= (a >> 4) & c3;
+ a |= (a >> 8) & c4;
+ a |= (a >> 16) & c5;
+ a &= m; // isolate single bit in each segment
+ a ^= m; // reverse isolated bits
+
+ return a;
+ }
+ else if (width == 64) {
+ return a == 0 ? 1 : 0;
+ }
+ else {
+ TIGHTDB_ASSERT(false);
+ return uint64_t(-1);
}
+}
- // This is the main finding function for Array. Other finding functions are just wrappers around this one.
- // Search for 'value' using condition cond2 (EQUAL, NOTEQUAL, LESS, etc) and call FIND_ACTION() or FIND_ACTION_PATTERN() for each match. Break and return if FIND_ACTION returns false or 'end' is reached.
- template void Array::find_optimized(int64_t value, size_t start, size_t end, size_t baseindex, state_state *state, Callback callback) const
- {
- cond2 C;
- TIGHTDB_ASSERT(start <= m_len && (end <= m_len || end == (size_t)-1) && start <= end);
-
- // Test first few items with no initial time overhead
- if (start > 0) {
- if (m_len > start && C(Get(start), value) && start < end) { if (!FIND_ACTION(start + baseindex, Get(start), state, callback)) return;} ++start;
- if (m_len > start && C(Get(start), value) && start < end) { if (!FIND_ACTION(start + baseindex, Get(start), state, callback)) return;} ++start;
- if (m_len > start && C(Get(start), value) && start < end) { if (!FIND_ACTION(start + baseindex, Get(start), state, callback)) return;} ++start;
- if (m_len > start && C(Get(start), value) && start < end) { if (!FIND_ACTION(start + baseindex, Get(start), state, callback)) return;} ++start;
- }
+// This is the main finding function for Array. Other finding functions are just wrappers around this one.
+// Search for 'value' using condition cond2 (EQUAL, NOTEQUAL, LESS, etc) and call FIND_ACTION() or FIND_ACTION_PATTERN() for each match. Break and return if FIND_ACTION returns false or 'end' is reached.
+template void Array::find_optimized(int64_t value, size_t start, size_t end, size_t baseindex, QueryState* state, Callback callback) const
+{
+ cond2 C;
+ TIGHTDB_ASSERT(start <= m_len && (end <= m_len || end == (size_t)-1) && start <= end);
+
+ // Test first few items with no initial time overhead
+ if (start > 0) {
+ if (m_len > start && C(Get(start), value) && start < end) { if (!FIND_ACTION(start + baseindex, Get(start), state, callback)) return;} ++start;
+ if (m_len > start && C(Get(start), value) && start < end) { if (!FIND_ACTION(start + baseindex, Get(start), state, callback)) return;} ++start;
+ if (m_len > start && C(Get(start), value) && start < end) { if (!FIND_ACTION(start + baseindex, Get(start), state, callback)) return;} ++start;
+ if (m_len > start && C(Get(start), value) && start < end) { if (!FIND_ACTION(start + baseindex, Get(start), state, callback)) return;} ++start;
+ }
- if (!(m_len > start && start < end))
- return;
+ if (!(m_len > start && start < end))
+ return;
- if (end == (size_t)-1) end = m_len;
+ if (end == (size_t)-1) end = m_len;
- // Return immediately if no items in array can match (such as if cond2 == GREATER and value == 100 and m_ubound == 15).
- if (!C.can_match(value, m_lbound, m_ubound))
- return;
+ // Return immediately if no items in array can match (such as if cond2 == GREATER and value == 100 and m_ubound == 15).
+ if (!C.can_match(value, m_lbound, m_ubound))
+ return;
- // call FIND_ACTION on all items in array if all items are guaranteed to match (such as cond2 == NOTEQUAL and value == 100 and m_ubound == 15)
- if (C.will_match(value, m_lbound, m_ubound)) {
- if (action == TDB_SUM || action == TDB_MAX || action == TDB_MIN) {
- int64_t res;
- if (action == TDB_SUM)
- res = Array::sum(start, end);
- if (action == TDB_MAX)
- Array::maximum(res, start, end);
- if (action == TDB_MIN)
- Array::minimum(res, start, end);
+ // call FIND_ACTION on all items in array if all items are guaranteed to match (such as cond2 == NOTEQUAL and value == 100 and m_ubound == 15)
+ if (C.will_match(value, m_lbound, m_ubound)) {
+ if (action == TDB_SUM || action == TDB_MAX || action == TDB_MIN) {
+ int64_t res;
+ if (action == TDB_SUM)
+ res = Array::sum(start, end);
+ if (action == TDB_MAX)
+ Array::maximum(res, start, end);
+ if (action == TDB_MIN)
+ Array::minimum(res, start, end);
- FIND_ACTION(start + baseindex, res, state, callback);
- }
- else if (action == TDB_COUNT) {
- state->state += end - start;
- }
- else {
- for (; start < end; start++)
- if (!FIND_ACTION(start + baseindex, Get(start), state, callback))
- return;
- }
- return;
+ FIND_ACTION(start + baseindex, res, state, callback);
+ }
+ else if (action == TDB_COUNT) {
+ state->state += end - start;
}
+ else {
+ for (; start < end; start++)
+ if (!FIND_ACTION(start + baseindex, Get(start), state, callback))
+ return;
+ }
+ return;
+ }
- // finder cannot handle this bitwidth
- TIGHTDB_ASSERT(m_width != 0);
+ // finder cannot handle this bitwidth
+ TIGHTDB_ASSERT(m_width != 0);
#if defined(TIGHTDB_COMPILER_SSE)
- if ((cpuid_sse<42>() && (end - start >= sizeof(__m128i) && m_width >= 8))
- || (cpuid_sse<30>() && (SameType::value && end - start >= sizeof(__m128i) && m_width >= 8 && m_width < 64))) {
+ if ((cpuid_sse<42>() && (end - start >= sizeof(__m128i) && m_width >= 8))
+ || (cpuid_sse<30>() && (SameType::value && end - start >= sizeof(__m128i) && m_width >= 8 && m_width < 64))) {
- // FindSSE() must start at 16-byte boundary, so search area before that using CompareEquality()
- __m128i* const a = (__m128i *)round_up(m_data + start * bitwidth / 8, sizeof(__m128i));
- __m128i* const b = (__m128i *)round_down(m_data + end * bitwidth / 8, sizeof(__m128i));
+ // FindSSE() must start at 16-byte boundary, so search area before that using CompareEquality()
+ __m128i* const a = (__m128i *)round_up(m_data + start * bitwidth / 8, sizeof(__m128i));
+ __m128i* const b = (__m128i *)round_down(m_data + end * bitwidth / 8, sizeof(__m128i));
- if (!Compare(value, start, ((unsigned char *)a - m_data) * 8 / NO0(bitwidth), baseindex, state, callback))
- return;
+ if (!Compare(value, start, ((unsigned char *)a - m_data) * 8 / NO0(bitwidth), baseindex, state, callback))
+ return;
- // Search aligned area with SSE
- if (b > a) {
- if(cpuid_sse<42>()) {
- if (!FindSSE(value, a, b - a, state, baseindex + (((unsigned char *)a - m_data) * 8 / NO0(bitwidth)), callback))
- return;
- }
- else if(cpuid_sse<30>()) {
-
- if (!FindSSE(value, a, b - a, state, baseindex + (((unsigned char *)a - m_data) * 8 / NO0(bitwidth)), callback))
- return;
- }
- }
-
- // Search remainder with CompareEquality()
- if (!Compare(value, ((unsigned char *)b - m_data) * 8 / NO0(bitwidth), end, baseindex, state, callback))
- return;
+ // Search aligned area with SSE
+ if (b > a) {
+ if (cpuid_sse<42>()) {
+ if (!FindSSE(value, a, b - a, state, baseindex + (((unsigned char *)a - m_data) * 8 / NO0(bitwidth)), callback))
+ return;
+ }
+ else if (cpuid_sse<30>()) {
- return;
+ if (!FindSSE(value, a, b - a, state, baseindex + (((unsigned char *)a - m_data) * 8 / NO0(bitwidth)), callback))
+ return;
+ }
}
- else {
- Compare(value, start, end, baseindex, state, callback);
+
+ // Search remainder with CompareEquality()
+ if (!Compare(value, ((unsigned char *)b - m_data) * 8 / NO0(bitwidth), end, baseindex, state, callback))
return;
- }
+
+ return;
+ }
+ else {
+ Compare(value, start, end, baseindex, state, callback);
+ return;
+ }
#else
- Compare(value, start, end, baseindex, state, callback);
- return;
+Compare(value, start, end, baseindex, state, callback);
+return;
#endif
- }
-
- // popcount
- #if defined(_MSC_VER) && _MSC_VER >= 1500
- #include
- inline int Array::fast_popcount32(uint32_t x)
- {
- return __popcnt(x);
- }
- #if defined(_M_X64)
- inline int Array::fast_popcount64(unsigned __int64 x) const
- {
- return (int)__popcnt64(x);
- }
- #else
- inline int Array::fast_popcount64(unsigned __int64 x) const
- {
- return __popcnt((unsigned)(x)) + __popcnt((unsigned)(x >> 32));
- }
- #endif
- #elif defined(__GNUC__) && __GNUC__ >= 4 || defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 900
- #define fast_popcount32 __builtin_popcount
- #if ULONG_MAX == 0xffffffff
- inline int Array::fast_popcount64(unsigned long long x) const
- {
- return __builtin_popcount((unsigned)(x)) + __builtin_popcount((unsigned)(x >> 32));
- }
- #else
- inline int Array::fast_popcount64(unsigned long long x) const
- {
- return __builtin_popcountll(x);
- }
- #endif
- #else
- static const char a_popcount_bits[256] = {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
- };
-
- // Masking away bits might be faster than bit shifting (which can be slow). Note that the compiler may optimize this automatically. Todo, investigate.
- inline int Array::fast_popcount32(uint32_t x) const
- {
- return a_popcount_bits[255 & x] + a_popcount_bits[255 & x>> 8] + a_popcount_bits[255 & x>>16] + a_popcount_bits[255 & x>>24];
- }
- inline int Array::fast_popcount64(uint64_t x) const
- {
- return fast_popcount32(x) + fast_popcount32(x >> 32);
- }
-
- #endif // select best popcount implementations
+}
- template inline int64_t Array::LowerBits(void) const
- {
- if (width == 1)
- return 0xFFFFFFFFFFFFFFFFULL;
- else if (width == 2)
- return 0x5555555555555555ULL;
- else if (width == 4)
- return 0x1111111111111111ULL;
- else if (width == 8)
- return 0x0101010101010101ULL;
- else if (width == 16)
- return 0x0001000100010001ULL;
- else if (width == 32)
- return 0x0000000100000001ULL;
- else if (width == 64)
- return 0x0000000000000001ULL;
- else {
- TIGHTDB_ASSERT(false);
- return int64_t(-1);
- }
+template inline int64_t Array::LowerBits(void) const
+{
+ if (width == 1)
+ return 0xFFFFFFFFFFFFFFFFULL;
+ else if (width == 2)
+ return 0x5555555555555555ULL;
+ else if (width == 4)
+ return 0x1111111111111111ULL;
+ else if (width == 8)
+ return 0x0101010101010101ULL;
+ else if (width == 16)
+ return 0x0001000100010001ULL;
+ else if (width == 32)
+ return 0x0000000100000001ULL;
+ else if (width == 64)
+ return 0x0000000000000001ULL;
+ else {
+ TIGHTDB_ASSERT(false);
+ return int64_t(-1);
}
+}
- // Tests if any chunk in 'value' is 0
- template inline bool Array::TestZero(uint64_t value) const {
- uint64_t hasZeroByte;
- uint64_t lower = LowerBits();
- uint64_t upper = LowerBits() * 1ULL << (width == 0 ? 0 : (width - 1ULL));
- hasZeroByte = (value - lower) & ~value & upper;
- return hasZeroByte != 0;
- }
+// Tests if any chunk in 'value' is 0
+template inline bool Array::TestZero(uint64_t value) const
+{
+ uint64_t hasZeroByte;
+ uint64_t lower = LowerBits();
+ uint64_t upper = LowerBits() * 1ULL << (width == 0 ? 0 : (width - 1ULL));
+ hasZeroByte = (value - lower) & ~value & upper;
+ return hasZeroByte != 0;
+}
- // Finds first zero (if eq == true) or non-zero (if eq == false) element in v and returns its position.
- // IMPORTANT: This function assumes that at least 1 item matches (test this with TestZero() or other means first)!
- template size_t Array::FindZero(uint64_t v) const
- {
- size_t start = 0;
- uint64_t hasZeroByte;
- uint64_t mask = (width == 64 ? ~0ULL : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1
+// Finds first zero (if eq == true) or non-zero (if eq == false) element in v and returns its position.
+// IMPORTANT: This function assumes that at least 1 item matches (test this with TestZero() or other means first)!
+template size_t Array::FindZero(uint64_t v) const
+{
+ size_t start = 0;
+ uint64_t hasZeroByte;
+ uint64_t mask = (width == 64 ? ~0ULL : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1
- if (eq == (((v >> (width * start)) & mask) == 0)) {
- return 0;
- }
+ if (eq == (((v >> (width * start)) & mask) == 0)) {
+ return 0;
+ }
- // Bisection optimization, speeds up small bitwidths with high match frequency. More partions than 2 do NOT pay off because
- // the work done by TestZero() is wasted for the cases where the value exists in first half, but useful if it exists in last
- // half. Sweet spot turns out to be the widths and partitions below.
- if (width <= 8) {
- hasZeroByte = TestZero(v | 0xffffffff00000000ULL);
- if (eq ? !hasZeroByte : (v & 0x00000000ffffffffULL) == 0) {
- // 00?? -> increasing
- start += 64 / NO0(width) / 2;
- if (width <= 4) {
- hasZeroByte = TestZero(v | 0xffff000000000000ULL);
- if (eq ? !hasZeroByte : (v & 0x0000ffffffffffffULL) == 0) {
- // 000?
- start += 64 / NO0(width) / 4;
- }
+ // Bisection optimization, speeds up small bitwidths with high match frequency. More partions than 2 do NOT pay off because
+ // the work done by TestZero() is wasted for the cases where the value exists in first half, but useful if it exists in last
+ // half. Sweet spot turns out to be the widths and partitions below.
+ if (width <= 8) {
+ hasZeroByte = TestZero(v | 0xffffffff00000000ULL);
+ if (eq ? !hasZeroByte : (v & 0x00000000ffffffffULL) == 0) {
+ // 00?? -> increasing
+ start += 64 / NO0(width) / 2;
+ if (width <= 4) {
+ hasZeroByte = TestZero(v | 0xffff000000000000ULL);
+ if (eq ? !hasZeroByte : (v & 0x0000ffffffffffffULL) == 0) {
+ // 000?
+ start += 64 / NO0(width) / 4;
}
}
- else {
- if (width <= 4) {
- // ??00
- hasZeroByte = TestZero(v | 0xffffffffffff0000ULL);
- if (eq ? !hasZeroByte : (v & 0x000000000000ffffULL) == 0) {
- // 0?00
- start += 64 / NO0(width) / 4;
- }
+ }
+ else {
+ if (width <= 4) {
+ // ??00
+ hasZeroByte = TestZero(v | 0xffffffffffff0000ULL);
+ if (eq ? !hasZeroByte : (v & 0x000000000000ffffULL) == 0) {
+ // 0?00
+ start += 64 / NO0(width) / 4;
}
}
}
-
- while (eq == (((v >> (width * start)) & mask) != 0)) {
- TIGHTDB_ASSERT(start <= 8 * sizeof(v)); // You must only call FindZero() if you are sure that at least 1 item matches
- start++;
- }
-
- return start;
}
- // Generate a magic constant used for later bithacks
- template int64_t Array::FindGTLT_Magic(int64_t v) const
- {
- uint64_t mask1 = (width == 64 ? ~0ULL : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1
- uint64_t mask2 = mask1 >> 1;
- uint64_t magic = gt ? (~0ULL / NO0(mask1) * (mask2 - v)) : (~0ULL / NO0(mask1) * v);
- return magic;
+ while (eq == (((v >> (width * start)) & mask) != 0)) {
+ TIGHTDB_ASSERT(start <= 8 * sizeof(v)); // You must only call FindZero() if you are sure that at least 1 item matches
+ start++;
}
- template bool Array::FindGTLT_Fast(uint64_t chunk, uint64_t magic, state_state *state, size_t baseindex, Callback callback) const
- {
- // Tests if a a chunk of values contains values that are greater (if gt == true) or less (if gt == false) than v.
- // Fast, but limited to work when all values in the chunk are positive.
-
- uint64_t mask1 = (width == 64 ? ~0ULL : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1
- uint64_t mask2 = mask1 >> 1;
- uint64_t m = gt ? (((chunk + magic) | chunk) & ~0ULL / NO0(mask1) * (mask2 + 1)) : ((chunk - magic) & ~chunk&~0ULL/NO0(mask1)*(mask2+1));
- size_t p = 0;
- while(m) {
- if (FIND_ACTION_PATTERN(baseindex, m >> (NO0(width) - 1), state, callback))
- break; // consumed, so do not call FIND_ACTION()
-
- size_t t = FirstSetBit64(m) / NO0(width);
- p += t;
- if (!FIND_ACTION(p + baseindex, (chunk >> (p * width)) & mask1, state, callback))
- return false;
+ return start;
+}
- if ((t + 1) * width == 64)
- m = 0;
- else
- m >>= (t + 1) * width;
- p++;
- }
+// Generate a magic constant used for later bithacks
+template int64_t Array::FindGTLT_Magic(int64_t v) const
+{
+ uint64_t mask1 = (width == 64 ? ~0ULL : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1
+ uint64_t mask2 = mask1 >> 1;
+ uint64_t magic = gt ? (~0ULL / NO0(mask1) * (mask2 - v)) : (~0ULL / NO0(mask1) * v);
+ return magic;
+}
- return true;
+template bool Array::FindGTLT_Fast(uint64_t chunk, uint64_t magic, QueryState* state, size_t baseindex, Callback callback) const
+{
+ // Tests if a a chunk of values contains values that are greater (if gt == true) or less (if gt == false) than v.
+ // Fast, but limited to work when all values in the chunk are positive.
+
+ uint64_t mask1 = (width == 64 ? ~0ULL : ((1ULL << (width == 64 ? 0 : width)) - 1ULL)); // Warning free way of computing (1ULL << width) - 1
+ uint64_t mask2 = mask1 >> 1;
+ uint64_t m = gt ? (((chunk + magic) | chunk) & ~0ULL / NO0(mask1) * (mask2 + 1)) : ((chunk - magic) & ~chunk&~0ULL/NO0(mask1)*(mask2+1));
+ size_t p = 0;
+ while(m) {
+ if (FIND_ACTION_PATTERN(baseindex, m >> (NO0(width) - 1), state, callback))
+ break; // consumed, so do not call FIND_ACTION()
+
+ size_t t = FirstSetBit64(m) / NO0(width);
+ p += t;
+ if (!FIND_ACTION(p + baseindex, (chunk >> (p * width)) & mask1, state, callback))
+ return false;
+
+ if ((t + 1) * width == 64)
+ m = 0;
+ else
+ m >>= (t + 1) * width;
+ p++;
}
+ return true;
+}
- template bool Array::FindGTLT(int64_t v, uint64_t chunk, state_state *state, size_t baseindex, Callback callback) const
- {
- // Fínd items in 'chunk' that are greater (if gt == true) or smaller (if gt == false) than 'v'. Fixme, __forceinline can make it crash in vS2010 - find out why
- if (width == 1) {
- for (size_t t = 0; t < 64; t++) {
- if (gt ? (int64_t)(chunk & 0x1) > v : (int64_t)(chunk & 0x1) < v) {if (!FIND_ACTION( t + baseindex, (int64_t)(chunk & 0x1), state, callback)) return false;} chunk >>= 1;
- }
- }
- else if (width == 2) {
- // Alot (50% +) faster than loop/compiler-unrolled loop
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 0 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 1 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 2 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 3 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 4 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 5 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 6 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 7 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
-
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 8 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 9 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 10 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 11 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 12 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 13 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 14 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 15 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
-
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 16 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 17 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 18 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 19 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 20 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 21 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 22 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 23 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
-
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 24 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 25 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 26 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 27 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 28 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 29 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 30 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 31 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
- }
- else if (width == 4) {
- // 128 ms:
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 0 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 1 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 2 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 3 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 4 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 5 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 6 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 7 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
-
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 8 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 9 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 10 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 11 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 12 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 13 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 14 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
- if (gt ? (int64_t)(chunk & 0xf) > v : (int64_t)(chunk & 0xf) < v) {if (!FIND_ACTION( 15 + baseindex, (int64_t)(chunk & 0xf), state, callback)) return false;} chunk >>= 4;
-
- // 187 ms:
- // if (gt ? (int64_t)(chunk >> 0*4) & 0xf > v : (int64_t)(chunk >> 0*4) & 0xf < v) return 0;
+
+template bool Array::FindGTLT(int64_t v, uint64_t chunk, QueryState* state, size_t baseindex, Callback callback) const
+{
+ // Fínd items in 'chunk' that are greater (if gt == true) or smaller (if gt == false) than 'v'. Fixme, __forceinline can make it crash in vS2010 - find out why
+ if (width == 1) {
+ for (size_t t = 0; t < 64; t++) {
+ if (gt ? (int64_t)(chunk & 0x1) > v : (int64_t)(chunk & 0x1) < v) {if (!FIND_ACTION( t + baseindex, (int64_t)(chunk & 0x1), state, callback)) return false;} chunk >>= 1;
}
- else if (width == 8) {
- // 88 ms:
- if (gt ? (char)chunk > v : (char)chunk < v) {if (!FIND_ACTION( 0 + baseindex, (char)chunk, state, callback)) return false;} chunk >>= 8;
- if (gt ? (char)chunk > v : (char)chunk < v) {if (!FIND_ACTION( 1 + baseindex, (char)chunk, state, callback)) return false;} chunk >>= 8;
- if (gt ? (char)chunk > v : (char)chunk < v) {if (!FIND_ACTION( 2 + baseindex, (char)chunk, state, callback)) return false;} chunk >>= 8;
- if (gt ? (char)chunk > v : (char)chunk < v) {if (!FIND_ACTION( 3 + baseindex, (char)chunk, state, callback)) return false;} chunk >>= 8;
- if (gt ? (char)chunk > v : (char)chunk < v) {if (!FIND_ACTION( 4 + baseindex, (char)chunk, state, callback)) return false;} chunk >>= 8;
- if (gt ? (char)chunk > v : (char)chunk < v) {if (!FIND_ACTION( 5 + baseindex, (char)chunk, state, callback)) return false;} chunk >>= 8;
- if (gt ? (char)chunk > v : (char)chunk < v) {if (!FIND_ACTION( 6 + baseindex, (char)chunk, state, callback)) return false;} chunk >>= 8;
- if (gt ? (char)chunk > v : (char)chunk < v) {if (!FIND_ACTION( 7 + baseindex, (char)chunk, state, callback)) return false;} chunk >>= 8;
+ }
+ else if (width == 2) {
+ // Alot (50% +) faster than loop/compiler-unrolled loop
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 0 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 1 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 2 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 3 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 4 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 5 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 6 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 7 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 8 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 9 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 10 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION( 11 + baseindex, (int64_t)(chunk & 0x3), state, callback)) return false;} chunk >>= 2;
+ if (gt ? (int64_t)(chunk & 0x3) > v : (int64_t)(chunk & 0x3) < v) {if (!FIND_ACTION