123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- #ifndef REALM_INDEX_STRING_HPP
- #define REALM_INDEX_STRING_HPP
- #include <cstring>
- #include <memory>
- #include <array>
- #include <realm/array.hpp>
- #include <realm/table_cluster_tree.hpp>
- namespace realm {
- class Spec;
- class Timestamp;
- class ClusterColumn;
- template <class T>
- class BPlusTree;
- class IndexArray : public Array {
- public:
- IndexArray(Allocator& allocator)
- : Array(allocator)
- {
- }
- ObjKey index_string_find_first(Mixed value, const ClusterColumn& column) const;
- void index_string_find_all(std::vector<ObjKey>& result, Mixed value, const ClusterColumn& column,
- bool case_insensitive = false) const;
- FindRes index_string_find_all_no_copy(Mixed value, const ClusterColumn& column, InternalFindResult& result) const;
- size_t index_string_count(Mixed value, const ClusterColumn& column) const;
- private:
- template <IndexMethod>
- int64_t from_list(Mixed value, InternalFindResult& result_ref, const IntegerColumn& key_values,
- const ClusterColumn& column) const;
- void from_list_all(Mixed value, std::vector<ObjKey>& result, const IntegerColumn& rows,
- const ClusterColumn& column) const;
- void from_list_all_ins(StringData value, std::vector<ObjKey>& result, const IntegerColumn& rows,
- const ClusterColumn& column) const;
- template <IndexMethod method>
- int64_t index_string(Mixed value, InternalFindResult& result_ref, const ClusterColumn& column) const;
- void index_string_all(Mixed value, std::vector<ObjKey>& result, const ClusterColumn& column) const;
- void index_string_all_ins(StringData value, std::vector<ObjKey>& result, const ClusterColumn& column) const;
- };
- constexpr size_t string_conversion_buffer_size = 16;
- using StringConversionBuffer = std::array<char, string_conversion_buffer_size>;
- static_assert(sizeof(UUID::UUIDBytes) <= string_conversion_buffer_size,
- "if you change the size of a UUID then also change the string index buffer space");
- class ClusterColumn {
- public:
- ClusterColumn(const TableClusterTree* cluster_tree, ColKey column_key)
- : m_cluster_tree(cluster_tree)
- , m_column_key(column_key)
- {
- }
- size_t size() const
- {
- return m_cluster_tree->size();
- }
- TableClusterTree::Iterator begin() const
- {
- return TableClusterTree::Iterator(*m_cluster_tree, 0);
- }
- TableClusterTree::Iterator end() const
- {
- return TableClusterTree::Iterator(*m_cluster_tree, size());
- }
- DataType get_data_type() const;
- ColKey get_column_key() const
- {
- return m_column_key;
- }
- bool is_nullable() const;
- Mixed get_value(ObjKey key) const;
- private:
- const TableClusterTree* m_cluster_tree;
- ColKey m_column_key;
- };
- class StringIndex {
- public:
- StringIndex(const ClusterColumn& target_column, Allocator&);
- StringIndex(ref_type, ArrayParent*, size_t ndx_in_parent, const ClusterColumn& target_column, Allocator&);
- ~StringIndex() noexcept
- {
- }
- ColKey get_column_key() const
- {
- return m_target_column.get_column_key();
- }
- static bool type_supported(realm::DataType type)
- {
- return (type == type_Int || type == type_String || type == type_Bool || type == type_Timestamp ||
- type == type_ObjectId || type == type_Mixed || type == type_UUID);
- }
- static ref_type create_empty(Allocator& alloc);
- void set_target(const ClusterColumn& target_column) noexcept;
-
- Allocator& get_alloc() const noexcept;
- void destroy() noexcept;
- void detach();
- bool is_attached() const noexcept;
- void set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept;
- size_t get_ndx_in_parent() const noexcept;
- void set_ndx_in_parent(size_t ndx_in_parent) noexcept;
- void update_from_parent() noexcept;
- void refresh_accessor_tree(const ClusterColumn& target_column);
- ref_type get_ref() const noexcept;
-
- bool is_empty() const;
- template <class T>
- void insert(ObjKey key, T value);
- template <class T>
- void insert(ObjKey key, util::Optional<T> value);
- template <class T>
- void set(ObjKey key, T new_value);
- template <class T>
- void set(ObjKey key, util::Optional<T> new_value);
- void erase(ObjKey key);
- template <class T>
- ObjKey find_first(T value) const;
- template <class T>
- void find_all(std::vector<ObjKey>& result, T value, bool case_insensitive = false) const;
- template <class T>
- FindRes find_all_no_copy(T value, InternalFindResult& result) const;
- template <class T>
- size_t count(T value) const;
- void clear();
- bool has_duplicate_values() const noexcept;
- void verify() const;
- #ifdef REALM_DEBUG
- template <class T>
- void verify_entries(const ClusterColumn& column) const;
- void do_dump_node_structure(std::ostream&, int) const;
- #endif
- typedef int32_t key_type;
-
-
-
-
-
-
-
- static const size_t s_max_offset = 200;
- static const size_t s_index_key_length = 4;
- static key_type create_key(StringData) noexcept;
- static key_type create_key(StringData, size_t) noexcept;
- private:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- std::unique_ptr<IndexArray> m_array;
- ClusterColumn m_target_column;
- struct inner_node_tag {
- };
- StringIndex(inner_node_tag, Allocator&);
- static IndexArray* create_node(Allocator&, bool is_leaf);
- void insert_with_offset(ObjKey key, StringData index_data, const Mixed& value, size_t offset);
- void insert_row_list(size_t ref, size_t offset, StringData value);
- void insert_to_existing_list(ObjKey key, Mixed value, IntegerColumn& list);
- void insert_to_existing_list_at_lower(ObjKey key, Mixed value, IntegerColumn& list,
- const IntegerColumnIterator& lower);
- key_type get_last_key() const;
- struct NodeChange {
- size_t ref1;
- size_t ref2;
- enum ChangeType { change_None, change_InsertBefore, change_InsertAfter, change_Split } type;
- NodeChange(ChangeType t, size_t r1 = 0, size_t r2 = 0)
- : ref1(r1)
- , ref2(r2)
- , type(t)
- {
- }
- NodeChange()
- : ref1(0)
- , ref2(0)
- , type(change_None)
- {
- }
- };
-
- void TreeInsert(ObjKey obj_key, key_type, size_t offset, StringData index_data, const Mixed& value);
- NodeChange do_insert(ObjKey, key_type, size_t offset, StringData index_data, const Mixed& value);
-
- bool leaf_insert(ObjKey obj_key, key_type, size_t offset, StringData index_data, const Mixed& value,
- bool noextend = false);
- void node_insert_split(size_t ndx, size_t new_ref);
- void node_insert(size_t ndx, size_t ref);
- void do_delete(ObjKey key, StringData, size_t offset);
- Mixed get(ObjKey key) const;
- void node_add_key(ref_type ref);
- #ifdef REALM_DEBUG
- static void dump_node_structure(const Array& node, std::ostream&, int level);
- #endif
- };
- class SortedListComparator {
- public:
- SortedListComparator(const TableClusterTree* cluster_tree, ColKey column_key)
- : m_column(cluster_tree, column_key)
- {
- }
- SortedListComparator(const ClusterColumn& column)
- : m_column(column)
- {
- }
- bool operator()(int64_t key_value, Mixed needle);
- bool operator()(Mixed needle, int64_t key_value);
- private:
- const ClusterColumn m_column;
- };
- inline StringIndex::StringIndex(const ClusterColumn& target_column, Allocator& alloc)
- : m_array(create_node(alloc, true))
- , m_target_column(target_column)
- {
- }
- inline StringIndex::StringIndex(ref_type ref, ArrayParent* parent, size_t ndx_in_parent,
- const ClusterColumn& target_column, Allocator& alloc)
- : m_array(new IndexArray(alloc))
- , m_target_column(target_column)
- {
- REALM_ASSERT_EX(Array::get_context_flag_from_header(alloc.translate(ref)), ref, size_t(alloc.translate(ref)));
- m_array->init_from_ref(ref);
- set_parent(parent, ndx_in_parent);
- }
- inline StringIndex::StringIndex(inner_node_tag, Allocator& alloc)
- : m_array(create_node(alloc, false))
- , m_target_column(ClusterColumn(nullptr, {}))
- {
- }
- inline StringIndex::key_type StringIndex::create_key(StringData str) noexcept
- {
- key_type key = 0;
- if (str.size() >= 4)
- goto four;
- if (str.size() < 2) {
- if (str.size() == 0)
- goto none;
- goto one;
- }
- if (str.size() == 2)
- goto two;
- goto three;
- four:
- key |= (key_type(static_cast<unsigned char>(str[3])) << 0);
- three:
- key |= (key_type(static_cast<unsigned char>(str[2])) << 8);
- two:
- key |= (key_type(static_cast<unsigned char>(str[1])) << 16);
- one:
- key |= (key_type(static_cast<unsigned char>(str[0])) << 24);
- none:
- return key;
- }
- inline StringIndex::key_type StringIndex::create_key(StringData str, size_t offset) noexcept
- {
- if (str.is_null())
- return 0;
- if (offset > str.size())
- return 0;
-
- size_t tail = str.size() - offset;
- if (tail <= sizeof(key_type) - 1) {
- char buf[sizeof(key_type)];
- memset(buf, 0, sizeof(key_type));
- buf[tail] = 'X';
- memcpy(buf, str.data() + offset, tail);
- return create_key(StringData(buf, tail + 1));
- }
-
- return create_key(str.substr(offset));
- }
- template <class T>
- void StringIndex::insert(ObjKey key, T value)
- {
- StringConversionBuffer buffer;
- Mixed m(value);
- size_t offset = 0;
- insert_with_offset(key, m.get_index_data(buffer), m, offset);
- }
- template <class T>
- void StringIndex::insert(ObjKey key, util::Optional<T> value)
- {
- if (value) {
- insert(key, *value);
- }
- else {
- insert(key, null{});
- }
- }
- template <class T>
- void StringIndex::set(ObjKey key, T new_value)
- {
- Mixed old_value = get(key);
- Mixed new_value2 = Mixed(new_value);
-
- if (REALM_LIKELY(new_value2 != old_value)) {
-
-
- erase(key);
- StringConversionBuffer buffer;
- size_t offset = 0;
- auto index_data = new_value2.get_index_data(buffer);
- insert_with_offset(key, index_data, new_value2, offset);
- }
- }
- template <class T>
- void StringIndex::set(ObjKey key, util::Optional<T> new_value)
- {
- if (new_value) {
- set(key, *new_value);
- }
- else {
- set(key, null{});
- }
- }
- template <class T>
- ObjKey StringIndex::find_first(T value) const
- {
-
- return m_array->index_string_find_first(Mixed(value), m_target_column);
- }
- template <class T>
- void StringIndex::find_all(std::vector<ObjKey>& result, T value, bool case_insensitive) const
- {
-
- return m_array->index_string_find_all(result, Mixed(value), m_target_column, case_insensitive);
- }
- template <class T>
- FindRes StringIndex::find_all_no_copy(T value, InternalFindResult& result) const
- {
- return m_array->index_string_find_all_no_copy(Mixed(value), m_target_column, result);
- }
- template <class T>
- size_t StringIndex::count(T value) const
- {
-
- return m_array->index_string_count(Mixed(value), m_target_column);
- }
- inline void StringIndex::destroy() noexcept
- {
- return m_array->destroy_deep();
- }
- inline bool StringIndex::is_attached() const noexcept
- {
- return m_array->is_attached();
- }
- inline void StringIndex::refresh_accessor_tree(const ClusterColumn& target_column)
- {
- m_array->init_from_parent();
- m_target_column = target_column;
- }
- inline ref_type StringIndex::get_ref() const noexcept
- {
- return m_array->get_ref();
- }
- inline void StringIndex::set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept
- {
- m_array->set_parent(parent, ndx_in_parent);
- }
- inline size_t StringIndex::get_ndx_in_parent() const noexcept
- {
- return m_array->get_ndx_in_parent();
- }
- inline void StringIndex::set_ndx_in_parent(size_t ndx_in_parent) noexcept
- {
- m_array->set_ndx_in_parent(ndx_in_parent);
- }
- inline void StringIndex::update_from_parent() noexcept
- {
- m_array->update_from_parent();
- }
- }
- #endif
|