set.hpp 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. /*************************************************************************
  2. *
  3. * Copyright 2020 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_SET_HPP
  19. #define REALM_SET_HPP
  20. #include <realm/collection.hpp>
  21. #include <realm/bplustree.hpp>
  22. #include <realm/array_key.hpp>
  23. namespace realm {
  24. class SetBase : public CollectionBase {
  25. public:
  26. using CollectionBase::CollectionBase;
  27. SetBase(const SetBase& other);
  28. SetBase(SetBase&& other) noexcept;
  29. SetBase& operator=(const SetBase& other);
  30. SetBase& operator=(SetBase&& other) noexcept;
  31. virtual SetBasePtr clone() const = 0;
  32. virtual std::pair<size_t, bool> insert_null() = 0;
  33. virtual std::pair<size_t, bool> erase_null() = 0;
  34. virtual std::pair<size_t, bool> insert_any(Mixed value) = 0;
  35. virtual std::pair<size_t, bool> erase_any(Mixed value) = 0;
  36. bool is_subset_of(const CollectionBase&) const;
  37. bool is_strict_subset_of(const CollectionBase& rhs) const;
  38. bool is_superset_of(const CollectionBase& rhs) const;
  39. bool is_strict_superset_of(const CollectionBase& rhs) const;
  40. bool intersects(const CollectionBase& rhs) const;
  41. bool set_equals(const CollectionBase& rhs) const;
  42. void assign_union(const CollectionBase&);
  43. void assign_intersection(const CollectionBase&);
  44. void assign_difference(const CollectionBase&);
  45. void assign_symmetric_difference(const CollectionBase&);
  46. protected:
  47. mutable std::unique_ptr<BPlusTreeBase> m_tree;
  48. void insert_repl(Replication* repl, size_t index, Mixed value) const;
  49. void erase_repl(Replication* repl, size_t index, Mixed value) const;
  50. void clear_repl(Replication* repl) const;
  51. REALM_COLD REALM_NORETURN void throw_invalid_null()
  52. {
  53. throw InvalidArgument(ErrorCodes::PropertyNotNullable,
  54. util::format("Set: %1", CollectionBase::get_property_name()));
  55. }
  56. };
  57. template <class T>
  58. class Set final : public CollectionBaseImpl<SetBase> {
  59. public:
  60. using Base = CollectionBaseImpl<SetBase>;
  61. using value_type = T;
  62. using iterator = CollectionIterator<Set<T>>;
  63. Set() = default;
  64. Set(const Obj& owner, ColKey col_key);
  65. Set(const Set& other);
  66. Set(Set&& other) noexcept;
  67. Set& operator=(const Set& other);
  68. Set& operator=(Set&& other) noexcept;
  69. SetBasePtr clone() const final
  70. {
  71. return std::make_unique<Set<T>>(*this);
  72. }
  73. T get(size_t ndx) const
  74. {
  75. const auto current_size = size();
  76. CollectionBase::validate_index("get()", ndx, current_size);
  77. return tree().get(ndx);
  78. }
  79. iterator begin() const noexcept
  80. {
  81. return iterator{this, 0};
  82. }
  83. iterator end() const noexcept
  84. {
  85. return iterator{this, size()};
  86. }
  87. size_t find_first(const T& value) const
  88. {
  89. return find(value);
  90. }
  91. template <class Func>
  92. void find_all(T value, Func&& func) const
  93. {
  94. size_t found = find(value);
  95. if (found != not_found) {
  96. func(found);
  97. }
  98. }
  99. /// Insert a value into the set if it does not already exist, returning the index of the inserted value,
  100. /// or the index of the already-existing value.
  101. std::pair<size_t, bool> insert(T value);
  102. /// Find the index of a value in the set, or `size_t(-1)` if it is not in the set.
  103. size_t find(T value) const;
  104. /// Erase an element from the set, returning true if the set contained the element.
  105. std::pair<size_t, bool> erase(T value);
  106. // Overriding members of CollectionBase:
  107. size_t size() const final;
  108. bool is_null(size_t ndx) const final;
  109. Mixed get_any(size_t ndx) const final
  110. {
  111. return get(ndx);
  112. }
  113. void clear() final;
  114. util::Optional<Mixed> min(size_t* return_ndx = nullptr) const final;
  115. util::Optional<Mixed> max(size_t* return_ndx = nullptr) const final;
  116. util::Optional<Mixed> sum(size_t* return_cnt = nullptr) const final;
  117. util::Optional<Mixed> avg(size_t* return_cnt = nullptr) const final;
  118. std::unique_ptr<CollectionBase> clone_collection() const final
  119. {
  120. return std::make_unique<Set<T>>(*this);
  121. }
  122. void sort(std::vector<size_t>& indices, bool ascending = true) const final;
  123. void distinct(std::vector<size_t>& indices, util::Optional<bool> sort_order = util::none) const final;
  124. // Overriding members of SetBase:
  125. size_t find_any(Mixed) const final;
  126. std::pair<size_t, bool> insert_null() final;
  127. std::pair<size_t, bool> erase_null() final;
  128. std::pair<size_t, bool> insert_any(Mixed value) final;
  129. std::pair<size_t, bool> erase_any(Mixed value) final;
  130. const BPlusTree<T>& get_tree() const
  131. {
  132. return tree();
  133. }
  134. UpdateStatus update_if_needed() const final;
  135. UpdateStatus ensure_created() final;
  136. void migrate();
  137. private:
  138. // Friend because it needs access to `m_tree` in the implementation of
  139. // `ObjCollectionBase::get_mutable_tree()`.
  140. friend class LnkSet;
  141. using Base::bump_content_version;
  142. using Base::m_col_key;
  143. using Base::m_nullable;
  144. using Base::m_obj;
  145. BPlusTree<T>& tree() const
  146. {
  147. return static_cast<BPlusTree<T>&>(*m_tree);
  148. }
  149. bool init_from_parent(bool allow_create) const;
  150. /// Update the accessor and return true if it is attached after the update.
  151. inline bool update() const
  152. {
  153. return update_if_needed() != UpdateStatus::Detached;
  154. }
  155. // `do_` methods here perform the action after preconditions have been
  156. // checked (bounds check, writability, etc.).
  157. void do_insert(size_t ndx, T value);
  158. void do_erase(size_t ndx);
  159. void do_clear();
  160. iterator find_impl(const T& value) const;
  161. };
  162. class LnkSet final : public ObjCollectionBase<SetBase> {
  163. public:
  164. using Base = ObjCollectionBase<SetBase>;
  165. using value_type = ObjKey;
  166. using iterator = CollectionIterator<LnkSet>;
  167. LnkSet() = default;
  168. LnkSet(const Obj& owner, ColKey col_key)
  169. : m_set(owner, col_key)
  170. {
  171. }
  172. LnkSet(const LnkSet&) = default;
  173. LnkSet(LnkSet&&) = default;
  174. LnkSet& operator=(const LnkSet&) = default;
  175. LnkSet& operator=(LnkSet&&) = default;
  176. bool operator==(const LnkSet& other) const;
  177. bool operator!=(const LnkSet& other) const;
  178. ObjKey get(size_t ndx) const;
  179. size_t find(ObjKey) const;
  180. size_t find_first(ObjKey) const;
  181. std::pair<size_t, bool> insert(ObjKey);
  182. std::pair<size_t, bool> erase(ObjKey);
  183. // Overriding members of CollectionBase:
  184. using CollectionBase::get_owner_key;
  185. CollectionBasePtr clone_collection() const
  186. {
  187. return clone_linkset();
  188. }
  189. size_t size() const final;
  190. bool is_null(size_t ndx) const final;
  191. Mixed get_any(size_t ndx) const final;
  192. void clear() final;
  193. util::Optional<Mixed> min(size_t* return_ndx = nullptr) const final;
  194. util::Optional<Mixed> max(size_t* return_ndx = nullptr) const final;
  195. util::Optional<Mixed> sum(size_t* return_cnt = nullptr) const final;
  196. util::Optional<Mixed> avg(size_t* return_cnt = nullptr) const final;
  197. void sort(std::vector<size_t>& indices, bool ascending = true) const final;
  198. void distinct(std::vector<size_t>& indices, util::Optional<bool> sort_order = util::none) const final;
  199. const Obj& get_obj() const noexcept final;
  200. bool is_attached() const final;
  201. bool has_changed() const final;
  202. ColKey get_col_key() const noexcept final;
  203. // Overriding members of SetBase:
  204. SetBasePtr clone() const
  205. {
  206. return clone_linkset();
  207. }
  208. // Overriding members of ObjList:
  209. LinkCollectionPtr clone_obj_list() const final
  210. {
  211. return clone_linkset();
  212. }
  213. size_t find_any(Mixed) const final;
  214. std::pair<size_t, bool> insert_null() final;
  215. std::pair<size_t, bool> erase_null() final;
  216. std::pair<size_t, bool> insert_any(Mixed value) final;
  217. std::pair<size_t, bool> erase_any(Mixed value) final;
  218. // Overriding members of ObjList:
  219. Obj get_object(size_t ndx) const final;
  220. ObjKey get_key(size_t ndx) const final;
  221. // LnkSet interface:
  222. std::unique_ptr<LnkSet> clone_linkset() const
  223. {
  224. // FIXME: The copy constructor requires this.
  225. update_if_needed();
  226. return std::make_unique<LnkSet>(*this);
  227. }
  228. template <class Func>
  229. void find_all(ObjKey value, Func&& func) const
  230. {
  231. if (value.is_unresolved()) {
  232. return;
  233. }
  234. m_set.find_all(value, [&](size_t ndx) {
  235. func(real2virtual(ndx));
  236. });
  237. }
  238. TableView get_sorted_view(SortDescriptor order) const;
  239. TableView get_sorted_view(ColKey column_key, bool ascending = true);
  240. void remove_target_row(size_t link_ndx);
  241. void remove_all_target_rows();
  242. iterator begin() const noexcept
  243. {
  244. return iterator{this, 0};
  245. }
  246. iterator end() const noexcept
  247. {
  248. return iterator{this, size()};
  249. }
  250. private:
  251. Set<ObjKey> m_set;
  252. // Overriding members of ObjCollectionBase:
  253. UpdateStatus do_update_if_needed() const final
  254. {
  255. return m_set.update_if_needed();
  256. }
  257. BPlusTree<ObjKey>* get_mutable_tree() const final
  258. {
  259. return &m_set.tree();
  260. }
  261. };
  262. template <>
  263. void Set<ObjKey>::do_insert(size_t, ObjKey);
  264. template <>
  265. void Set<ObjKey>::do_erase(size_t);
  266. template <>
  267. void Set<ObjKey>::do_clear();
  268. template <>
  269. void Set<ObjLink>::do_insert(size_t, ObjLink);
  270. template <>
  271. void Set<ObjLink>::do_erase(size_t);
  272. template <>
  273. void Set<Mixed>::do_insert(size_t, Mixed);
  274. template <>
  275. void Set<Mixed>::do_erase(size_t);
  276. template <>
  277. void Set<Mixed>::do_clear();
  278. template <>
  279. void Set<Mixed>::migrate();
  280. /// Compare set elements.
  281. ///
  282. /// We cannot use `std::less<>` directly, because the ordering of set elements
  283. /// impacts the file format. For primitive types this is trivial (and can indeed
  284. /// be just `std::less<>`), but for example `Mixed` has specialized comparison
  285. /// that defines equality of numeric types.
  286. template <class T>
  287. struct SetElementLessThan {
  288. bool operator()(const T& a, const T& b) const noexcept
  289. {
  290. // CAUTION: This routine is technically part of the file format, because
  291. // it determines the storage order of Set elements.
  292. return a < b;
  293. }
  294. };
  295. template <class T>
  296. struct SetElementEquals {
  297. bool operator()(const T& a, const T& b) const noexcept
  298. {
  299. // CAUTION: This routine is technically part of the file format, because
  300. // it determines the storage order of Set elements.
  301. return a == b;
  302. }
  303. };
  304. template <>
  305. struct SetElementLessThan<Mixed> {
  306. bool operator()(const Mixed& a, const Mixed& b) const noexcept
  307. {
  308. // CAUTION: This routine is technically part of the file format, because
  309. // it determines the storage order of Set elements.
  310. // These are the rules for comparison of Mixed types in a Set<Mixed>:
  311. // - If both values are null they are equal
  312. // - If only one value is null, that value is lesser than the other
  313. // - All numeric types are compared as the corresponding real numbers
  314. // would compare. So integer 3 equals double 3.
  315. // - String and binary types are compared using lexicographical comparison.
  316. // - All other types are compared using the comparison operators defined
  317. // for the types.
  318. // - If two values have different types, the rank of the types are compared.
  319. // the rank is as follows:
  320. // boolean
  321. // numeric
  322. // string
  323. // binary
  324. // Timestamp
  325. // ObjectId
  326. // UUID
  327. // TypedLink
  328. // Link
  329. //
  330. // The current Mixed::compare function implements these rules except when comparing
  331. // string and binary. If that function is changed we should either implement the rules
  332. // here or upgrade all Set<Mixed> columns.
  333. if (a.is_type(type_String) && b.is_type(type_Binary)) {
  334. return true;
  335. }
  336. if (a.is_type(type_Binary) && b.is_type(type_String)) {
  337. return false;
  338. }
  339. return a.compare(b) < 0;
  340. }
  341. };
  342. template <>
  343. struct SetElementEquals<Mixed> {
  344. bool operator()(const Mixed& a, const Mixed& b) const noexcept
  345. {
  346. // CAUTION: This routine is technically part of the file format, because
  347. // it determines the storage order of Set elements.
  348. // See comments above
  349. if (a.is_type(type_String) && b.is_type(type_Binary)) {
  350. return false;
  351. }
  352. if (a.is_type(type_Binary) && b.is_type(type_String)) {
  353. return false;
  354. }
  355. return a.compare(b) == 0;
  356. }
  357. };
  358. template <class T>
  359. inline Set<T>::Set(const Obj& obj, ColKey col_key)
  360. : Base(obj, col_key)
  361. {
  362. if (!col_key.is_set()) {
  363. throw InvalidArgument(ErrorCodes::TypeMismatch, "Property not a set");
  364. }
  365. check_column_type<value_type>(m_col_key);
  366. }
  367. inline SetBase::SetBase(const SetBase& other)
  368. : CollectionBase(other)
  369. {
  370. // Note: does not copy m_tree and instead that's initialized on demand
  371. }
  372. inline SetBase::SetBase(SetBase&& other) noexcept
  373. : CollectionBase(std::move(other))
  374. , m_tree(std::exchange(other.m_tree, nullptr))
  375. {
  376. }
  377. inline SetBase& SetBase::operator=(const SetBase& other)
  378. {
  379. if (this != &other) {
  380. // Just reset the pointer and rely on init_from_parent() being called
  381. // when the accessor is actually used.
  382. m_tree.reset();
  383. }
  384. return *this;
  385. }
  386. inline SetBase& SetBase::operator=(SetBase&& other) noexcept
  387. {
  388. if (this != &other) {
  389. m_tree = std::exchange(other.m_tree, nullptr);
  390. }
  391. return *this;
  392. }
  393. template <class T>
  394. inline Set<T>::Set(const Set& other)
  395. : Base(static_cast<const Base&>(other))
  396. {
  397. // Reset the content version so we can rely on init_from_parent() being
  398. // called lazily when the accessor is used.
  399. Base::reset_content_version();
  400. }
  401. template <class T>
  402. inline Set<T>::Set(Set&& other) noexcept
  403. : Base(static_cast<Base&&>(other))
  404. {
  405. if (m_tree) {
  406. m_tree->set_parent(this, 0);
  407. }
  408. }
  409. template <class T>
  410. inline Set<T>& Set<T>::operator=(const Set& other)
  411. {
  412. Base::operator=(static_cast<const Base&>(other));
  413. if (this != &other) {
  414. // Just reset the pointer and rely on init_from_parent() being called
  415. // when the accessor is actually used.
  416. Base::reset_content_version();
  417. }
  418. return *this;
  419. }
  420. template <class T>
  421. inline Set<T>& Set<T>::operator=(Set&& other) noexcept
  422. {
  423. Base::operator=(static_cast<Base&&>(other));
  424. if (this != &other) {
  425. if (m_tree) {
  426. m_tree->set_parent(this, 0);
  427. // Note: We do not need to call reset_content_version(), because we
  428. // took both `m_tree` and `m_content_version` from `other`.
  429. }
  430. }
  431. return *this;
  432. }
  433. template <typename U>
  434. Set<U> Obj::get_set(ColKey col_key) const
  435. {
  436. return Set<U>(*this, col_key);
  437. }
  438. template <typename U>
  439. inline SetPtr<U> Obj::get_set_ptr(ColKey col_key) const
  440. {
  441. return std::make_unique<Set<U>>(*this, col_key);
  442. }
  443. inline LnkSet Obj::get_linkset(ColKey col_key) const
  444. {
  445. return LnkSet{*this, col_key};
  446. }
  447. inline LnkSet Obj::get_linkset(StringData col_name) const
  448. {
  449. return get_linkset(get_column_key(col_name));
  450. }
  451. inline LnkSetPtr Obj::get_linkset_ptr(ColKey col_key) const
  452. {
  453. return std::make_unique<LnkSet>(*this, col_key);
  454. }
  455. template <class T>
  456. size_t Set<T>::find(T value) const
  457. {
  458. auto it = find_impl(value);
  459. if (it != end() && SetElementEquals<T>{}(*it, value)) {
  460. return it.index();
  461. }
  462. return npos;
  463. }
  464. template <class T>
  465. size_t Set<T>::find_any(Mixed value) const
  466. {
  467. if constexpr (std::is_same_v<T, Mixed>) {
  468. return find(value);
  469. }
  470. else {
  471. if (value.is_null()) {
  472. if (!m_nullable) {
  473. return not_found;
  474. }
  475. return find(BPlusTree<T>::default_value(true));
  476. }
  477. else {
  478. return find(value.get<typename util::RemoveOptional<T>::type>());
  479. }
  480. }
  481. }
  482. template <class T>
  483. REALM_NOINLINE auto Set<T>::find_impl(const T& value) const -> iterator
  484. {
  485. auto b = this->begin();
  486. auto e = this->end(); // Note: This ends up calling `update_if_needed()`.
  487. return std::lower_bound(b, e, value, SetElementLessThan<T>{});
  488. }
  489. template <class T>
  490. std::pair<size_t, bool> Set<T>::insert(T value)
  491. {
  492. if (!m_nullable && value_is_null(value))
  493. throw_invalid_null();
  494. update_if_needed();
  495. ensure_created();
  496. auto it = find_impl(value);
  497. if (it != this->end() && SetElementEquals<T>{}(*it, value)) {
  498. return {it.index(), false};
  499. }
  500. if (Replication* repl = m_obj.get_replication()) {
  501. // FIXME: We should emit an instruction regardless of element presence for the purposes of conflict
  502. // resolution in synchronized databases. The reason is that the new insertion may come at a later time
  503. // than an interleaving erase instruction, so emitting the instruction ensures that last "write" wins.
  504. this->insert_repl(repl, it.index(), value);
  505. }
  506. do_insert(it.index(), value);
  507. bump_content_version();
  508. return {it.index(), true};
  509. }
  510. template <class T>
  511. std::pair<size_t, bool> Set<T>::insert_any(Mixed value)
  512. {
  513. if constexpr (std::is_same_v<T, Mixed>) {
  514. return insert(value);
  515. }
  516. else {
  517. if (value.is_null()) {
  518. return insert_null();
  519. }
  520. else {
  521. return insert(value.get<typename util::RemoveOptional<T>::type>());
  522. }
  523. }
  524. }
  525. template <class T>
  526. std::pair<size_t, bool> Set<T>::erase(T value)
  527. {
  528. auto it = find_impl(value); // Note: This ends up calling `update_if_needed()`.
  529. if (it == end() || !SetElementEquals<T>{}(*it, value)) {
  530. return {npos, false};
  531. }
  532. if (Replication* repl = m_obj.get_replication()) {
  533. this->erase_repl(repl, it.index(), value);
  534. }
  535. do_erase(it.index());
  536. bump_content_version();
  537. return {it.index(), true};
  538. }
  539. template <class T>
  540. std::pair<size_t, bool> Set<T>::erase_any(Mixed value)
  541. {
  542. if constexpr (std::is_same_v<T, Mixed>) {
  543. return erase(value);
  544. }
  545. else {
  546. if (value.is_null()) {
  547. return erase_null();
  548. }
  549. else {
  550. return erase(value.get<typename util::RemoveOptional<T>::type>());
  551. }
  552. }
  553. }
  554. template <class T>
  555. inline std::pair<size_t, bool> Set<T>::insert_null()
  556. {
  557. return insert(BPlusTree<T>::default_value(this->m_nullable));
  558. }
  559. template <class T>
  560. std::pair<size_t, bool> Set<T>::erase_null()
  561. {
  562. return erase(BPlusTree<T>::default_value(this->m_nullable));
  563. }
  564. template <class T>
  565. REALM_NOINLINE size_t Set<T>::size() const
  566. {
  567. return update() ? m_tree->size() : 0;
  568. }
  569. template <class T>
  570. inline bool Set<T>::is_null(size_t ndx) const
  571. {
  572. return m_nullable && value_is_null(get(ndx));
  573. }
  574. template <class T>
  575. inline void Set<T>::clear()
  576. {
  577. if (size() > 0) {
  578. if (Replication* repl = this->m_obj.get_replication()) {
  579. this->clear_repl(repl);
  580. }
  581. do_clear();
  582. bump_content_version();
  583. }
  584. }
  585. template <class T>
  586. inline util::Optional<Mixed> Set<T>::min(size_t* return_ndx) const
  587. {
  588. if (update()) {
  589. return MinHelper<T>::eval(tree(), return_ndx);
  590. }
  591. return MinHelper<T>::not_found(return_ndx);
  592. }
  593. template <class T>
  594. inline util::Optional<Mixed> Set<T>::max(size_t* return_ndx) const
  595. {
  596. if (update()) {
  597. return MaxHelper<T>::eval(tree(), return_ndx);
  598. }
  599. return MaxHelper<T>::not_found(return_ndx);
  600. }
  601. template <class T>
  602. inline util::Optional<Mixed> Set<T>::sum(size_t* return_cnt) const
  603. {
  604. if (update()) {
  605. return SumHelper<T>::eval(tree(), return_cnt);
  606. }
  607. return SumHelper<T>::not_found(return_cnt);
  608. }
  609. template <class T>
  610. inline util::Optional<Mixed> Set<T>::avg(size_t* return_cnt) const
  611. {
  612. if (update()) {
  613. return AverageHelper<T>::eval(tree(), return_cnt);
  614. }
  615. return AverageHelper<T>::not_found(return_cnt);
  616. }
  617. REALM_NOINLINE void set_sorted_indices(size_t sz, std::vector<size_t>& indices, bool ascending);
  618. template <class T>
  619. inline void Set<T>::sort(std::vector<size_t>& indices, bool ascending) const
  620. {
  621. auto sz = size();
  622. set_sorted_indices(sz, indices, ascending);
  623. }
  624. template <>
  625. void Set<Mixed>::sort(std::vector<size_t>& indices, bool ascending) const;
  626. template <class T>
  627. void Set<T>::distinct(std::vector<size_t>& indices, util::Optional<bool> sort_order) const
  628. {
  629. auto ascending = !sort_order || *sort_order;
  630. set_sorted_indices(size(), indices, ascending);
  631. }
  632. template <class T>
  633. inline void Set<T>::do_insert(size_t ndx, T value)
  634. {
  635. tree().insert(ndx, value);
  636. }
  637. template <class T>
  638. inline void Set<T>::do_erase(size_t ndx)
  639. {
  640. m_tree->erase(ndx);
  641. }
  642. template <class T>
  643. inline void Set<T>::do_clear()
  644. {
  645. m_tree->clear();
  646. }
  647. inline bool LnkSet::operator==(const LnkSet& other) const
  648. {
  649. return m_set == other.m_set;
  650. }
  651. inline bool LnkSet::operator!=(const LnkSet& other) const
  652. {
  653. return m_set != other.m_set;
  654. }
  655. inline ObjKey LnkSet::get(size_t ndx) const
  656. {
  657. const auto current_size = size();
  658. if (ndx >= current_size) {
  659. throw OutOfBounds(util::format("Invalid index into set: %1", CollectionBase::get_property_name()), ndx,
  660. current_size);
  661. }
  662. return m_set.tree().get(virtual2real(ndx));
  663. }
  664. inline size_t LnkSet::find(ObjKey value) const
  665. {
  666. if (value.is_unresolved()) {
  667. return not_found;
  668. }
  669. update_if_needed();
  670. size_t ndx = m_set.find(value);
  671. if (ndx == not_found) {
  672. return not_found;
  673. }
  674. return real2virtual(ndx);
  675. }
  676. inline size_t LnkSet::find_first(ObjKey value) const
  677. {
  678. return find(value);
  679. }
  680. inline size_t LnkSet::size() const
  681. {
  682. update_if_needed();
  683. return m_set.size() - num_unresolved();
  684. }
  685. inline std::pair<size_t, bool> LnkSet::insert(ObjKey value)
  686. {
  687. REALM_ASSERT(!value.is_unresolved());
  688. update_if_needed();
  689. auto [ndx, inserted] = m_set.insert(value);
  690. if (inserted) {
  691. update_unresolved(UpdateStatus::Updated);
  692. }
  693. return {real2virtual(ndx), inserted};
  694. }
  695. inline std::pair<size_t, bool> LnkSet::erase(ObjKey value)
  696. {
  697. REALM_ASSERT(!value.is_unresolved());
  698. update_if_needed();
  699. auto [ndx, removed] = m_set.erase(value);
  700. if (removed) {
  701. update_unresolved(UpdateStatus::Updated);
  702. ndx = real2virtual(ndx);
  703. }
  704. return {ndx, removed};
  705. }
  706. inline bool LnkSet::is_null(size_t ndx) const
  707. {
  708. update_if_needed();
  709. return m_set.is_null(virtual2real(ndx));
  710. }
  711. inline Mixed LnkSet::get_any(size_t ndx) const
  712. {
  713. update_if_needed();
  714. auto obj_key = m_set.get(virtual2real(ndx));
  715. return ObjLink{get_target_table()->get_key(), obj_key};
  716. }
  717. inline std::pair<size_t, bool> LnkSet::insert_null()
  718. {
  719. update_if_needed();
  720. auto [ndx, inserted] = m_set.insert_null();
  721. if (inserted) {
  722. update_unresolved(UpdateStatus::Updated);
  723. }
  724. return {real2virtual(ndx), inserted};
  725. }
  726. inline std::pair<size_t, bool> LnkSet::erase_null()
  727. {
  728. update_if_needed();
  729. auto [ndx, erased] = m_set.erase_null();
  730. if (erased) {
  731. update_unresolved(UpdateStatus::Updated);
  732. ndx = real2virtual(ndx);
  733. }
  734. return {ndx, erased};
  735. }
  736. inline std::pair<size_t, bool> LnkSet::insert_any(Mixed value)
  737. {
  738. update_if_needed();
  739. auto [ndx, inserted] = m_set.insert_any(value);
  740. if (inserted) {
  741. update_unresolved(UpdateStatus::Updated);
  742. }
  743. return {real2virtual(ndx), inserted};
  744. }
  745. inline std::pair<size_t, bool> LnkSet::erase_any(Mixed value)
  746. {
  747. auto [ndx, erased] = m_set.erase_any(value);
  748. if (erased) {
  749. update_unresolved(UpdateStatus::Updated);
  750. ndx = real2virtual(ndx);
  751. }
  752. return {ndx, erased};
  753. }
  754. inline void LnkSet::clear()
  755. {
  756. // Note: Explicit call to `ensure_writable()` not needed, because we
  757. // explicitly call `clear_unresolved()`.
  758. m_set.clear();
  759. clear_unresolved();
  760. }
  761. inline util::Optional<Mixed> LnkSet::min(size_t* return_ndx) const
  762. {
  763. update_if_needed();
  764. size_t found = not_found;
  765. auto value = m_set.min(&found);
  766. if (found != not_found && return_ndx) {
  767. *return_ndx = real2virtual(found);
  768. }
  769. return value;
  770. }
  771. inline util::Optional<Mixed> LnkSet::max(size_t* return_ndx) const
  772. {
  773. update_if_needed();
  774. size_t found = not_found;
  775. auto value = m_set.max(&found);
  776. if (found != not_found && return_ndx) {
  777. *return_ndx = real2virtual(found);
  778. }
  779. return value;
  780. }
  781. inline util::Optional<Mixed> LnkSet::sum(size_t* return_cnt) const
  782. {
  783. static_cast<void>(return_cnt);
  784. REALM_TERMINATE("Not implemented");
  785. }
  786. inline util::Optional<Mixed> LnkSet::avg(size_t* return_cnt) const
  787. {
  788. static_cast<void>(return_cnt);
  789. REALM_TERMINATE("Not implemented");
  790. }
  791. inline void LnkSet::sort(std::vector<size_t>& indices, bool ascending) const
  792. {
  793. update_if_needed();
  794. // Map the input indices to real indices.
  795. std::transform(indices.begin(), indices.end(), indices.begin(), [this](size_t ndx) {
  796. return virtual2real(ndx);
  797. });
  798. m_set.sort(indices, ascending);
  799. if (has_unresolved()) {
  800. indices.erase(std::remove_if(indices.begin(), indices.end(),
  801. [&](size_t ndx) {
  802. return real_is_unresolved(ndx);
  803. }),
  804. indices.end());
  805. }
  806. // Map the output indices to virtual indices.
  807. std::transform(indices.begin(), indices.end(), indices.begin(), [this](size_t ndx) {
  808. return real2virtual(ndx);
  809. });
  810. }
  811. inline void LnkSet::distinct(std::vector<size_t>& indices, util::Optional<bool> sort_order) const
  812. {
  813. update_if_needed();
  814. // Map the input indices to real indices.
  815. std::transform(indices.begin(), indices.end(), indices.begin(), [this](size_t ndx) {
  816. return virtual2real(ndx);
  817. });
  818. m_set.distinct(indices, sort_order);
  819. if (has_unresolved()) {
  820. indices.erase(std::remove_if(indices.begin(), indices.end(),
  821. [&](size_t ndx) {
  822. return real_is_unresolved(ndx);
  823. }),
  824. indices.end());
  825. }
  826. // Map the output indices to virtual indices.
  827. std::transform(indices.begin(), indices.end(), indices.begin(), [this](size_t ndx) {
  828. return real2virtual(ndx);
  829. });
  830. }
  831. inline const Obj& LnkSet::get_obj() const noexcept
  832. {
  833. return m_set.get_obj();
  834. }
  835. inline bool LnkSet::is_attached() const
  836. {
  837. return m_set.is_attached();
  838. }
  839. inline bool LnkSet::has_changed() const
  840. {
  841. return m_set.has_changed();
  842. }
  843. inline ColKey LnkSet::get_col_key() const noexcept
  844. {
  845. return m_set.get_col_key();
  846. }
  847. inline size_t LnkSet::find_any(Mixed value) const
  848. {
  849. if (value.is_null())
  850. return not_found;
  851. const auto type = value.get_type();
  852. if (type == type_Link) {
  853. return find(value.get<ObjKey>());
  854. }
  855. if (type == type_TypedLink) {
  856. auto link = value.get_link();
  857. if (link.get_table_key() == get_target_table()->get_key()) {
  858. return find(link.get_obj_key());
  859. }
  860. }
  861. return not_found;
  862. }
  863. inline Obj LnkSet::get_object(size_t ndx) const
  864. {
  865. ObjKey key = get(ndx);
  866. return get_target_table()->get_object(key);
  867. }
  868. inline ObjKey LnkSet::get_key(size_t ndx) const
  869. {
  870. return get(ndx);
  871. }
  872. } // namespace realm
  873. #endif // REALM_SET_HPP