mixed.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. /*************************************************************************
  2. *
  3. * Copyright 2016 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_MIXED_HPP
  19. #define REALM_MIXED_HPP
  20. #include <cstdint> // int64_t - not part of C++03, not even required by C++11 (see C++11 section 18.4.1)
  21. #include <cstddef> // size_t
  22. #include <cstring>
  23. #include <realm/keys.hpp>
  24. #include <realm/binary_data.hpp>
  25. #include <realm/data_type.hpp>
  26. #if REALM_ENABLE_GEOSPATIAL
  27. #include <realm/geospatial.hpp>
  28. #endif
  29. #include <realm/string_data.hpp>
  30. #include <realm/timestamp.hpp>
  31. #include <realm/decimal128.hpp>
  32. #include <realm/object_id.hpp>
  33. #include <realm/uuid.hpp>
  34. #include <realm/util/assert.hpp>
  35. #include <realm/utilities.hpp>
  36. namespace realm {
  37. /// This class represents a polymorphic Realm value.
  38. ///
  39. /// At any particular moment an instance of this class stores a
  40. /// definite value of a definite type. If, for instance, that is an
  41. /// integer value, you may call get<int64_t>() to extract that value. You
  42. /// may call get_type() to discover what type of value is currently
  43. /// stored. Calling get<int64_t>() on an instance that does not store an
  44. /// integer, has undefined behavior, and likewise for all the other
  45. /// types that can be stored.
  46. ///
  47. /// It is crucial to understand that the act of extracting a value of
  48. /// a particular type requires definite knowledge about the stored
  49. /// type. Calling a getter method for any particular type, that is not
  50. /// the same type as the stored value, has undefined behavior.
  51. ///
  52. /// While values of numeric types are contained directly in a Mixed
  53. /// instance, character and binary data are merely referenced. A Mixed
  54. /// instance never owns the referenced data, nor does it in any other
  55. /// way attempt to manage its lifetime.
  56. ///
  57. /// For compatibility with C style strings, when a string (character
  58. /// data) is stored in a Realm database, it is always followed by a
  59. /// terminating null character. This is also true when strings are
  60. /// stored in a mixed type column. This means that in the following
  61. /// code, if the 'mixed' value of the 8th row stores a string, then \c
  62. /// c_str will always point to a null-terminated string:
  63. ///
  64. /// \code{.cpp}
  65. ///
  66. /// const char* c_str = my_table[7].mixed.data(); // Always null-terminated
  67. ///
  68. /// \endcode
  69. ///
  70. /// Note that this assumption does not hold in general for strings in
  71. /// instances of Mixed. Indeed there is nothing stopping you from
  72. /// constructing a new Mixed instance that refers to a string without
  73. /// a terminating null character.
  74. ///
  75. /// At the present time no soultion has been found that would allow
  76. /// for a Mixed instance to directly store a reference to a table. The
  77. /// problem is roughly as follows: From most points of view, the
  78. /// desirable thing to do, would be to store the table reference in a
  79. /// Mixed instance as a plain pointer without any ownership
  80. /// semantics. This would have no negative impact on the performance
  81. /// of copying and destroying Mixed instances, and it would serve just
  82. /// fine for passing a table as argument when setting the value of an
  83. /// entry in a mixed column. In that case a copy of the referenced
  84. /// table would be inserted into the mixed column.
  85. ///
  86. /// On the other hand, when retrieving a table reference from a mixed
  87. /// column, storing it as a plain pointer in a Mixed instance is no
  88. /// longer an acceptable option. The complex rules for managing the
  89. /// lifetime of a Table instance, that represents a subtable,
  90. /// necessitates the use of a "smart pointer" such as
  91. /// TableRef. Enhancing the Mixed class to be able to act as a
  92. /// TableRef would be possible, but would also lead to several new
  93. /// problems. One problem is the risk of a Mixed instance outliving a
  94. /// stack allocated Table instance that it references. This would be a
  95. /// fatal error. Another problem is the impact that the nontrivial
  96. /// table reference has on the performance of copying and destroying
  97. /// Mixed instances.
  98. ///
  99. /// \sa StringData
  100. class Mixed {
  101. public:
  102. Mixed() noexcept
  103. : m_type(0)
  104. {
  105. }
  106. Mixed(util::None) noexcept
  107. : Mixed()
  108. {
  109. }
  110. Mixed(realm::null) noexcept
  111. : Mixed()
  112. {
  113. }
  114. Mixed(int i) noexcept
  115. : Mixed(int64_t(i))
  116. {
  117. }
  118. Mixed(int64_t) noexcept;
  119. Mixed(bool) noexcept;
  120. explicit Mixed(std::vector<bool>::reference b) noexcept
  121. : Mixed(bool(b))
  122. {
  123. }
  124. Mixed(float) noexcept;
  125. Mixed(double) noexcept;
  126. Mixed(util::Optional<int64_t>) noexcept;
  127. Mixed(util::Optional<bool>) noexcept;
  128. Mixed(util::Optional<float>) noexcept;
  129. Mixed(util::Optional<double>) noexcept;
  130. Mixed(StringData) noexcept;
  131. Mixed(BinaryData) noexcept;
  132. Mixed(Timestamp) noexcept;
  133. Mixed(Decimal128);
  134. Mixed(ObjectId) noexcept;
  135. Mixed(util::Optional<ObjectId>) noexcept;
  136. Mixed(ObjKey) noexcept;
  137. Mixed(ObjLink) noexcept;
  138. Mixed(UUID) noexcept;
  139. Mixed(util::Optional<UUID>) noexcept;
  140. Mixed(const Obj&) noexcept;
  141. #if REALM_ENABLE_GEOSPATIAL
  142. Mixed(Geospatial*) noexcept;
  143. #endif
  144. // These are shortcuts for Mixed(StringData(c_str)), and are
  145. // needed to avoid unwanted implicit conversion of char* to bool.
  146. Mixed(char* c_str) noexcept
  147. : Mixed(StringData(c_str))
  148. {
  149. }
  150. Mixed(const char* c_str) noexcept
  151. : Mixed(StringData(c_str))
  152. {
  153. }
  154. Mixed(const std::string& s) noexcept
  155. : Mixed(StringData(s))
  156. {
  157. }
  158. DataType get_type() const noexcept
  159. {
  160. REALM_ASSERT(m_type);
  161. return DataType(m_type - 1);
  162. }
  163. template <class... Tail>
  164. bool is_type(DataType head, Tail... tail) const noexcept
  165. {
  166. return _is_type(head, tail...);
  167. }
  168. template <class... Tail>
  169. static bool is_numeric(DataType head, Tail... tail) noexcept
  170. {
  171. return _is_numeric(head, tail...);
  172. }
  173. static bool types_are_comparable(const Mixed& l, const Mixed& r);
  174. static bool data_types_are_comparable(DataType l_type, DataType r_type);
  175. template <class T>
  176. T get() const noexcept;
  177. template <class T>
  178. const T* get_if() const noexcept;
  179. template <class T>
  180. T export_to_type() const noexcept;
  181. // These functions are kept to be backwards compatible
  182. int64_t get_int() const noexcept;
  183. bool get_bool() const noexcept;
  184. float get_float() const noexcept;
  185. double get_double() const noexcept;
  186. StringData get_string() const noexcept;
  187. BinaryData get_binary() const noexcept;
  188. Timestamp get_timestamp() const noexcept;
  189. Decimal128 get_decimal() const noexcept;
  190. ObjectId get_object_id() const noexcept;
  191. UUID get_uuid() const noexcept;
  192. ObjLink get_link() const noexcept;
  193. bool is_null() const noexcept;
  194. bool accumulate_numeric_to(Decimal128& destination) const noexcept;
  195. bool is_unresolved_link() const noexcept;
  196. bool is_same_type(const Mixed& b) const noexcept;
  197. // Will use utf8_compare for strings
  198. int compare(const Mixed& b) const noexcept;
  199. // Will compare strings as arrays of signed chars
  200. int compare_signed(const Mixed& b) const noexcept;
  201. friend bool operator==(const Mixed& a, const Mixed& b) noexcept
  202. {
  203. return a.compare(b) == 0;
  204. }
  205. friend bool operator!=(const Mixed& a, const Mixed& b) noexcept
  206. {
  207. return a.compare(b) != 0;
  208. }
  209. friend bool operator<(const Mixed& a, const Mixed& b) noexcept
  210. {
  211. return a.compare(b) < 0;
  212. }
  213. friend bool operator>(const Mixed& a, const Mixed& b) noexcept
  214. {
  215. return a.compare(b) > 0;
  216. }
  217. friend bool operator<=(const Mixed& a, const Mixed& b) noexcept
  218. {
  219. return a.compare(b) <= 0;
  220. }
  221. friend bool operator>=(const Mixed& a, const Mixed& b) noexcept
  222. {
  223. return a.compare(b) >= 0;
  224. }
  225. Mixed operator+(const Mixed&) const noexcept;
  226. Mixed operator-(const Mixed&) const noexcept;
  227. Mixed operator*(const Mixed&) const noexcept;
  228. Mixed operator/(const Mixed&) const noexcept;
  229. size_t hash() const;
  230. StringData get_index_data(std::array<char, 16>&) const noexcept;
  231. void use_buffer(std::string& buf) noexcept;
  232. protected:
  233. friend std::ostream& operator<<(std::ostream& out, const Mixed& m);
  234. uint32_t m_type;
  235. union {
  236. int64_t int_val;
  237. bool bool_val;
  238. float float_val;
  239. double double_val;
  240. StringData string_val;
  241. BinaryData binary_val;
  242. Timestamp date_val;
  243. ObjectId id_val;
  244. Decimal128 decimal_val;
  245. ObjLink link_val;
  246. UUID uuid_val;
  247. #if REALM_ENABLE_GEOSPATIAL
  248. Geospatial* geospatial_val;
  249. #endif
  250. };
  251. private:
  252. static bool _is_type() noexcept
  253. {
  254. return false;
  255. }
  256. bool _is_type(DataType type) const noexcept
  257. {
  258. return m_type == unsigned(int(type) + 1);
  259. }
  260. template <class... Tail>
  261. bool _is_type(DataType head, Tail... tail) const noexcept
  262. {
  263. return _is_type(head) || _is_type(tail...);
  264. }
  265. static bool _is_numeric(DataType type) noexcept
  266. {
  267. return type == type_Int || type == type_Float || type == type_Double || type == type_Decimal ||
  268. type == type_Mixed;
  269. }
  270. template <class... Tail>
  271. static bool _is_numeric(DataType head, Tail... tail) noexcept
  272. {
  273. return _is_numeric(head) && _is_numeric(tail...);
  274. }
  275. };
  276. static_assert(std::is_trivially_destructible_v<Mixed>);
  277. class OwnedMixed : public Mixed {
  278. public:
  279. explicit OwnedMixed(std::string&& str)
  280. : m_owned_string(std::move(str))
  281. {
  282. m_type = int(type_String) + 1;
  283. string_val = m_owned_string;
  284. }
  285. OwnedMixed(OwnedMixed&& m) noexcept
  286. : Mixed(m)
  287. , m_owned_string(std::move(m.m_owned_string))
  288. {
  289. if (is_type(type_String)) {
  290. string_val = m_owned_string;
  291. }
  292. }
  293. OwnedMixed(const OwnedMixed& m)
  294. : Mixed(m)
  295. , m_owned_string(m.m_owned_string)
  296. {
  297. if (is_type(type_String)) {
  298. string_val = m_owned_string;
  299. }
  300. }
  301. OwnedMixed& operator=(OwnedMixed&& m) noexcept
  302. {
  303. *static_cast<Mixed*>(this) = m;
  304. if (is_type(type_String)) {
  305. m_owned_string = std::move(m.m_owned_string);
  306. string_val = m_owned_string;
  307. }
  308. return *this;
  309. }
  310. OwnedMixed& operator=(const OwnedMixed& m)
  311. {
  312. *static_cast<Mixed*>(this) = m;
  313. if (is_type(type_String)) {
  314. m_owned_string = m.m_owned_string;
  315. string_val = m_owned_string;
  316. }
  317. return *this;
  318. }
  319. explicit OwnedMixed(const Mixed& m)
  320. : Mixed(m)
  321. {
  322. if (m.is_type(type_String)) {
  323. m_owned_string = std::string(m.get_string());
  324. string_val = m_owned_string;
  325. }
  326. }
  327. OwnedMixed& operator=(const Mixed& m)
  328. {
  329. *static_cast<Mixed*>(this) = m;
  330. if (m.is_type(type_String)) {
  331. m_owned_string = std::string(m.get_string());
  332. string_val = m_owned_string;
  333. }
  334. return *this;
  335. }
  336. using Mixed::Mixed;
  337. private:
  338. std::string m_owned_string;
  339. };
  340. // Implementation:
  341. inline Mixed::Mixed(int64_t v) noexcept
  342. {
  343. m_type = int(type_Int) + 1;
  344. int_val = v;
  345. }
  346. inline Mixed::Mixed(bool v) noexcept
  347. {
  348. m_type = int(type_Bool) + 1;
  349. bool_val = v;
  350. }
  351. inline Mixed::Mixed(float v) noexcept
  352. {
  353. if (null::is_null_float(v)) {
  354. m_type = 0;
  355. }
  356. else {
  357. m_type = int(type_Float) + 1;
  358. float_val = v;
  359. }
  360. }
  361. inline Mixed::Mixed(double v) noexcept
  362. {
  363. if (null::is_null_float(v)) {
  364. m_type = 0;
  365. }
  366. else {
  367. m_type = int(type_Double) + 1;
  368. double_val = v;
  369. }
  370. }
  371. inline Mixed::Mixed(util::Optional<int64_t> v) noexcept
  372. {
  373. if (v) {
  374. m_type = int(type_Int) + 1;
  375. int_val = *v;
  376. }
  377. else {
  378. m_type = 0;
  379. }
  380. }
  381. inline Mixed::Mixed(util::Optional<bool> v) noexcept
  382. {
  383. if (v) {
  384. m_type = int(type_Bool) + 1;
  385. bool_val = *v;
  386. }
  387. else {
  388. m_type = 0;
  389. }
  390. }
  391. inline Mixed::Mixed(util::Optional<float> v) noexcept
  392. {
  393. if (v && !null::is_null_float(*v)) {
  394. m_type = int(type_Float) + 1;
  395. float_val = *v;
  396. }
  397. else {
  398. m_type = 0;
  399. }
  400. }
  401. inline Mixed::Mixed(util::Optional<double> v) noexcept
  402. {
  403. if (v && !null::is_null_float(*v)) {
  404. m_type = int(type_Double) + 1;
  405. double_val = *v;
  406. }
  407. else {
  408. m_type = 0;
  409. }
  410. }
  411. inline Mixed::Mixed(util::Optional<ObjectId> v) noexcept
  412. {
  413. if (v) {
  414. m_type = int(type_ObjectId) + 1;
  415. id_val = *v;
  416. }
  417. else {
  418. m_type = 0;
  419. }
  420. }
  421. inline Mixed::Mixed(util::Optional<UUID> v) noexcept
  422. {
  423. if (v) {
  424. m_type = int(type_UUID) + 1;
  425. uuid_val = *v;
  426. }
  427. else {
  428. m_type = 0;
  429. }
  430. }
  431. inline Mixed::Mixed(StringData v) noexcept
  432. {
  433. if (!v.is_null()) {
  434. m_type = int(type_String) + 1;
  435. string_val = v;
  436. }
  437. else {
  438. m_type = 0;
  439. }
  440. }
  441. inline Mixed::Mixed(BinaryData v) noexcept
  442. {
  443. if (!v.is_null()) {
  444. m_type = int(type_Binary) + 1;
  445. binary_val = v;
  446. }
  447. else {
  448. m_type = 0;
  449. }
  450. }
  451. inline Mixed::Mixed(Timestamp v) noexcept
  452. {
  453. if (!v.is_null()) {
  454. m_type = int(type_Timestamp) + 1;
  455. date_val = v;
  456. }
  457. else {
  458. m_type = 0;
  459. }
  460. }
  461. inline Mixed::Mixed(Decimal128 v)
  462. {
  463. if (!v.is_null()) {
  464. m_type = int(type_Decimal) + 1;
  465. decimal_val = v;
  466. }
  467. else {
  468. m_type = 0;
  469. }
  470. }
  471. #if REALM_ENABLE_GEOSPATIAL
  472. inline Mixed::Mixed(Geospatial* store) noexcept
  473. {
  474. m_type = int(type_Geospatial) + 1;
  475. geospatial_val = store;
  476. }
  477. #endif
  478. inline Mixed::Mixed(ObjectId v) noexcept
  479. {
  480. m_type = int(type_ObjectId) + 1;
  481. id_val = v;
  482. }
  483. inline Mixed::Mixed(UUID v) noexcept
  484. {
  485. m_type = int(type_UUID) + 1;
  486. uuid_val = v;
  487. }
  488. inline Mixed::Mixed(ObjKey v) noexcept
  489. {
  490. if (v) {
  491. m_type = int(type_Link) + 1;
  492. int_val = v.value;
  493. }
  494. else {
  495. m_type = 0;
  496. }
  497. }
  498. inline Mixed::Mixed(ObjLink v) noexcept
  499. {
  500. if (v) {
  501. m_type = int(type_TypedLink) + 1;
  502. link_val = v;
  503. }
  504. else {
  505. m_type = 0;
  506. }
  507. }
  508. template <>
  509. inline null Mixed::get<null>() const noexcept
  510. {
  511. REALM_ASSERT(m_type == 0);
  512. return {};
  513. }
  514. template <>
  515. inline int64_t Mixed::get<int64_t>() const noexcept
  516. {
  517. REALM_ASSERT(get_type() == type_Int);
  518. return int_val;
  519. }
  520. template <>
  521. inline int Mixed::get<int>() const noexcept
  522. {
  523. REALM_ASSERT(get_type() == type_Int);
  524. return int(int_val);
  525. }
  526. inline int64_t Mixed::get_int() const noexcept
  527. {
  528. return get<int64_t>();
  529. }
  530. template <>
  531. inline const int64_t* Mixed::get_if<int64_t>() const noexcept
  532. {
  533. return is_type(type_Int) ? &int_val : nullptr;
  534. }
  535. template <>
  536. inline bool Mixed::get<bool>() const noexcept
  537. {
  538. REALM_ASSERT(get_type() == type_Bool);
  539. return bool_val;
  540. }
  541. inline bool Mixed::get_bool() const noexcept
  542. {
  543. return get<bool>();
  544. }
  545. template <>
  546. inline const bool* Mixed::get_if<bool>() const noexcept
  547. {
  548. return is_type(type_Bool) ? &bool_val : nullptr;
  549. }
  550. template <>
  551. inline float Mixed::get<float>() const noexcept
  552. {
  553. REALM_ASSERT(get_type() == type_Float);
  554. return float_val;
  555. }
  556. inline float Mixed::get_float() const noexcept
  557. {
  558. return get<float>();
  559. }
  560. template <>
  561. inline const float* Mixed::get_if<float>() const noexcept
  562. {
  563. return is_type(type_Float) ? &float_val : nullptr;
  564. }
  565. template <>
  566. inline double Mixed::get<double>() const noexcept
  567. {
  568. REALM_ASSERT(get_type() == type_Double);
  569. return double_val;
  570. }
  571. inline double Mixed::get_double() const noexcept
  572. {
  573. return get<double>();
  574. }
  575. template <>
  576. inline const double* Mixed::get_if<double>() const noexcept
  577. {
  578. return is_type(type_Double) ? &double_val : nullptr;
  579. }
  580. template <>
  581. inline StringData Mixed::get<StringData>() const noexcept
  582. {
  583. if (is_null())
  584. return StringData();
  585. REALM_ASSERT(get_type() == type_String);
  586. return string_val;
  587. }
  588. inline StringData Mixed::get_string() const noexcept
  589. {
  590. return get<StringData>();
  591. }
  592. template <>
  593. inline const StringData* Mixed::get_if<StringData>() const noexcept
  594. {
  595. return is_type(type_String) ? &string_val : nullptr;
  596. }
  597. template <>
  598. inline BinaryData Mixed::get<BinaryData>() const noexcept
  599. {
  600. if (is_null())
  601. return BinaryData();
  602. if (get_type() == type_Binary) {
  603. return binary_val;
  604. }
  605. REALM_ASSERT(get_type() == type_String);
  606. return BinaryData(string_val.data(), string_val.size());
  607. }
  608. inline BinaryData Mixed::get_binary() const noexcept
  609. {
  610. return get<BinaryData>();
  611. }
  612. template <>
  613. inline const BinaryData* Mixed::get_if<BinaryData>() const noexcept
  614. {
  615. return is_type(type_Binary) ? &binary_val : nullptr;
  616. }
  617. template <>
  618. inline Timestamp Mixed::get<Timestamp>() const noexcept
  619. {
  620. REALM_ASSERT(get_type() == type_Timestamp);
  621. return date_val;
  622. }
  623. inline Timestamp Mixed::get_timestamp() const noexcept
  624. {
  625. return get<Timestamp>();
  626. }
  627. template <>
  628. inline const Timestamp* Mixed::get_if<Timestamp>() const noexcept
  629. {
  630. return is_type(type_Timestamp) ? &date_val : nullptr;
  631. }
  632. template <>
  633. inline Decimal128 Mixed::get<Decimal128>() const noexcept
  634. {
  635. REALM_ASSERT(get_type() == type_Decimal);
  636. return decimal_val;
  637. }
  638. inline Decimal128 Mixed::get_decimal() const noexcept
  639. {
  640. return get<Decimal128>();
  641. }
  642. template <>
  643. inline const Decimal128* Mixed::get_if<Decimal128>() const noexcept
  644. {
  645. return is_type(type_Decimal) ? &decimal_val : nullptr;
  646. }
  647. template <>
  648. inline ObjectId Mixed::get<ObjectId>() const noexcept
  649. {
  650. REALM_ASSERT(get_type() == type_ObjectId);
  651. return id_val;
  652. }
  653. inline ObjectId Mixed::get_object_id() const noexcept
  654. {
  655. return get<ObjectId>();
  656. }
  657. template <>
  658. inline const ObjectId* Mixed::get_if<ObjectId>() const noexcept
  659. {
  660. return is_type(type_ObjectId) ? &id_val : nullptr;
  661. }
  662. template <>
  663. inline UUID Mixed::get<UUID>() const noexcept
  664. {
  665. REALM_ASSERT(get_type() == type_UUID);
  666. return uuid_val;
  667. }
  668. inline UUID Mixed::get_uuid() const noexcept
  669. {
  670. return get<UUID>();
  671. }
  672. template <>
  673. inline const UUID* Mixed::get_if<UUID>() const noexcept
  674. {
  675. return is_type(type_UUID) ? &uuid_val : nullptr;
  676. }
  677. template <>
  678. inline ObjKey Mixed::get<ObjKey>() const noexcept
  679. {
  680. if (get_type() == type_TypedLink)
  681. return link_val.get_obj_key();
  682. REALM_ASSERT(get_type() == type_Link);
  683. return ObjKey(int_val);
  684. }
  685. template <>
  686. inline ObjLink Mixed::get<ObjLink>() const noexcept
  687. {
  688. REALM_ASSERT(get_type() == type_TypedLink);
  689. return link_val;
  690. }
  691. #if REALM_ENABLE_GEOSPATIAL
  692. template <>
  693. inline Geospatial Mixed::get<Geospatial>() const noexcept
  694. {
  695. auto type = get_type();
  696. REALM_ASSERT_EX(type == type_Geospatial, type);
  697. if (type == type_Geospatial) {
  698. return *geospatial_val;
  699. }
  700. REALM_UNREACHABLE();
  701. }
  702. #endif
  703. template <>
  704. inline Mixed Mixed::get<Mixed>() const noexcept
  705. {
  706. return *this;
  707. }
  708. inline ObjLink Mixed::get_link() const noexcept
  709. {
  710. return get<ObjLink>();
  711. }
  712. inline bool Mixed::is_null() const noexcept
  713. {
  714. return (m_type == 0);
  715. }
  716. inline bool Mixed::is_same_type(const Mixed& b) const noexcept
  717. {
  718. return (m_type == b.m_type);
  719. }
  720. inline bool Mixed::is_unresolved_link() const noexcept
  721. {
  722. if (is_null()) {
  723. return false;
  724. }
  725. else if (get_type() == type_TypedLink) {
  726. return get<ObjLink>().is_unresolved();
  727. }
  728. else if (get_type() == type_Link) {
  729. return get<ObjKey>().is_unresolved();
  730. }
  731. return false;
  732. }
  733. std::ostream& operator<<(std::ostream& out, const Mixed& m);
  734. } // namespace realm
  735. namespace std {
  736. template <>
  737. struct hash<::realm::Mixed> {
  738. inline size_t operator()(const ::realm::Mixed& m) const noexcept
  739. {
  740. return m.hash();
  741. }
  742. };
  743. } // namespace std
  744. #endif // REALM_MIXED_HPP