dictionary.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*************************************************************************
  2. *
  3. * Copyright 2019 Realm Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_DICTIONARY_HPP
  19. #define REALM_DICTIONARY_HPP
  20. #include <realm/collection.hpp>
  21. #include <realm/obj.hpp>
  22. #include <realm/mixed.hpp>
  23. #include <realm/array_mixed.hpp>
  24. namespace realm {
  25. class Dictionary final : public CollectionBaseImpl<CollectionBase> {
  26. public:
  27. using Base = CollectionBaseImpl<CollectionBase>;
  28. class Iterator;
  29. Dictionary() {}
  30. ~Dictionary();
  31. Dictionary(const Obj& obj, ColKey col_key);
  32. Dictionary(const Dictionary& other)
  33. : Base(static_cast<const Base&>(other))
  34. , m_key_type(other.m_key_type)
  35. {
  36. *this = other;
  37. }
  38. Dictionary& operator=(const Dictionary& other);
  39. DataType get_key_data_type() const;
  40. DataType get_value_data_type() const;
  41. std::pair<Mixed, Mixed> get_pair(size_t ndx) const;
  42. Mixed get_key(size_t ndx) const;
  43. // Overriding members of CollectionBase:
  44. std::unique_ptr<CollectionBase> clone_collection() const final;
  45. size_t size() const final;
  46. bool is_null(size_t ndx) const final;
  47. Mixed get_any(size_t ndx) const final;
  48. size_t find_any(Mixed value) const final;
  49. size_t find_any_key(Mixed value) const noexcept;
  50. util::Optional<Mixed> min(size_t* return_ndx = nullptr) const final;
  51. util::Optional<Mixed> max(size_t* return_ndx = nullptr) const final;
  52. util::Optional<Mixed> sum(size_t* return_cnt = nullptr) const final;
  53. util::Optional<Mixed> avg(size_t* return_cnt = nullptr) const final;
  54. void sort(std::vector<size_t>& indices, bool ascending = true) const final;
  55. void distinct(std::vector<size_t>& indices, util::Optional<bool> sort_order = util::none) const final;
  56. void sort_keys(std::vector<size_t>& indices, bool ascending = true) const;
  57. void distinct_keys(std::vector<size_t>& indices, util::Optional<bool> sort_order = util::none) const;
  58. // first points to inserted/updated element.
  59. // second is true if the element was inserted
  60. std::pair<Iterator, bool> insert(Mixed key, Mixed value);
  61. std::pair<Iterator, bool> insert(Mixed key, const Obj& obj);
  62. Obj create_and_insert_linked_object(Mixed key);
  63. // throws std::out_of_range if key is not found
  64. Mixed get(Mixed key) const;
  65. // Noexcept version
  66. util::Optional<Mixed> try_get(Mixed key) const noexcept;
  67. // adds entry if key is not found
  68. const Mixed operator[](Mixed key);
  69. Obj get_object(StringData key);
  70. bool contains(Mixed key) const noexcept;
  71. Iterator find(Mixed key) const noexcept;
  72. void erase(Mixed key);
  73. Iterator erase(Iterator it);
  74. bool try_erase(Mixed key);
  75. void nullify(Mixed);
  76. void remove_backlinks(CascadeState& state) const;
  77. void clear() final;
  78. template <class T>
  79. void for_all_values(T&& f)
  80. {
  81. if (update()) {
  82. BPlusTree<Mixed> values(m_obj.get_alloc());
  83. values.init_from_ref(m_dictionary_top->get_as_ref(1));
  84. auto func = [&f](BPlusTreeNode* node, size_t) {
  85. auto leaf = static_cast<BPlusTree<Mixed>::LeafNode*>(node);
  86. size_t sz = leaf->size();
  87. for (size_t i = 0; i < sz; i++) {
  88. f(leaf->get(i));
  89. }
  90. return IteratorControl::AdvanceToNext;
  91. };
  92. values.traverse(func);
  93. }
  94. }
  95. template <class T, class Func>
  96. void for_all_keys(Func&& f)
  97. {
  98. if (update()) {
  99. BPlusTree<T> keys(m_obj.get_alloc());
  100. keys.init_from_ref(m_dictionary_top->get_as_ref(0));
  101. auto func = [&f](BPlusTreeNode* node, size_t) {
  102. auto leaf = static_cast<typename BPlusTree<T>::LeafNode*>(node);
  103. size_t sz = leaf->size();
  104. for (size_t i = 0; i < sz; i++) {
  105. f(leaf->get(i));
  106. }
  107. return IteratorControl::AdvanceToNext;
  108. };
  109. keys.traverse(func);
  110. }
  111. }
  112. Iterator begin() const;
  113. Iterator end() const;
  114. void migrate();
  115. private:
  116. template <typename T, typename Op>
  117. friend class CollectionColumnAggregate;
  118. friend class DictionaryLinkValues;
  119. friend class Cluster;
  120. friend void Obj::assign_pk_and_backlinks(Obj& other);
  121. mutable std::unique_ptr<Array> m_dictionary_top;
  122. mutable std::unique_ptr<BPlusTreeBase> m_keys;
  123. mutable std::unique_ptr<BPlusTree<Mixed>> m_values;
  124. DataType m_key_type = type_String;
  125. Dictionary(Allocator& alloc, ColKey col_key, ref_type ref);
  126. bool init_from_parent(bool allow_create) const;
  127. Mixed do_get(size_t ndx) const;
  128. void do_erase(size_t ndx, Mixed key);
  129. Mixed do_get_key(size_t ndx) const;
  130. size_t do_find_key(Mixed key) const noexcept;
  131. std::pair<size_t, Mixed> find_impl(Mixed key) const noexcept;
  132. std::pair<Mixed, Mixed> do_get_pair(size_t ndx) const;
  133. bool clear_backlink(Mixed value, CascadeState& state) const;
  134. void align_indices(std::vector<size_t>& indices) const;
  135. void swap_content(Array& fields1, Array& fields2, size_t index1, size_t index2);
  136. util::Optional<Mixed> do_min(size_t* return_ndx = nullptr) const;
  137. util::Optional<Mixed> do_max(size_t* return_ndx = nullptr) const;
  138. util::Optional<Mixed> do_sum(size_t* return_cnt = nullptr) const;
  139. util::Optional<Mixed> do_avg(size_t* return_cnt = nullptr) const;
  140. Mixed find_value(Mixed) const noexcept;
  141. template <typename AggregateType>
  142. void do_accumulate(size_t* return_ndx, AggregateType& agg) const;
  143. UpdateStatus update_if_needed() const final;
  144. UpdateStatus ensure_created() final;
  145. inline bool update() const
  146. {
  147. return update_if_needed() != UpdateStatus::Detached;
  148. }
  149. void verify() const;
  150. };
  151. class Dictionary::Iterator {
  152. public:
  153. using iterator_category = std::random_access_iterator_tag;
  154. using value_type = std::pair<Mixed, Mixed>;
  155. using difference_type = ptrdiff_t;
  156. using pointer = const value_type*;
  157. using reference = const value_type&;
  158. pointer operator->() const
  159. {
  160. m_val = m_list->get_pair(m_ndx);
  161. return &m_val;
  162. }
  163. reference operator*() const
  164. {
  165. return *operator->();
  166. }
  167. Iterator& operator++() noexcept
  168. {
  169. ++m_ndx;
  170. return *this;
  171. }
  172. Iterator operator++(int) noexcept
  173. {
  174. auto tmp = *this;
  175. operator++();
  176. return tmp;
  177. }
  178. Iterator& operator--() noexcept
  179. {
  180. --m_ndx;
  181. return *this;
  182. }
  183. Iterator operator--(int) noexcept
  184. {
  185. auto tmp = *this;
  186. operator--();
  187. return tmp;
  188. }
  189. Iterator& operator+=(ptrdiff_t n) noexcept
  190. {
  191. m_ndx += n;
  192. return *this;
  193. }
  194. Iterator& operator-=(ptrdiff_t n) noexcept
  195. {
  196. m_ndx -= n;
  197. return *this;
  198. }
  199. friend ptrdiff_t operator-(const Iterator& lhs, const Iterator& rhs) noexcept
  200. {
  201. return ptrdiff_t(lhs.m_ndx) - ptrdiff_t(rhs.m_ndx);
  202. }
  203. friend Iterator operator+(Iterator lhs, ptrdiff_t rhs) noexcept
  204. {
  205. lhs.m_ndx += rhs;
  206. return lhs;
  207. }
  208. friend Iterator operator+(ptrdiff_t lhs, Iterator rhs) noexcept
  209. {
  210. return rhs + lhs;
  211. }
  212. bool operator!=(const Iterator& rhs) const noexcept
  213. {
  214. REALM_ASSERT_DEBUG(m_list == rhs.m_list);
  215. return m_ndx != rhs.m_ndx;
  216. }
  217. bool operator==(const Iterator& rhs) const noexcept
  218. {
  219. REALM_ASSERT_DEBUG(m_list == rhs.m_list);
  220. return m_ndx == rhs.m_ndx;
  221. }
  222. size_t index() const noexcept
  223. {
  224. return m_ndx;
  225. }
  226. private:
  227. Iterator(const Dictionary* l, size_t ndx) noexcept
  228. : m_list(l)
  229. , m_ndx(ndx)
  230. {
  231. }
  232. friend class Dictionary;
  233. mutable value_type m_val;
  234. const Dictionary* m_list;
  235. size_t m_ndx = size_t(-1);
  236. };
  237. // An interface used when the value type of the dictionary consists of
  238. // links to a single table. Implementation of the ObjList interface on
  239. // top of a Dictionary of objects. This is the dictionary equivilent of
  240. // LnkLst and LnkSet.
  241. class DictionaryLinkValues final : public ObjCollectionBase<CollectionBase> {
  242. public:
  243. DictionaryLinkValues() = default;
  244. DictionaryLinkValues(const Obj& obj, ColKey col_key);
  245. DictionaryLinkValues(const Dictionary& source);
  246. // Overrides of ObjList:
  247. ObjKey get_key(size_t ndx) const final;
  248. Obj get_object(size_t row_ndx) const final;
  249. // Overrides of CollectionBase, these simply forward to the underlying dictionary.
  250. size_t size() const final
  251. {
  252. return m_source.size();
  253. }
  254. bool is_null(size_t ndx) const final
  255. {
  256. return m_source.is_null(ndx);
  257. }
  258. Mixed get_any(size_t ndx) const final
  259. {
  260. return m_source.get_any(ndx);
  261. }
  262. void clear() final
  263. {
  264. m_source.clear();
  265. }
  266. util::Optional<Mixed> min(size_t* return_ndx = nullptr) const final
  267. {
  268. return m_source.min(return_ndx);
  269. }
  270. util::Optional<Mixed> max(size_t* return_ndx = nullptr) const final
  271. {
  272. return m_source.max(return_ndx);
  273. }
  274. util::Optional<Mixed> sum(size_t* return_cnt = nullptr) const final
  275. {
  276. return m_source.sum(return_cnt);
  277. }
  278. util::Optional<Mixed> avg(size_t* return_cnt = nullptr) const final
  279. {
  280. return m_source.avg(return_cnt);
  281. }
  282. std::unique_ptr<CollectionBase> clone_collection() const final
  283. {
  284. return std::make_unique<DictionaryLinkValues>(m_source);
  285. }
  286. LinkCollectionPtr clone_obj_list() const final
  287. {
  288. return std::make_unique<DictionaryLinkValues>(m_source);
  289. }
  290. void sort(std::vector<size_t>& indices, bool ascending = true) const final
  291. {
  292. m_source.sort(indices, ascending);
  293. }
  294. void distinct(std::vector<size_t>& indices, util::Optional<bool> sort_order = util::none) const final
  295. {
  296. m_source.distinct(indices, sort_order);
  297. }
  298. size_t find_any(Mixed value) const final
  299. {
  300. return m_source.find_any(value);
  301. }
  302. const Obj& get_obj() const noexcept final
  303. {
  304. return m_source.get_obj();
  305. }
  306. ColKey get_col_key() const noexcept final
  307. {
  308. return m_source.get_col_key();
  309. }
  310. bool has_changed() const final
  311. {
  312. return m_source.has_changed();
  313. }
  314. // Overrides of ObjCollectionBase:
  315. UpdateStatus do_update_if_needed() const final
  316. {
  317. return m_source.update_if_needed();
  318. }
  319. BPlusTree<ObjKey>* get_mutable_tree() const
  320. {
  321. // We are faking being an ObjList because the underlying storage is not
  322. // actually a BPlusTree<ObjKey> for dictionaries it is all mixed values.
  323. // But this is ok, because we don't need to deal with unresolved link
  324. // maintenance because they are not hidden from view in dictionaries in
  325. // the same way as for LnkSet and LnkLst. This means that the functions
  326. // that call get_mutable_tree do not need to do anything for dictionaries.
  327. return nullptr;
  328. }
  329. private:
  330. Dictionary m_source;
  331. };
  332. inline std::pair<Dictionary::Iterator, bool> Dictionary::insert(Mixed key, const Obj& obj)
  333. {
  334. return insert(key, Mixed(obj.get_link()));
  335. }
  336. inline std::unique_ptr<CollectionBase> Dictionary::clone_collection() const
  337. {
  338. return m_obj.get_dictionary_ptr(m_col_key);
  339. }
  340. } // namespace realm
  341. #endif /* SRC_REALM_DICTIONARY_HPP_ */