mixed.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  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. #include <realm/string_data.hpp>
  27. #include <realm/timestamp.hpp>
  28. #include <realm/decimal128.hpp>
  29. #include <realm/object_id.hpp>
  30. #include <realm/uuid.hpp>
  31. #include <realm/util/assert.hpp>
  32. #include <realm/utilities.hpp>
  33. namespace realm {
  34. /// This class represents a polymorphic Realm value.
  35. ///
  36. /// At any particular moment an instance of this class stores a
  37. /// definite value of a definite type. If, for instance, that is an
  38. /// integer value, you may call get<int64_t>() to extract that value. You
  39. /// may call get_type() to discover what type of value is currently
  40. /// stored. Calling get<int64_t>() on an instance that does not store an
  41. /// integer, has undefined behavior, and likewise for all the other
  42. /// types that can be stored.
  43. ///
  44. /// It is crucial to understand that the act of extracting a value of
  45. /// a particular type requires definite knowledge about the stored
  46. /// type. Calling a getter method for any particular type, that is not
  47. /// the same type as the stored value, has undefined behavior.
  48. ///
  49. /// While values of numeric types are contained directly in a Mixed
  50. /// instance, character and binary data are merely referenced. A Mixed
  51. /// instance never owns the referenced data, nor does it in any other
  52. /// way attempt to manage its lifetime.
  53. ///
  54. /// For compatibility with C style strings, when a string (character
  55. /// data) is stored in a Realm database, it is always followed by a
  56. /// terminating null character. This is also true when strings are
  57. /// stored in a mixed type column. This means that in the following
  58. /// code, if the 'mixed' value of the 8th row stores a string, then \c
  59. /// c_str will always point to a null-terminated string:
  60. ///
  61. /// \code{.cpp}
  62. ///
  63. /// const char* c_str = my_table[7].mixed.data(); // Always null-terminated
  64. ///
  65. /// \endcode
  66. ///
  67. /// Note that this assumption does not hold in general for strings in
  68. /// instances of Mixed. Indeed there is nothing stopping you from
  69. /// constructing a new Mixed instance that refers to a string without
  70. /// a terminating null character.
  71. ///
  72. /// At the present time no soultion has been found that would allow
  73. /// for a Mixed instance to directly store a reference to a table. The
  74. /// problem is roughly as follows: From most points of view, the
  75. /// desirable thing to do, would be to store the table reference in a
  76. /// Mixed instance as a plain pointer without any ownership
  77. /// semantics. This would have no negative impact on the performance
  78. /// of copying and destroying Mixed instances, and it would serve just
  79. /// fine for passing a table as argument when setting the value of an
  80. /// entry in a mixed column. In that case a copy of the referenced
  81. /// table would be inserted into the mixed column.
  82. ///
  83. /// On the other hand, when retrieving a table reference from a mixed
  84. /// column, storing it as a plain pointer in a Mixed instance is no
  85. /// longer an acceptable option. The complex rules for managing the
  86. /// lifetime of a Table instance, that represents a subtable,
  87. /// necessitates the use of a "smart pointer" such as
  88. /// TableRef. Enhancing the Mixed class to be able to act as a
  89. /// TableRef would be possible, but would also lead to several new
  90. /// problems. One problem is the risk of a Mixed instance outliving a
  91. /// stack allocated Table instance that it references. This would be a
  92. /// fatal error. Another problem is the impact that the nontrivial
  93. /// table reference has on the performance of copying and destroying
  94. /// Mixed instances.
  95. ///
  96. /// \sa StringData
  97. class Mixed {
  98. public:
  99. Mixed() noexcept
  100. : m_type(0)
  101. {
  102. }
  103. Mixed(util::None) noexcept
  104. : Mixed()
  105. {
  106. }
  107. Mixed(realm::null) noexcept
  108. : Mixed()
  109. {
  110. }
  111. Mixed(int i) noexcept
  112. : Mixed(int64_t(i))
  113. {
  114. }
  115. Mixed(int64_t) noexcept;
  116. Mixed(bool) noexcept;
  117. Mixed(float) noexcept;
  118. Mixed(double) noexcept;
  119. Mixed(util::Optional<int64_t>) noexcept;
  120. Mixed(util::Optional<bool>) noexcept;
  121. Mixed(util::Optional<float>) noexcept;
  122. Mixed(util::Optional<double>) noexcept;
  123. Mixed(StringData) noexcept;
  124. Mixed(BinaryData) noexcept;
  125. Mixed(Timestamp) noexcept;
  126. Mixed(Decimal128);
  127. Mixed(ObjectId) noexcept;
  128. Mixed(util::Optional<ObjectId>) noexcept;
  129. Mixed(ObjKey) noexcept;
  130. Mixed(ObjLink) noexcept;
  131. Mixed(UUID) noexcept;
  132. Mixed(util::Optional<UUID>) noexcept;
  133. Mixed(const Obj&) noexcept;
  134. // These are shortcuts for Mixed(StringData(c_str)), and are
  135. // needed to avoid unwanted implicit conversion of char* to bool.
  136. Mixed(char* c_str) noexcept
  137. : Mixed(StringData(c_str))
  138. {
  139. }
  140. Mixed(const char* c_str) noexcept
  141. : Mixed(StringData(c_str))
  142. {
  143. }
  144. Mixed(const std::string& s) noexcept
  145. : Mixed(StringData(s))
  146. {
  147. }
  148. ~Mixed() noexcept
  149. {
  150. }
  151. DataType get_type() const noexcept
  152. {
  153. REALM_ASSERT(m_type);
  154. return DataType(m_type - 1);
  155. }
  156. static bool types_are_comparable(const Mixed& l, const Mixed& r);
  157. static bool data_types_are_comparable(DataType l_type, DataType r_type);
  158. template <class T>
  159. T get() const noexcept;
  160. template <class T>
  161. T export_to_type() const noexcept;
  162. // These functions are kept to be backwards compatible
  163. int64_t get_int() const;
  164. bool get_bool() const;
  165. float get_float() const;
  166. double get_double() const;
  167. StringData get_string() const;
  168. BinaryData get_binary() const;
  169. Timestamp get_timestamp() const;
  170. Decimal128 get_decimal() const;
  171. ObjectId get_object_id() const;
  172. UUID get_uuid() const;
  173. ObjLink get_link() const;
  174. bool is_null() const;
  175. bool is_unresolved_link() const;
  176. int compare(const Mixed& b) const;
  177. bool operator==(const Mixed& other) const
  178. {
  179. return compare(other) == 0;
  180. }
  181. bool operator!=(const Mixed& other) const
  182. {
  183. return compare(other) != 0;
  184. }
  185. bool operator<(const Mixed& other) const
  186. {
  187. return compare(other) < 0;
  188. }
  189. bool operator>(const Mixed& other) const
  190. {
  191. return compare(other) > 0;
  192. }
  193. bool operator<=(const Mixed& other) const
  194. {
  195. return compare(other) <= 0;
  196. }
  197. bool operator>=(const Mixed& other) const
  198. {
  199. return compare(other) >= 0;
  200. }
  201. size_t hash() const;
  202. protected:
  203. friend std::ostream& operator<<(std::ostream& out, const Mixed& m);
  204. uint32_t m_type;
  205. union {
  206. int64_t int_val;
  207. bool bool_val;
  208. float float_val;
  209. double double_val;
  210. StringData string_val;
  211. BinaryData binary_val;
  212. Timestamp date_val;
  213. ObjectId id_val;
  214. Decimal128 decimal_val;
  215. ObjLink link_val;
  216. UUID uuid_val;
  217. };
  218. };
  219. // Implementation:
  220. inline Mixed::Mixed(int64_t v) noexcept
  221. {
  222. m_type = int(type_Int) + 1;
  223. int_val = v;
  224. }
  225. inline Mixed::Mixed(bool v) noexcept
  226. {
  227. m_type = int(type_Bool) + 1;
  228. bool_val = v;
  229. }
  230. inline Mixed::Mixed(float v) noexcept
  231. {
  232. if (null::is_null_float(v)) {
  233. m_type = 0;
  234. }
  235. else {
  236. m_type = int(type_Float) + 1;
  237. float_val = v;
  238. }
  239. }
  240. inline Mixed::Mixed(double v) noexcept
  241. {
  242. if (null::is_null_float(v)) {
  243. m_type = 0;
  244. }
  245. else {
  246. m_type = int(type_Double) + 1;
  247. double_val = v;
  248. }
  249. }
  250. inline Mixed::Mixed(util::Optional<int64_t> v) noexcept
  251. {
  252. if (v) {
  253. m_type = int(type_Int) + 1;
  254. int_val = *v;
  255. }
  256. else {
  257. m_type = 0;
  258. }
  259. }
  260. inline Mixed::Mixed(util::Optional<bool> v) noexcept
  261. {
  262. if (v) {
  263. m_type = int(type_Bool) + 1;
  264. bool_val = *v;
  265. }
  266. else {
  267. m_type = 0;
  268. }
  269. }
  270. inline Mixed::Mixed(util::Optional<float> v) noexcept
  271. {
  272. if (v && !null::is_null_float(*v)) {
  273. m_type = int(type_Float) + 1;
  274. float_val = *v;
  275. }
  276. else {
  277. m_type = 0;
  278. }
  279. }
  280. inline Mixed::Mixed(util::Optional<double> v) noexcept
  281. {
  282. if (v && !null::is_null_float(*v)) {
  283. m_type = int(type_Double) + 1;
  284. double_val = *v;
  285. }
  286. else {
  287. m_type = 0;
  288. }
  289. }
  290. inline Mixed::Mixed(util::Optional<ObjectId> v) noexcept
  291. {
  292. if (v) {
  293. m_type = int(type_ObjectId) + 1;
  294. id_val = *v;
  295. }
  296. else {
  297. m_type = 0;
  298. }
  299. }
  300. inline Mixed::Mixed(util::Optional<UUID> v) noexcept
  301. {
  302. if (v) {
  303. m_type = int(type_UUID) + 1;
  304. uuid_val = *v;
  305. }
  306. else {
  307. m_type = 0;
  308. }
  309. }
  310. inline Mixed::Mixed(StringData v) noexcept
  311. {
  312. if (!v.is_null()) {
  313. m_type = int(type_String) + 1;
  314. string_val = v;
  315. }
  316. else {
  317. m_type = 0;
  318. }
  319. }
  320. inline Mixed::Mixed(BinaryData v) noexcept
  321. {
  322. if (!v.is_null()) {
  323. m_type = int(type_Binary) + 1;
  324. binary_val = v;
  325. }
  326. else {
  327. m_type = 0;
  328. }
  329. }
  330. inline Mixed::Mixed(Timestamp v) noexcept
  331. {
  332. if (!v.is_null()) {
  333. m_type = int(type_Timestamp) + 1;
  334. date_val = v;
  335. }
  336. else {
  337. m_type = 0;
  338. }
  339. }
  340. inline Mixed::Mixed(Decimal128 v)
  341. {
  342. if (!v.is_null()) {
  343. m_type = int(type_Decimal) + 1;
  344. decimal_val = v;
  345. }
  346. else {
  347. m_type = 0;
  348. }
  349. }
  350. inline Mixed::Mixed(ObjectId v) noexcept
  351. {
  352. m_type = int(type_ObjectId) + 1;
  353. id_val = v;
  354. }
  355. inline Mixed::Mixed(UUID v) noexcept
  356. {
  357. m_type = int(type_UUID) + 1;
  358. uuid_val = v;
  359. }
  360. inline Mixed::Mixed(ObjKey v) noexcept
  361. {
  362. if (v) {
  363. m_type = int(type_Link) + 1;
  364. int_val = v.value;
  365. }
  366. else {
  367. m_type = 0;
  368. }
  369. }
  370. inline Mixed::Mixed(ObjLink v) noexcept
  371. {
  372. if (v) {
  373. m_type = int(type_TypedLink) + 1;
  374. link_val = v;
  375. }
  376. else {
  377. m_type = 0;
  378. }
  379. }
  380. template <>
  381. inline null Mixed::get<null>() const noexcept
  382. {
  383. REALM_ASSERT(m_type == 0);
  384. return {};
  385. }
  386. template <>
  387. inline int64_t Mixed::get<int64_t>() const noexcept
  388. {
  389. REALM_ASSERT(get_type() == type_Int);
  390. return int_val;
  391. }
  392. template <>
  393. inline int Mixed::get<int>() const noexcept
  394. {
  395. REALM_ASSERT(get_type() == type_Int);
  396. return int(int_val);
  397. }
  398. inline int64_t Mixed::get_int() const
  399. {
  400. return get<int64_t>();
  401. }
  402. template <>
  403. inline bool Mixed::get<bool>() const noexcept
  404. {
  405. REALM_ASSERT(get_type() == type_Bool);
  406. return bool_val;
  407. }
  408. inline bool Mixed::get_bool() const
  409. {
  410. return get<bool>();
  411. }
  412. template <>
  413. inline float Mixed::get<float>() const noexcept
  414. {
  415. REALM_ASSERT(get_type() == type_Float);
  416. return float_val;
  417. }
  418. inline float Mixed::get_float() const
  419. {
  420. return get<float>();
  421. }
  422. template <>
  423. inline double Mixed::get<double>() const noexcept
  424. {
  425. REALM_ASSERT(get_type() == type_Double);
  426. return double_val;
  427. }
  428. inline double Mixed::get_double() const
  429. {
  430. return get<double>();
  431. }
  432. template <>
  433. inline StringData Mixed::get<StringData>() const noexcept
  434. {
  435. if (is_null())
  436. return StringData();
  437. REALM_ASSERT(get_type() == type_String);
  438. return string_val;
  439. }
  440. inline StringData Mixed::get_string() const
  441. {
  442. return get<StringData>();
  443. }
  444. template <>
  445. inline BinaryData Mixed::get<BinaryData>() const noexcept
  446. {
  447. if (is_null())
  448. return BinaryData();
  449. if (get_type() == type_Binary) {
  450. return binary_val;
  451. }
  452. REALM_ASSERT(get_type() == type_String);
  453. return BinaryData(string_val.data(), string_val.size());
  454. }
  455. inline BinaryData Mixed::get_binary() const
  456. {
  457. return get<BinaryData>();
  458. }
  459. template <>
  460. inline Timestamp Mixed::get<Timestamp>() const noexcept
  461. {
  462. REALM_ASSERT(get_type() == type_Timestamp);
  463. return date_val;
  464. }
  465. inline Timestamp Mixed::get_timestamp() const
  466. {
  467. return get<Timestamp>();
  468. }
  469. template <>
  470. inline Decimal128 Mixed::get<Decimal128>() const noexcept
  471. {
  472. REALM_ASSERT(get_type() == type_Decimal);
  473. return decimal_val;
  474. }
  475. inline Decimal128 Mixed::get_decimal() const
  476. {
  477. return get<Decimal128>();
  478. }
  479. template <>
  480. inline ObjectId Mixed::get<ObjectId>() const noexcept
  481. {
  482. REALM_ASSERT(get_type() == type_ObjectId);
  483. return id_val;
  484. }
  485. inline ObjectId Mixed::get_object_id() const
  486. {
  487. return get<ObjectId>();
  488. }
  489. template <>
  490. inline UUID Mixed::get<UUID>() const noexcept
  491. {
  492. REALM_ASSERT(get_type() == type_UUID);
  493. return uuid_val;
  494. }
  495. inline UUID Mixed::get_uuid() const
  496. {
  497. return get<UUID>();
  498. }
  499. template <>
  500. inline ObjKey Mixed::get<ObjKey>() const noexcept
  501. {
  502. REALM_ASSERT(get_type() == type_Link);
  503. return ObjKey(int_val);
  504. }
  505. template <>
  506. inline ObjLink Mixed::get<ObjLink>() const noexcept
  507. {
  508. REALM_ASSERT(get_type() == type_TypedLink);
  509. return link_val;
  510. }
  511. template <>
  512. inline Mixed Mixed::get<Mixed>() const noexcept
  513. {
  514. return *this;
  515. }
  516. inline ObjLink Mixed::get_link() const
  517. {
  518. return get<ObjLink>();
  519. }
  520. inline bool Mixed::is_null() const
  521. {
  522. return (m_type == 0);
  523. }
  524. inline bool Mixed::is_unresolved_link() const
  525. {
  526. if (is_null()) {
  527. return false;
  528. }
  529. else if (get_type() == type_TypedLink) {
  530. return get<ObjLink>().is_unresolved();
  531. }
  532. else if (get_type() == type_Link) {
  533. return get<ObjKey>().is_unresolved();
  534. }
  535. return false;
  536. }
  537. std::ostream& operator<<(std::ostream& out, const Mixed& m);
  538. } // namespace realm
  539. #endif // REALM_MIXED_HPP