diff --git a/CHANGELOG.md b/CHANGELOG.md index 37243983f11..7821afdef26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ ----------- ### Internals -* None. +* Simplify the implementation of query expression nodes which have a btree leaf cache. ---------------------------------------------- diff --git a/src/realm/metrics/query_info.cpp b/src/realm/metrics/query_info.cpp index 5b5e75816a9..4ff00370ead 100644 --- a/src/realm/metrics/query_info.cpp +++ b/src/realm/metrics/query_info.cpp @@ -20,7 +20,6 @@ #include #include #include -#include using namespace realm; using namespace realm::metrics; diff --git a/src/realm/metrics/query_info.hpp b/src/realm/metrics/query_info.hpp index 7bc9795db5f..1334a076880 100644 --- a/src/realm/metrics/query_info.hpp +++ b/src/realm/metrics/query_info.hpp @@ -21,7 +21,6 @@ #include #include -#include #include #include diff --git a/src/realm/query.cpp b/src/realm/query.cpp index 156ef5ee753..4222fc3fd26 100644 --- a/src/realm/query.cpp +++ b/src/realm/query.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -1056,6 +1055,20 @@ size_t Query::find_best_node(ParentNode* pn) const void Query::aggregate_internal(ParentNode* pn, QueryStateBase* st, size_t start, size_t end, ArrayPayload* source_column) const { + // Number of matches to find in best condition loop before breaking out to probe other conditions. Too low value + // gives too many constant time overheads everywhere in the query engine. Too high value makes it adapt less + // rapidly to changes in match frequencies. + constexpr size_t findlocals = 64; + + // Average match distance in linear searches where further increase in distance no longer increases query speed + // (because time spent on handling each match becomes insignificant compared to time spent on the search). + constexpr size_t bestdist = 512; + + // Minimum number of matches required in a certain condition before it can be used to compute statistics. Too high + // value can spent too much time in a bad node (with high match frequency). Too low value gives inaccurate + // statistics. + constexpr size_t probe_matches = 4; + while (start < end) { // Executes start...end range of a query and will stay inside the condition loop of the node it was called // on. Can be called on any node; yields same result, but different performance. Returns prematurely if diff --git a/src/realm/query.hpp b/src/realm/query.hpp index ef0f17e18b0..9648daf8161 100644 --- a/src/realm/query.hpp +++ b/src/realm/query.hpp @@ -35,28 +35,27 @@ #endif #include -#include -#include #include -#include +#include #include -#include +#include +#include #include -#include +#include namespace realm { // Pre-declarations -class ParentNode; -class Table; -class TableView; -class TableView; class Array; class Expression; class Group; -class Transaction; class LinkMap; +class ParentNode; +class Table; +class TableView; +class Timestamp; +class Transaction; namespace metrics { class QueryInfo; diff --git a/src/realm/query_engine.cpp b/src/realm/query_engine.cpp index 910bf2706d8..855709f4150 100644 --- a/src/realm/query_engine.cpp +++ b/src/realm/query_engine.cpp @@ -189,7 +189,7 @@ size_t MixedNode::find_first_local(size_t start, size_t end) return m_index_evaluator->do_search_index(m_cluster, start, end); } else { - return m_leaf_ptr->find_first(m_value, start, end); + return m_leaf->find_first(m_value, start, end); } return not_found; @@ -246,7 +246,7 @@ size_t MixedNode::find_first_local(size_t start, size_t end) EqualIns cond; if (m_value.is_type(type_String)) { for (size_t i = start; i < end; i++) { - QueryValue val(m_leaf_ptr->get(i)); + QueryValue val(m_leaf->get(i)); StringData val_as_str; if (val.is_type(type_String)) { val_as_str = val.get(); @@ -261,7 +261,7 @@ size_t MixedNode::find_first_local(size_t start, size_t end) } else { for (size_t i = start; i < end; i++) { - QueryValue val(m_leaf_ptr->get(i)); + QueryValue val(m_leaf->get(i)); if (cond(val, m_value)) return i; } @@ -416,13 +416,13 @@ bool StringNode::do_consume_condition(ParentNode& node) size_t StringNode::_find_first_local(size_t start, size_t end) { if (m_needles.empty()) { - return m_leaf_ptr->find_first(m_value, start, end); + return m_leaf->find_first(m_value, start, end); } else { if (end == npos) - end = m_leaf_ptr->size(); + end = m_leaf->size(); REALM_ASSERT_3(start, <=, end); - return find_first_haystack<20>(*m_leaf_ptr, m_needles, start, end); + return find_first_haystack<20>(*m_leaf, m_needles, start, end); } } @@ -826,7 +826,7 @@ size_t LinksToNode::find_first_local(size_t start, size_t end) BPlusTree links(m_table.unchecked_ptr()->get_alloc()); for (size_t i = start; i < end; i++) { - if (ref_type ref = LinkMap::get_ref(m_leaf_ptr, m_column_type, i)) { + if (ref_type ref = get_ref(i)) { links.init_from_ref(ref); for (auto& key : m_target_keys) { if (key) { @@ -837,9 +837,9 @@ size_t LinksToNode::find_first_local(size_t start, size_t end) } } } - else if (m_column_type == col_type_Link) { + else if (m_list) { for (auto& key : m_target_keys) { - auto pos = static_cast(m_leaf_ptr)->find_first(key, start, end); + auto pos = m_list->find_first(key, start, end); if (pos != realm::npos) { return pos; } @@ -859,7 +859,7 @@ size_t LinksToNode::find_first_local(size_t start, size_t end) if (m_column_type == col_type_LinkList || m_condition_column_key.is_set()) { BPlusTree links(m_table.unchecked_ptr()->get_alloc()); for (size_t i = start; i < end; i++) { - if (ref_type ref = LinkMap::get_ref(m_leaf_ptr, m_column_type, i)) { + if (ref_type ref = get_ref(i)) { links.init_from_ref(ref); auto sz = links.size(); for (size_t j = 0; j < sz; j++) { @@ -870,10 +870,9 @@ size_t LinksToNode::find_first_local(size_t start, size_t end) } } } - else if (m_column_type == col_type_Link) { - auto leaf = static_cast(m_leaf_ptr); + else if (m_list) { for (size_t i = start; i < end; i++) { - if (leaf->get(i) != key) { + if (m_list->get(i) != key) { return i; } } diff --git a/src/realm/query_engine.hpp b/src/realm/query_engine.hpp index 33645154646..af97159c359 100644 --- a/src/realm/query_engine.hpp +++ b/src/realm/query_engine.hpp @@ -61,24 +61,6 @@ Template arguments in methods: TConditionFunction: Each node has a condition from query_conditions.c such as Equal, GreaterEqual, etc TConditionValue: Type of values in condition column. That is, int64_t, float, int, bool, etc - -TAction: What to do with each search result, from the enums act_ReturnFirst, act_Count, act_Sum, etc - -TResult: Type of result of actions - float, double, int64_t, etc. Special notes: For act_Count it's - int64_t, for RLM_FIND_ALL it's int64_t which points at destination array. - -TSourceColumn: Type of source column used in actions, or *ignored* if no source column is used (like for - act_Count, act_ReturnFirst) - - -There are two important classes used in queries: ----------------------------------------------------------------------------------------------------- -SequentialGetter Column iterator used to get successive values with leaf caching. Used both for condition columns - and aggregate source column - -AggregateState State of the aggregate - contains a state variable that stores intermediate sum, max, min, - etc, etc. - */ #ifndef REALM_QUERY_ENGINE_HPP @@ -124,24 +106,6 @@ namespace realm { class IndexEvaluator; -// Number of matches to find in best condition loop before breaking out to probe other conditions. Too low value gives -// too many constant time overheads everywhere in the query engine. Too high value makes it adapt less rapidly to -// changes in match frequencies. -const size_t findlocals = 64; - -// Average match distance in linear searches where further increase in distance no longer increases query speed -// (because time spent on handling each match becomes insignificant compared to time spent on the search). -const size_t bestdist = 512; - -// Minimum number of matches required in a certain condition before it can be used to compute statistics. Too high -// value can spent too much time in a bad node (with high match frequency). Too low value gives inaccurate statistics. -const size_t probe_matches = 4; - -const size_t bitwidth_time_unit = 64; - -typedef bool (*CallbackDummy)(int64_t); -using Evaluator = util::FunctionRef; - class ParentNode { typedef ParentNode ThisType; @@ -174,6 +138,7 @@ class ParentNode { double cost() const { + constexpr size_t bitwidth_time_unit = 64; // dt = 1/64 to 1. Match dist is 8 times more important than bitwidth return 8 * bitwidth_time_unit / m_dD + m_dT; } @@ -341,9 +306,6 @@ class ColumnNodeBase : public ParentNode { class IndexEvaluator { public: - IndexEvaluator() {} - virtual ~IndexEvaluator() = default; - void init(StringIndex* index, Mixed value); void init(std::vector* storage); @@ -362,7 +324,7 @@ class IndexEvaluator { } private: - inline ObjKey get_internal(size_t ndx) const + ObjKey get_internal(size_t ndx) const { if (m_matching_keys) { return m_matching_keys->at(ndx); @@ -391,7 +353,6 @@ template class IntegerNodeBase : public ColumnNodeBase { public: using TConditionValue = typename LeafType::value_type; - // static const bool nullable = ColType::nullable; protected: IntegerNodeBase(TConditionValue value, ColKey column_key) @@ -408,15 +369,8 @@ class IntegerNodeBase : public ColumnNodeBase { void cluster_changed() override { - // Assigning nullptr will cause the Leaf destructor to be called. Must - // be done before assigning a new one. Otherwise the destructor will be - // called after the constructor is called and that is unfortunate if - // the object has the same address. (As in this case) - m_array_ptr = nullptr; - // Create new Leaf - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(this->m_condition_column_key, &*m_leaf); } void init(bool will_query_ranges) override @@ -432,21 +386,21 @@ class IntegerNodeBase : public ColumnNodeBase { return true; // Compare leafs to see if they are the same auto leaf = dynamic_cast(m_source_column); - return leaf ? leaf->get_ref() == m_leaf_ptr->get_ref() : false; + return leaf && leaf->get_ref() == m_leaf->get_ref(); } template size_t find_all_local(size_t start, size_t end) { if (run_single()) { - m_leaf_ptr->template find(m_value, start, end, m_state, nullptr); + m_leaf->template find(m_value, start, end, m_state, nullptr); } else { auto callback = [this](size_t index) { auto val = m_source_column->get_any(index); return m_state->match(index, val); }; - m_leaf_ptr->template find(m_value, start, end, m_state, callback); + m_leaf->template find(m_value, start, end, m_state, callback); } return end; @@ -463,11 +417,7 @@ class IntegerNodeBase : public ColumnNodeBase { TConditionValue m_value; // Leaf cache - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const LeafType* m_leaf_ptr = nullptr; + std::optional m_leaf; }; @@ -490,7 +440,7 @@ class IntegerNode : public IntegerNodeBase { size_t find_first_local(size_t start, size_t end) override { - return this->m_leaf_ptr->template find_first(this->m_value, start, end); + return this->m_leaf->template find_first(this->m_value, start, end); } size_t find_all_local(size_t start, size_t end) override @@ -586,18 +536,18 @@ class IntegerNode : public IntegerNodeBase { if (start < end) { if (m_nb_needles) { - s = find_first_haystack<22>(*this->m_leaf_ptr, m_needles, start, end); + s = find_first_haystack<22>(*this->m_leaf, m_needles, start, end); } else if (m_index_evaluator) { return m_index_evaluator->do_search_index(BaseType::m_cluster, start, end); } else if (end - start == 1) { - if (this->m_leaf_ptr->get(start) == this->m_value) { + if (this->m_leaf->get(start) == this->m_value) { s = start; } } else { - s = this->m_leaf_ptr->template find_first(this->m_value, start, end); + s = this->m_leaf->template find_first(this->m_value, start, end); } } @@ -670,15 +620,8 @@ class FloatDoubleNode : public ParentNode { void cluster_changed() override { - // Assigning nullptr will cause the Leaf destructor to be called. Must - // be done before assigning a new one. Otherwise the destructor will be - // called after the constructor is called and that is unfortunate if - // the object has the same address. (As in this case) - m_array_ptr = nullptr; - // Create new Leaf - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(this->m_condition_column_key, &*m_leaf); } size_t find_first_local(size_t start, size_t end) override @@ -686,11 +629,11 @@ class FloatDoubleNode : public ParentNode { TConditionFunction cond; auto find = [&](bool nullability) { - bool m_value_nan = nullability ? null::is_null_float(m_value) : false; + bool value_nan = nullability ? null::is_null_float(m_value) : false; for (size_t s = start; s < end; ++s) { - TConditionValue v = m_leaf_ptr->get(s); + TConditionValue v = m_leaf->get(s); REALM_ASSERT(!(null::is_null_float(v) && !nullability)); - if (cond(v, m_value, nullability ? null::is_null_float(v) : false, m_value_nan)) + if (cond(v, m_value, nullability ? null::is_null_float(v) : false, value_nan)) return s; } return not_found; @@ -727,12 +670,7 @@ class FloatDoubleNode : public ParentNode { protected: TConditionValue m_value; - // Leaf cache - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const LeafType* m_leaf_ptr = nullptr; + std::optional m_leaf; }; template @@ -747,21 +685,14 @@ class SizeNode : public ParentNode { void cluster_changed() override { - // Assigning nullptr will cause the Leaf destructor to be called. Must - // be done before assigning a new one. Otherwise the destructor will be - // called after the constructor is called and that is unfortunate if - // the object has the same address. (As in this case) - m_array_ptr = nullptr; - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); } size_t find_first_local(size_t start, size_t end) override { for (size_t s = start; s < end; ++s) { - T v = m_leaf_ptr->get(s); - if (v) { + if (T v = m_leaf->get(s)) { int64_t sz = v.size(); if (TConditionFunction()(sz, m_value)) return s; @@ -782,14 +713,8 @@ class SizeNode : public ParentNode { } private: - // Leaf cache using LeafType = typename ColumnTypeTraits::cluster_leaf_type; - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const LeafType* m_leaf_ptr = nullptr; - + std::optional m_leaf; int64_t m_value; }; @@ -814,14 +739,8 @@ class SizeListNode : public ParentNode { void cluster_changed() override { - // Assigning nullptr will cause the Leaf destructor to be called. Must - // be done before assigning a new one. Otherwise the destructor will be - // called after the constructor is called and that is unfortunate if - // the object has the same address. (As in this case) - m_array_ptr = nullptr; - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayList(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); reset_cache(); } @@ -835,8 +754,7 @@ class SizeListNode : public ParentNode { { Allocator& alloc = m_table.unchecked_ptr()->get_alloc(); for (size_t s = start; s < end; ++s) { - ref_type ref = m_leaf_ptr->get(s); - if (ref) { + if (ref_type ref = m_leaf->get(s)) { int64_t sz = size_of_list_from_ref(ref, alloc, m_cached_col_type, m_cached_nullable); if (TConditionFunction()(sz, m_value)) return s; @@ -857,12 +775,7 @@ class SizeListNode : public ParentNode { } private: - // Leaf cache - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayList* m_leaf_ptr = nullptr; + std::optional m_leaf; int64_t m_value; @@ -891,24 +804,22 @@ class BinaryNode : public ParentNode { void cluster_changed() override { - m_array_ptr = nullptr; - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayBinary(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); } size_t find_first_local(size_t start, size_t end) override { TConditionFunction condition; for (size_t s = start; s < end; ++s) { - BinaryData value = m_leaf_ptr->get(s); + BinaryData value = m_leaf->get(s); if (condition(m_value.get(), value)) return s; } return not_found; } - virtual std::string describe(util::serializer::SerialisationState& state) const override + std::string describe(util::serializer::SerialisationState& state) const override { REALM_ASSERT(m_condition_column_key); return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + @@ -928,11 +839,7 @@ class BinaryNode : public ParentNode { private: OwnedBinaryData m_value; - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayBinary* m_leaf_ptr = nullptr; + std::optional m_leaf; }; template @@ -986,10 +893,8 @@ class BoolNode : public ParentNode { void cluster_changed() override { - m_array_ptr = nullptr; - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayBoolNull(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); } size_t find_first_local(size_t start, size_t end) override @@ -1003,14 +908,14 @@ class BoolNode : public ParentNode { TConditionFunction condition; bool m_value_is_null = !m_value; for (size_t s = start; s < end; ++s) { - util::Optional value = m_leaf_ptr->get(s); + auto value = m_leaf->get(s); if (condition(value, m_value, !value, m_value_is_null)) return s; } return not_found; } - virtual std::string describe(util::serializer::SerialisationState& state) const override + std::string describe(util::serializer::SerialisationState& state) const override { return state.describe_column(ParentNode::m_table, m_condition_column_key) + " " + TConditionFunction::description() + " " + util::serializer::print_value(m_value); @@ -1022,12 +927,8 @@ class BoolNode : public ParentNode { } private: - util::Optional m_value; - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayBoolNull* m_leaf_ptr = nullptr; + std::optional m_value; + std::optional m_leaf; std::optional m_index_evaluator; }; @@ -1050,10 +951,8 @@ class TimestampNodeBase : public ParentNode { void cluster_changed() override { - m_array_ptr = nullptr; - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayTimestamp(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); } protected: @@ -1064,11 +963,7 @@ class TimestampNodeBase : public ParentNode { } Timestamp m_value; - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayTimestamp* m_leaf_ptr = nullptr; + std::optional m_leaf; }; template @@ -1101,7 +996,7 @@ class TimestampNode : public TimestampNodeBase { const IndexEvaluator* index_based_keys() override { - return m_index_evaluator ? &(*m_index_evaluator) : nullptr; + return m_index_evaluator ? &*m_index_evaluator : nullptr; } bool has_search_index() const override @@ -1116,7 +1011,7 @@ class TimestampNode : public TimestampNodeBase { return m_index_evaluator->do_search_index(this->m_cluster, start, end); } } - return m_leaf_ptr->find_first(m_value, start, end); + return m_leaf->find_first(m_value, start, end); } std::string describe(util::serializer::SerialisationState& state) const override @@ -1132,10 +1027,6 @@ class TimestampNode : public TimestampNodeBase { } protected: - TimestampNode(const TimestampNode& from, Transaction* tr) - : TimestampNodeBase(from, tr) - { - } std::optional m_index_evaluator; }; @@ -1157,10 +1048,8 @@ class DecimalNodeBase : public ParentNode { void cluster_changed() override { - m_array_ptr = nullptr; - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayDecimal128(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); } void init(bool will_query_ranges) override @@ -1178,11 +1067,7 @@ class DecimalNodeBase : public ParentNode { } Decimal128 m_value; - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayDecimal128* m_leaf_ptr = nullptr; + std::optional m_leaf; }; template @@ -1195,7 +1080,7 @@ class DecimalNode : public DecimalNodeBase { TConditionFunction cond; bool value_is_null = m_value.is_null(); for (size_t i = start; i < end; i++) { - Decimal128 val = m_leaf_ptr->get(i); + Decimal128 val = m_leaf->get(i); if (cond(val, m_value, val.is_null(), value_is_null)) return i; } @@ -1213,12 +1098,6 @@ class DecimalNode : public DecimalNodeBase { { return std::unique_ptr(new DecimalNode(*this)); } - -protected: - DecimalNode(const DecimalNode& from, Transaction* tr) - : DecimalNodeBase(from, tr) - { - } }; template @@ -1241,10 +1120,8 @@ class FixedBytesNodeBase : public ParentNode { void cluster_changed() override { - m_array_ptr = nullptr; - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayType(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); } void init(bool will_query_ranges) override @@ -1263,12 +1140,8 @@ class FixedBytesNodeBase : public ParentNode { } ObjectType m_value; + std::optional m_leaf; bool m_value_is_null = false; - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayType* m_leaf_ptr = nullptr; }; template @@ -1280,7 +1153,7 @@ class FixedBytesNode : public FixedBytesNodeBase { { TConditionFunction cond; for (size_t i = start; i < end; i++) { - util::Optional val = this->m_leaf_ptr->get(i); + util::Optional val = this->m_leaf->get(i); if (val) { if (cond(*val, this->m_value, false, this->m_value_is_null)) return i; @@ -1306,12 +1179,6 @@ class FixedBytesNode : public FixedBytesNodeBase { { return std::unique_ptr(new FixedBytesNode(*this)); } - -protected: - FixedBytesNode(const FixedBytesNode& from, Transaction* tr) - : FixedBytesNode(from, tr) - { - } }; template @@ -1363,12 +1230,12 @@ class FixedBytesNode : public FixedBytesNodeBasem_leaf_ptr->get(start) == m_optional_value) { + if (this->m_leaf->get(start) == m_optional_value) { s = start; } } else { - s = this->m_leaf_ptr->find_first(m_optional_value, start, end); + s = this->m_leaf->find_first(m_optional_value, start, end); } } @@ -1390,10 +1257,6 @@ class FixedBytesNode : public FixedBytesNodeBase m_optional_value; std::optional m_index_evaluator; }; @@ -1426,10 +1289,8 @@ class MixedNodeBase : public ParentNode { void cluster_changed() override { - m_array_ptr = nullptr; - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayMixed(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); } void init(bool will_query_ranges) override @@ -1479,12 +1340,8 @@ class MixedNodeBase : public ParentNode { QueryValue m_value; OwnedBinaryData m_buffer; + std::optional m_leaf; bool m_value_is_null = false; - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayMixed* m_leaf_ptr = nullptr; }; template @@ -1496,7 +1353,7 @@ class MixedNode : public MixedNodeBase { { TConditionFunction cond; for (size_t i = start; i < end; i++) { - QueryValue val(m_leaf_ptr->get(i)); + QueryValue val(m_leaf->get(i)); if constexpr (realm::is_any_v) { // For some strange reason the parameters are swapped for string conditions @@ -1511,7 +1368,7 @@ class MixedNode : public MixedNodeBase { return realm::npos; } - virtual std::string describe_condition() const override + std::string describe_condition() const override { return TConditionFunction::description(); } @@ -1520,12 +1377,6 @@ class MixedNode : public MixedNodeBase { { return std::unique_ptr(new MixedNode(*this)); } - -protected: - MixedNode(const MixedNode& from, Transaction* tr) - : MixedNode(from, tr) - { - } }; template <> @@ -1564,7 +1415,7 @@ class MixedNode : public MixedNodeBase { size_t find_first_local(size_t start, size_t end) override; - virtual std::string describe_condition() const override + std::string describe_condition() const override { return Equal::description(); } @@ -1619,7 +1470,7 @@ class MixedNode : public MixedNodeBase { return bool(m_index_evaluator); } - virtual std::string describe_condition() const override + std::string describe_condition() const override { return EqualIns::description(); } @@ -1660,15 +1511,8 @@ class StringNodeBase : public ParentNode { void cluster_changed() override { - // Assigning nullptr will cause the Leaf destructor to be called. Must - // be done before assigning a new one. Otherwise the destructor will be - // called after the constructor is called and that is unfortunate if - // the object has the same address. (As in this case) - m_array_ptr = nullptr; - // Create new Leaf - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayString(m_table.unchecked_ptr()->get_alloc())); - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_table.unchecked_ptr()->get_alloc()); + m_cluster->init_leaf(m_condition_column_key, &*m_leaf); } void init(bool will_query_ranges) override @@ -1684,7 +1528,7 @@ class StringNodeBase : public ParentNode { virtual void clear_leaf_state() { - m_array_ptr = nullptr; + m_leaf.reset(); } StringNodeBase(const StringNodeBase& from) @@ -1694,7 +1538,7 @@ class StringNodeBase : public ParentNode { { } - virtual std::string describe(util::serializer::SerialisationState& state) const override + std::string describe(util::serializer::SerialisationState& state) const override { REALM_ASSERT(m_condition_column_key); StringData sd; @@ -1706,13 +1550,8 @@ class StringNodeBase : public ParentNode { } protected: - util::Optional m_value; - - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayString* m_leaf_ptr = nullptr; + std::optional m_value; + std::optional m_leaf; bool m_is_string_enum = false; @@ -1720,9 +1559,9 @@ class StringNodeBase : public ParentNode { size_t m_leaf_start = 0; size_t m_leaf_end = 0; - inline StringData get_string(size_t s) + StringData get_string(size_t s) { - return m_leaf_ptr->get(s); + return m_leaf->get(s); } }; @@ -1763,7 +1602,7 @@ class StringNode : public StringNodeBase { return not_found; } - virtual std::string describe_condition() const override + std::string describe_condition() const override { return TConditionFunction::description(); } @@ -1829,7 +1668,7 @@ class StringNode : public StringNodeBase { return not_found; } - virtual std::string describe_condition() const override + std::string describe_condition() const override { return Contains::description(); } @@ -1910,7 +1749,7 @@ class StringNode : public StringNodeBase { return not_found; } - virtual std::string describe_condition() const override + std::string describe_condition() const override { return ContainsIns::description(); } @@ -1971,7 +1810,7 @@ class StringNodeEqualBase : public StringNodeBase { size_t find_first_local(size_t start, size_t end) override; - virtual std::string describe_condition() const override + std::string describe_condition() const override { return Equal::description(); } @@ -2059,7 +1898,7 @@ class StringNode : public StringNodeEqualBase { void _search_index_init() override; - virtual std::string describe_condition() const override + std::string describe_condition() const override { return EqualIns::description(); } @@ -2104,7 +1943,7 @@ class StringNodeFulltext : public StringNodeEqualBase { return std::unique_ptr(new StringNodeFulltext(*this)); } - virtual std::string describe_condition() const override + std::string describe_condition() const override { return "FULLTEXT"; } @@ -2352,7 +2191,6 @@ class NotNode : public ParentNode { } } - std::unique_ptr clone() const override { return std::unique_ptr(new NotNode(*this)); @@ -2402,10 +2240,9 @@ class TwoColumnsNodeBase : public ParentNode { } } - ~TwoColumnsNodeBase() noexcept override {} void table_changed() override { - if (this->m_table) { + if (m_table) { ParentNode::m_table->check_column(m_condition_column_key1); ParentNode::m_table->check_column(m_condition_column_key2); } @@ -2415,19 +2252,19 @@ class TwoColumnsNodeBase : public ParentNode { const ColKey& col_key); void cluster_changed() override { - if (!m_leaf_ptr1) { - m_leaf_ptr1 = + if (!m_leaf1) { + m_leaf1 = update_cached_leaf_pointers_for_column(m_table.unchecked_ptr()->get_alloc(), m_condition_column_key1); } - if (!m_leaf_ptr2) { - m_leaf_ptr2 = + if (!m_leaf2) { + m_leaf2 = update_cached_leaf_pointers_for_column(m_table.unchecked_ptr()->get_alloc(), m_condition_column_key2); } - this->m_cluster->init_leaf(m_condition_column_key1, m_leaf_ptr1.get()); - this->m_cluster->init_leaf(m_condition_column_key2, m_leaf_ptr2.get()); + m_cluster->init_leaf(m_condition_column_key1, m_leaf1.get()); + m_cluster->init_leaf(m_condition_column_key2, m_leaf2.get()); } - virtual std::string describe(util::serializer::SerialisationState& state) const override + std::string describe(util::serializer::SerialisationState& state) const override { REALM_ASSERT(m_condition_column_key1 && m_condition_column_key2); return state.describe_column(ParentNode::m_table, m_condition_column_key1) + " " + describe_condition() + @@ -2442,10 +2279,10 @@ class TwoColumnsNodeBase : public ParentNode { } protected: - mutable ColKey m_condition_column_key1; - mutable ColKey m_condition_column_key2; - std::unique_ptr m_leaf_ptr1 = nullptr; - std::unique_ptr m_leaf_ptr2 = nullptr; + ColKey m_condition_column_key1; + ColKey m_condition_column_key2; + std::unique_ptr m_leaf1; + std::unique_ptr m_leaf2; }; @@ -2453,13 +2290,12 @@ template class TwoColumnsNode : public TwoColumnsNodeBase { public: using TwoColumnsNodeBase::TwoColumnsNodeBase; - ~TwoColumnsNode() noexcept override {} size_t find_first_local(size_t start, size_t end) override { size_t s = start; while (s < end) { - QueryValue v1(m_leaf_ptr1->get_any(s)); - QueryValue v2(m_leaf_ptr2->get_any(s)); + QueryValue v1(m_leaf1->get_any(s)); + QueryValue v2(m_leaf2->get_any(s)); if (TConditionFunction()(v1, v2)) return s; else @@ -2468,7 +2304,7 @@ class TwoColumnsNode : public TwoColumnsNodeBase { return not_found; } - virtual std::string describe_condition() const override + std::string describe_condition() const override { return TConditionFunction::description(); } @@ -2477,12 +2313,6 @@ class TwoColumnsNode : public TwoColumnsNodeBase { { return std::unique_ptr(new TwoColumnsNode(*this)); } - -protected: - TwoColumnsNode(const TwoColumnsNode& from, Transaction* tr) - : TwoColumnsNode(from, tr) - { - } }; @@ -2498,7 +2328,7 @@ class ExpressionNode : public ParentNode { void cluster_changed() override; void collect_dependencies(std::vector&) const override; - virtual std::string describe(util::serializer::SerialisationState& state) const override; + std::string describe(util::serializer::SerialisationState& state) const override; std::unique_ptr clone() const override; @@ -2528,18 +2358,18 @@ class LinksToNodeBase : public ParentNode { void cluster_changed() override { - m_array_ptr = nullptr; if (m_column_type == col_type_Link) { - m_array_ptr = LeafPtr(new (&m_storage.m_list) ArrayKey(m_table.unchecked_ptr()->get_alloc())); + m_list.emplace(m_table.unchecked_ptr()->get_alloc()); + m_leaf = &*m_list; } else if (m_column_type == col_type_LinkList) { - m_array_ptr = LeafPtr(new (&m_storage.m_linklist) ArrayList(m_table.unchecked_ptr()->get_alloc())); + m_linklist.emplace(m_table.unchecked_ptr()->get_alloc()); + m_leaf = &*m_linklist; } - m_cluster->init_leaf(this->m_condition_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_cluster->init_leaf(this->m_condition_column_key, m_leaf); } - virtual std::string describe(util::serializer::SerialisationState& state) const override + std::string describe(util::serializer::SerialisationState& state) const override { REALM_ASSERT(m_condition_column_key); if (m_target_keys.size() > 1) @@ -2552,14 +2382,9 @@ class LinksToNodeBase : public ParentNode { protected: std::vector m_target_keys; ColumnType m_column_type; - using LeafPtr = std::unique_ptr; - union Storage { - typename std::aligned_storage::type m_list; - typename std::aligned_storage::type m_linklist; - }; - Storage m_storage; - LeafPtr m_array_ptr; - const ArrayPayload* m_leaf_ptr = nullptr; + std::optional m_list; + std::optional m_linklist; + ArrayPayload* m_leaf = nullptr; LinksToNodeBase(const LinksToNodeBase& source) : ParentNode(source) @@ -2567,6 +2392,13 @@ class LinksToNodeBase : public ParentNode { , m_column_type(source.m_column_type) { } + + ref_type get_ref(size_t i) + { + if (m_list) + return m_list->get_as_ref(i); + return m_linklist->get(i); + } }; template diff --git a/src/realm/query_expression.cpp b/src/realm/query_expression.cpp index 83e3842a664..9c4c763c718 100644 --- a/src/realm/query_expression.cpp +++ b/src/realm/query_expression.cpp @@ -108,26 +108,17 @@ bool LinkMap::map_links(size_t column, ObjKey key, LinkMapFunction lm) const return true; } -ref_type LinkMap::get_ref(const ArrayPayload* array_payload, ColumnType type, size_t row) -{ - if (type == col_type_LinkList) - return static_cast(array_payload)->get(row); - return static_cast(array_payload)->get_as_ref(row); -} - void LinkMap::map_links(size_t column, size_t row, LinkMapFunction lm) const { - REALM_ASSERT(m_leaf_ptr != nullptr); - ColumnType type = m_link_types[column]; ColKey column_key = m_link_column_keys[column]; if (type == col_type_Link && !column_key.is_set()) { if (column_key.is_dictionary()) { - auto leaf = static_cast(m_leaf_ptr); - if (leaf->get(row)) { + auto& leaf = mpark::get(m_leaf); + if (leaf.get(row)) { Allocator& alloc = get_base_table()->get_alloc(); Array top(alloc); - top.set_parent(const_cast(leaf), row); + top.set_parent(const_cast(&leaf), row); top.init_from_parent(); BPlusTree values(alloc); values.set_parent(&top, 1); @@ -147,11 +138,19 @@ void LinkMap::map_links(size_t column, size_t row, LinkMapFunction lm) const } else { REALM_ASSERT(!column_key.is_collection()); - map_links(column + 1, static_cast(m_leaf_ptr)->get(row), lm); + map_links(column + 1, mpark::get(m_leaf).get(row), lm); } } else if (type == col_type_LinkList || (type == col_type_Link && column_key.is_set())) { - if (ref_type ref = get_ref(m_leaf_ptr, type, row)) { + ref_type ref; + if (auto list = mpark::get_if(&m_leaf)) { + ref = list->get(row); + } + else { + ref = mpark::get(m_leaf).get_as_ref(row); + } + + if (ref) { BPlusTree links(get_base_table()->get_alloc()); links.init_from_ref(ref); size_t sz = links.size(); @@ -162,10 +161,10 @@ void LinkMap::map_links(size_t column, size_t row, LinkMapFunction lm) const } } else if (type == col_type_BackLink) { - auto back_links = static_cast(m_leaf_ptr); - size_t sz = back_links->get_backlink_count(row); + auto& back_links = mpark::get(m_leaf); + size_t sz = back_links.get_backlink_count(row); for (size_t t = 0; t < sz; t++) { - ObjKey k = back_links->get_backlink(row, t); + ObjKey k = back_links.get_backlink(row, t); if (!map_links(column + 1, k, lm)) break; } @@ -241,16 +240,12 @@ void ColumnDictionaryKey::init_key(Mixed key_value) void ColumnDictionaryKeys::set_cluster(const Cluster* cluster) { - m_leaf_ptr = nullptr; - m_array_ptr = nullptr; if (m_link_map.has_links()) { m_link_map.set_cluster(cluster); } else { - // Create new Leaf - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayInteger(m_link_map.get_base_table()->get_alloc())); - cluster->init_leaf(m_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_link_map.get_base_table()->get_alloc()); + cluster->init_leaf(m_column_key, &*m_leaf); } } @@ -258,7 +253,7 @@ void ColumnDictionaryKeys::set_cluster(const Cluster* cluster) void ColumnDictionaryKeys::evaluate(size_t index, ValueBase& destination) { if (m_link_map.has_links()) { - REALM_ASSERT(m_leaf_ptr == nullptr); + REALM_ASSERT(!m_leaf); std::vector links = m_link_map.get_links(index); auto sz = links.size(); @@ -281,10 +276,10 @@ void ColumnDictionaryKeys::evaluate(size_t index, ValueBase& destination) // Not a link column Allocator& alloc = get_base_table()->get_alloc(); - REALM_ASSERT(m_leaf_ptr != nullptr); - if (m_leaf_ptr->get(index)) { + REALM_ASSERT(m_leaf); + if (m_leaf->get(index)) { Array top(alloc); - top.set_parent(const_cast(m_leaf_ptr), index); + top.set_parent(&*m_leaf, index); top.init_from_parent(); BPlusTree keys(alloc); keys.set_parent(&top, 0); @@ -304,7 +299,7 @@ void ColumnDictionaryKeys::evaluate(size_t index, ValueBase& destination) void ColumnDictionaryKey::evaluate(size_t index, ValueBase& destination) { if (links_exist()) { - REALM_ASSERT(m_leaf_ptr == nullptr); + REALM_ASSERT(!m_leaf); std::vector links = m_link_map.get_links(index); auto sz = links.size(); @@ -332,10 +327,10 @@ void ColumnDictionaryKey::evaluate(size_t index, ValueBase& destination) // Not a link column Allocator& alloc = get_base_table()->get_alloc(); - REALM_ASSERT(m_leaf_ptr != nullptr); - if (m_leaf_ptr->get(index)) { + REALM_ASSERT(m_leaf); + if (m_leaf->get(index)) { Array top(alloc); - top.set_parent(const_cast(m_leaf_ptr), index); + top.set_parent(&*m_leaf, index); top.init_from_parent(); BPlusTree keys(alloc); keys.set_parent(&top, 0); @@ -397,7 +392,7 @@ SizeOperator Columns::size() void Columns::evaluate(size_t index, ValueBase& destination) { if (links_exist()) { - REALM_ASSERT(m_leaf_ptr == nullptr); + REALM_ASSERT(!m_leaf); std::vector links = m_link_map.get_links(index); auto sz = links.size(); @@ -420,10 +415,10 @@ void Columns::evaluate(size_t index, ValueBase& destination) // Not a link column Allocator& alloc = get_base_table()->get_alloc(); - REALM_ASSERT(m_leaf_ptr != nullptr); - if (m_leaf_ptr->get(index)) { + REALM_ASSERT(m_leaf); + if (m_leaf->get(index)) { Array top(alloc); - top.set_parent(const_cast(m_leaf_ptr), index); + top.set_parent(&*m_leaf, index); top.init_from_parent(); BPlusTree values(alloc); values.set_parent(&top, 1); @@ -463,16 +458,12 @@ void Columns::evaluate(size_t index, ValueBase& destination) void ColumnListBase::set_cluster(const Cluster* cluster) { - m_leaf_ptr = nullptr; - m_array_ptr = nullptr; if (m_link_map.has_links()) { m_link_map.set_cluster(cluster); } else { - // Create new Leaf - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) ArrayInteger(m_link_map.get_base_table()->get_alloc())); - cluster->init_leaf(m_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_link_map.get_base_table()->get_alloc()); + cluster->init_leaf(m_column_key, &*m_leaf); } } @@ -501,12 +492,12 @@ void ColumnListBase::get_lists(size_t index, Value& destination, size_t } } else { - size_t rows = std::min(m_leaf_ptr->size() - index, nb_elements); + size_t rows = std::min(m_leaf->size() - index, nb_elements); destination.init(false, rows); for (size_t t = 0; t < rows; t++) { - destination.set(t, m_leaf_ptr->get(index + t)); + destination.set(t, m_leaf->get(index + t)); } } } diff --git a/src/realm/query_expression.hpp b/src/realm/query_expression.hpp index b9e08a0cac6..c3ca7911c50 100644 --- a/src/realm/query_expression.hpp +++ b/src/realm/query_expression.hpp @@ -152,6 +152,8 @@ The Columns class encapsulates all this into a simple class that, for any type T #include #include +#include + #include #include @@ -646,8 +648,7 @@ class ValueBase { class Expression { public: - Expression() {} - virtual ~Expression() {} + virtual ~Expression() = default; virtual double init() { @@ -672,7 +673,7 @@ std::unique_ptr make_expression(Args&&... args) class Subexpr { public: - virtual ~Subexpr() {} + virtual ~Subexpr() = default; virtual std::unique_ptr clone() const = 0; @@ -1534,28 +1535,26 @@ class LinkMap final { void set_cluster(const Cluster* cluster) { Allocator& alloc = get_base_table()->get_alloc(); - m_array_ptr = nullptr; + ArrayPayload* array_ptr; switch (m_link_types[0]) { case col_type_Link: if (m_link_column_keys[0].is_dictionary()) { - m_array_ptr = LeafPtr(new (&m_storage.m_dict) ArrayInteger(alloc)); + array_ptr = &m_leaf.emplace(alloc); } else { - m_array_ptr = LeafPtr(new (&m_storage.m_list) ArrayKey(alloc)); + array_ptr = &m_leaf.emplace(alloc); } break; case col_type_LinkList: - m_array_ptr = LeafPtr(new (&m_storage.m_linklist) ArrayList(alloc)); + array_ptr = &m_leaf.emplace(alloc); break; case col_type_BackLink: - m_array_ptr = LeafPtr(new (&m_storage.m_backlink) ArrayBacklink(alloc)); + array_ptr = &m_leaf.emplace(alloc); break; default: - break; + REALM_UNREACHABLE(); } - // m_tables[0]->report_invalid_key(m_link_column_keys[0]); - cluster->init_leaf(m_link_column_keys[0], m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + cluster->init_leaf(m_link_column_keys[0], array_ptr); } void collect_dependencies(std::vector& tables) const; @@ -1629,8 +1628,6 @@ class LinkMap final { return !m_link_column_keys.empty(); } - static ref_type get_ref(const ArrayPayload* array_payload, ColumnType type, size_t ndx); - private: bool map_links(size_t column, ObjKey key, LinkMapFunction lm) const; void map_links(size_t column, size_t row, LinkMapFunction lm) const; @@ -1647,17 +1644,8 @@ class LinkMap final { std::vector m_link_types; std::vector m_tables; bool m_only_unary_links = true; - // Leaf cache - using LeafPtr = std::unique_ptr; - union Storage { - typename std::aligned_storage::type m_list; - typename std::aligned_storage::type m_dict; - typename std::aligned_storage::type m_linklist; - typename std::aligned_storage::type m_backlink; - }; - Storage m_storage; - LeafPtr m_array_ptr; - const ArrayPayload* m_leaf_ptr = nullptr; + + mpark::variant m_leaf; template friend Query compare(const Subexpr2&, const Obj&); @@ -1838,23 +1826,19 @@ class SimpleQuerySupport : public ObjPropertyExpr { void set_cluster(const Cluster* cluster) override { - m_array_ptr = nullptr; - m_leaf_ptr = nullptr; if (links_exist()) { m_link_map.set_cluster(cluster); } else { - // Create new Leaf - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(m_link_map.get_base_table()->get_alloc())); - cluster->init_leaf(m_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + m_leaf.emplace(m_link_map.get_base_table()->get_alloc()); + cluster->init_leaf(m_column_key, &*m_leaf); } } void evaluate(size_t index, ValueBase& destination) override { if (links_exist()) { - REALM_ASSERT(m_leaf_ptr == nullptr); + REALM_ASSERT(!m_leaf); if (m_link_map.only_unary_links()) { REALM_ASSERT(destination.size() == 1); @@ -1899,14 +1883,14 @@ class SimpleQuerySupport : public ObjPropertyExpr { } else { // Not a link column - REALM_ASSERT(m_leaf_ptr != nullptr); + REALM_ASSERT(m_leaf); REALM_ASSERT(destination.size() == 1); REALM_ASSERT(!destination.m_from_list); - if (m_leaf_ptr->is_null(index)) { + if (m_leaf->is_null(index)) { destination.set_null(0); } else { - destination.set(0, m_leaf_ptr->get(index)); + destination.set(0, m_leaf->get(index)); } } } @@ -1936,13 +1920,8 @@ class SimpleQuerySupport : public ObjPropertyExpr { using ObjPropertyExpr::m_link_map; using ObjPropertyExpr::m_column_key; - // Leaf cache using LeafType = typename ColumnTypeTraits::cluster_leaf_type; - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - LeafType* m_leaf_ptr = nullptr; + std::optional m_leaf; }; template <> @@ -2195,7 +2174,7 @@ class UnaryLinkCompare : public Expression { return not_found; } - virtual std::string description(util::serializer::SerialisationState& state) const override + std::string description(util::serializer::SerialisationState& state) const override { return state.describe_columns(m_link_map, ColKey()) + (has_links ? " != NULL" : " == NULL"); } @@ -2258,7 +2237,7 @@ class LinkCount : public Subexpr2 { destination = Value(count); } - virtual std::string description(util::serializer::SerialisationState& state) const override + std::string description(util::serializer::SerialisationState& state) const override { return state.describe_columns(m_link_map, ColKey()) + util::serializer::value_separator + "@count"; } @@ -2335,7 +2314,7 @@ class BacklinkCount : public Subexpr2 { destination = Value(count); } - virtual std::string description(util::serializer::SerialisationState& state) const override + std::string description(util::serializer::SerialisationState& state) const override { std::string s; if (m_link_map.links_exist()) { @@ -2456,7 +2435,7 @@ class GeoWithinCompare : public Expression { return not_found; } - virtual std::string description(util::serializer::SerialisationState& state) const override + std::string description(util::serializer::SerialisationState& state) const override { return state.describe_expression_type(m_comp_type) + state.describe_columns(m_link_map, ColKey()) + " GEOWITHIN " + util::serializer::print_value(m_bounds); @@ -2638,7 +2617,7 @@ class KeyValue : public Subexpr2 { destination = Value(m_key); } - virtual std::string description(util::serializer::SerialisationState&) const override + std::string description(util::serializer::SerialisationState&) const override { return util::serializer::print_value(m_key); } @@ -2846,13 +2825,8 @@ class ColumnListBase { mutable ColKey m_column_key; LinkMap m_link_map; - // Leaf cache - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - ArrayInteger* m_leaf_ptr = nullptr; - util::Optional m_comparison_type; + std::optional m_leaf; + std::optional m_comparison_type; }; template @@ -3239,15 +3213,8 @@ class ColumnDictionaryKeys : public Subexpr2 { DataType m_key_type; ColKey m_column_key; LinkMap m_link_map; - util::Optional m_comparison_type; - - - // Leaf cache - using LeafCacheStorage = typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - ArrayInteger* m_leaf_ptr = nullptr; + std::optional m_comparison_type; + std::optional m_leaf; }; template @@ -3461,7 +3428,7 @@ class CollectionColumnAggregate : public Subexpr2get(index)) { + if (auto ref = m_columns_collection.m_leaf->get(index)) { Allocator& alloc = m_columns_collection.get_base_table()->get_alloc(); Dictionary dict(alloc, m_columns_collection.m_column_key, to_ref(ref)); destination.set(0, do_dictionary_agg(dict)); @@ -3505,7 +3472,7 @@ class CollectionColumnAggregate : public Subexpr2 { void set_cluster(const Cluster* cluster) override { - m_array_ptr = nullptr; - m_leaf_ptr = nullptr; if (links_exist()) { m_link_map.set_cluster(cluster); + m_leaf = mpark::monostate(); } else if (requires_null_column && is_nullable()) { - // Create new Leaf - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) NullableLeafType(this->get_base_table()->get_alloc())); - cluster->init_leaf(m_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + auto& leaf = m_leaf.template emplace(this->get_base_table()->get_alloc()); + cluster->init_leaf(m_column_key, &leaf); } else { - // Create new Leaf - m_array_ptr = LeafPtr(new (&m_leaf_cache_storage) LeafType(this->get_base_table()->get_alloc())); - cluster->init_leaf(m_column_key, m_array_ptr.get()); - m_leaf_ptr = m_array_ptr.get(); + auto& leaf = m_leaf.template emplace(this->get_base_table()->get_alloc()); + cluster->init_leaf(m_column_key, &leaf); } } @@ -3648,7 +3610,7 @@ class Columns : public ObjPropertyExpr { using U = typename LeafType2::value_type; if (links_exist()) { - REALM_ASSERT(m_leaf_ptr == nullptr); + REALM_ASSERT(mpark::holds_alternative(m_leaf)); if (m_link_map.only_unary_links()) { destination.init(false, 1); destination.set_null(0); @@ -3673,8 +3635,8 @@ class Columns : public ObjPropertyExpr { } } else { - REALM_ASSERT(m_leaf_ptr != nullptr); - auto leaf = static_cast(m_leaf_ptr); + auto leaf = mpark::get_if(&m_leaf); + REALM_ASSERT(leaf); // Not a Link column size_t colsize = leaf->size(); @@ -3710,7 +3672,7 @@ class Columns : public ObjPropertyExpr { } } - virtual std::string description(util::serializer::SerialisationState& state) const override + std::string description(util::serializer::SerialisationState& state) const override { return state.describe_expression_type(this->m_comparison_type) + state.describe_columns(m_link_map, m_column_key); @@ -3743,14 +3705,10 @@ class Columns : public ObjPropertyExpr { private: using ObjPropertyExpr::m_link_map; using ObjPropertyExpr::m_column_key; - - // Leaf cache - using LeafCacheStorage = - typename std::aligned_storage::type; - using LeafPtr = std::unique_ptr; - LeafCacheStorage m_leaf_cache_storage; - LeafPtr m_array_ptr; - const ArrayPayload* m_leaf_ptr = nullptr; + using LeafStorage = + std::conditional_t, + mpark::variant>; + LeafStorage m_leaf; }; template @@ -3806,7 +3764,7 @@ class SubColumns : public Subexpr, public SubColumnBase { REALM_ASSERT(false); } - virtual std::string description(util::serializer::SerialisationState&) const override + std::string description(util::serializer::SerialisationState&) const override { return ""; // by itself there are no conditions, see SubColumnAggregate } @@ -3935,7 +3893,7 @@ class SubColumnAggregate : public Subexpr2 { } } - virtual std::string description(util::serializer::SerialisationState& state) const override + std::string description(util::serializer::SerialisationState& state) const override { util::serializer::SerialisationState empty_state(state.group); return state.describe_columns(m_link_map, ColKey()) + util::serializer::value_separator + @@ -3995,7 +3953,7 @@ class SubQueryCount : public Subexpr2 { destination = Value(count); } - virtual std::string description(util::serializer::SerialisationState& state) const override + std::string description(util::serializer::SerialisationState& state) const override { REALM_ASSERT(m_link_map.get_base_table() != nullptr); std::string target = state.describe_columns(m_link_map, ColKey()); diff --git a/src/realm/table.cpp b/src/realm/table.cpp index fdc5e08b74c..9c5eff2639b 100644 --- a/src/realm/table.cpp +++ b/src/realm/table.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/src/realm/utilities.hpp b/src/realm/utilities.hpp index 2358735fca1..5875bff7698 100644 --- a/src/realm/utilities.hpp +++ b/src/realm/utilities.hpp @@ -361,31 +361,6 @@ constexpr inline size_t round_down(size_t p, size_t align) } -template -struct Wrap { - Wrap(const T& v) - : m_value(v) - { - } - operator T() const - { - return m_value; - } - -private: - T m_value; -}; - -// PlacementDelete is intended for use with std::unique_ptr when it holds an object allocated with -// placement new. It simply calls the object's destructor without freeing the memory. -struct PlacementDelete { - template - void operator()(T* v) const - { - v->~T(); - } -}; - #ifdef _WIN32 typedef HANDLE FileDesc; #else diff --git a/test/object-store/benchmarks/object.cpp b/test/object-store/benchmarks/object.cpp index 5c79bec4c65..834991ca98c 100644 --- a/test/object-store/benchmarks/object.cpp +++ b/test/object-store/benchmarks/object.cpp @@ -32,7 +32,6 @@ #include #include -#include #include #include diff --git a/test/object-store/benchmarks/results.cpp b/test/object-store/benchmarks/results.cpp index 3c5cc0dc1de..d40398133e8 100644 --- a/test/object-store/benchmarks/results.cpp +++ b/test/object-store/benchmarks/results.cpp @@ -29,7 +29,6 @@ #include #include -#include #include using namespace realm; diff --git a/test/object-store/dictionary.cpp b/test/object-store/dictionary.cpp index 3cfe681b180..42a38982292 100644 --- a/test/object-store/dictionary.cpp +++ b/test/object-store/dictionary.cpp @@ -33,9 +33,6 @@ #include #include -#include -#include - using namespace realm; using namespace realm::util; diff --git a/test/object-store/results.cpp b/test/object-store/results.cpp index f52dc725bd1..cfe6b8ef532 100644 --- a/test/object-store/results.cpp +++ b/test/object-store/results.cpp @@ -36,7 +36,6 @@ #include #include -#include #include #if REALM_ENABLE_SYNC