RLMUtil.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2014 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. #import <Realm/RLMConstants.h>
  19. #import <Realm/RLMSwiftValueStorage.h>
  20. #import <Realm/RLMValue.h>
  21. #import <realm/array.hpp>
  22. #import <realm/binary_data.hpp>
  23. #import <realm/object-store/object.hpp>
  24. #import <realm/string_data.hpp>
  25. #import <realm/timestamp.hpp>
  26. #import <realm/util/file.hpp>
  27. #import <objc/runtime.h>
  28. #import <os/lock.h>
  29. namespace realm {
  30. class Decimal128;
  31. class Exception;
  32. class Mixed;
  33. }
  34. class RLMClassInfo;
  35. @class RLMObjectSchema;
  36. @class RLMProperty;
  37. __attribute__((format(NSString, 1, 2)))
  38. NSException *RLMException(NSString *fmt, ...);
  39. NSException *RLMException(std::exception const& exception);
  40. NSException *RLMException(realm::Exception const& exception);
  41. void RLMSetErrorOrThrow(NSError *error, NSError **outError);
  42. RLM_HIDDEN_BEGIN
  43. // returns if the object can be inserted as the given type
  44. BOOL RLMIsObjectValidForProperty(id obj, RLMProperty *prop);
  45. // throw an exception if the object is not a valid value for the property
  46. void RLMValidateValueForProperty(id obj, RLMObjectSchema *objectSchema,
  47. RLMProperty *prop, bool validateObjects=false);
  48. id RLMValidateValue(id value, RLMPropertyType type, bool optional, bool collection,
  49. NSString *objectClassName);
  50. void RLMThrowTypeError(id obj, RLMObjectSchema *objectSchema, RLMProperty *prop);
  51. // gets default values for the given schema (+defaultPropertyValues)
  52. // merges with native property defaults if Swift class
  53. NSDictionary *RLMDefaultValuesForObjectSchema(RLMObjectSchema *objectSchema);
  54. BOOL RLMIsDebuggerAttached();
  55. BOOL RLMIsRunningInPlayground();
  56. // C version of isKindOfClass
  57. static inline BOOL RLMIsKindOfClass(Class class1, Class class2) {
  58. while (class1) {
  59. if (class1 == class2) return YES;
  60. class1 = class_getSuperclass(class1);
  61. }
  62. return NO;
  63. }
  64. template<typename T>
  65. static inline T *RLMDynamicCast(__unsafe_unretained id obj) {
  66. if ([obj isKindOfClass:[T class]]) {
  67. return obj;
  68. }
  69. return nil;
  70. }
  71. static inline id RLMCoerceToNil(__unsafe_unretained id obj) {
  72. if (static_cast<id>(obj) == NSNull.null) {
  73. return nil;
  74. }
  75. else if (__unsafe_unretained auto optional = RLMDynamicCast<RLMSwiftValueStorage>(obj)) {
  76. return RLMCoerceToNil(RLMGetSwiftValueStorage(optional));
  77. }
  78. return obj;
  79. }
  80. template<typename T>
  81. static inline T RLMCoerceToNil(__unsafe_unretained T obj) {
  82. return RLMCoerceToNil(static_cast<id>(obj));
  83. }
  84. id<NSFastEnumeration> RLMAsFastEnumeration(id obj);
  85. id RLMBridgeSwiftValue(id obj);
  86. bool RLMIsSwiftObjectClass(Class cls);
  87. // String conversion utilities
  88. static inline NSString *RLMStringDataToNSString(realm::StringData stringData) {
  89. static_assert(sizeof(NSUInteger) >= sizeof(size_t),
  90. "Need runtime overflow check for size_t to NSUInteger conversion");
  91. if (stringData.is_null()) {
  92. return nil;
  93. }
  94. else {
  95. return [[NSString alloc] initWithBytes:stringData.data()
  96. length:stringData.size()
  97. encoding:NSUTF8StringEncoding];
  98. }
  99. }
  100. static inline NSString *RLMStringViewToNSString(std::string_view stringView) {
  101. if (stringView.size() == 0) {
  102. return nil;
  103. }
  104. return [[NSString alloc] initWithBytes:stringView.data()
  105. length:stringView.size()
  106. encoding:NSUTF8StringEncoding];
  107. }
  108. static inline realm::StringData RLMStringDataWithNSString(__unsafe_unretained NSString *const string) {
  109. static_assert(sizeof(size_t) >= sizeof(NSUInteger),
  110. "Need runtime overflow check for NSUInteger to size_t conversion");
  111. return realm::StringData(string.UTF8String,
  112. [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
  113. }
  114. // Binary conversion utilities
  115. static inline NSData *RLMBinaryDataToNSData(realm::BinaryData binaryData) {
  116. return binaryData ? [NSData dataWithBytes:binaryData.data() length:binaryData.size()] : nil;
  117. }
  118. static inline realm::BinaryData RLMBinaryDataForNSData(__unsafe_unretained NSData *const data) {
  119. // this is necessary to ensure that the empty NSData isn't treated by core as the null realm::BinaryData
  120. // because data.bytes == 0 when data.length == 0
  121. // the casting bit ensures that we create a data with a non-null pointer
  122. auto bytes = static_cast<const char *>(data.bytes) ?: static_cast<char *>((__bridge void *)data);
  123. return realm::BinaryData(bytes, data.length);
  124. }
  125. // Date conversion utilities
  126. // These use the reference date and shift the seconds rather than just getting
  127. // the time interval since the epoch directly to avoid losing sub-second precision
  128. static inline NSDate *RLMTimestampToNSDate(realm::Timestamp ts) NS_RETURNS_RETAINED {
  129. if (ts.is_null())
  130. return nil;
  131. auto timeInterval = ts.get_seconds() - NSTimeIntervalSince1970 + ts.get_nanoseconds() / 1'000'000'000.0;
  132. return [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:timeInterval];
  133. }
  134. static inline realm::Timestamp RLMTimestampForNSDate(__unsafe_unretained NSDate *const date) {
  135. if (!date)
  136. return {};
  137. auto timeInterval = date.timeIntervalSinceReferenceDate;
  138. if (isnan(timeInterval))
  139. return {0, 0}; // Arbitrary choice
  140. // Clamp dates that we can't represent as a Timestamp to the maximum value
  141. if (timeInterval >= std::numeric_limits<int64_t>::max() - NSTimeIntervalSince1970)
  142. return {std::numeric_limits<int64_t>::max(), 1'000'000'000 - 1};
  143. if (timeInterval - NSTimeIntervalSince1970 < std::numeric_limits<int64_t>::min())
  144. return {std::numeric_limits<int64_t>::min(), -1'000'000'000 + 1};
  145. auto seconds = static_cast<int64_t>(timeInterval);
  146. auto nanoseconds = static_cast<int32_t>((timeInterval - seconds) * 1'000'000'000.0);
  147. seconds += static_cast<int64_t>(NSTimeIntervalSince1970);
  148. // Seconds and nanoseconds have to have the same sign
  149. if (nanoseconds < 0 && seconds > 0) {
  150. nanoseconds += 1'000'000'000;
  151. --seconds;
  152. }
  153. return {seconds, nanoseconds};
  154. }
  155. static inline NSUInteger RLMConvertNotFound(size_t index) {
  156. return index == realm::not_found ? NSNotFound : index;
  157. }
  158. static inline void RLMNSStringToStdString(std::string &out, NSString *in) {
  159. if (!in)
  160. return;
  161. out.resize([in maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
  162. if (out.empty()) {
  163. return;
  164. }
  165. NSUInteger size = out.size();
  166. [in getBytes:&out[0]
  167. maxLength:size
  168. usedLength:&size
  169. encoding:NSUTF8StringEncoding
  170. options:0 range:{0, in.length} remainingRange:nullptr];
  171. out.resize(size);
  172. }
  173. realm::Mixed RLMObjcToMixed(__unsafe_unretained id value,
  174. __unsafe_unretained RLMRealm *realm=nil,
  175. realm::CreatePolicy createPolicy={});
  176. id RLMMixedToObjc(realm::Mixed const& value,
  177. __unsafe_unretained RLMRealm *realm=nil,
  178. RLMClassInfo *classInfo=nullptr);
  179. realm::Decimal128 RLMObjcToDecimal128(id value);
  180. realm::UUID RLMObjcToUUID(__unsafe_unretained id const value);
  181. // Given a bundle identifier, return the base directory on the disk within which Realm database and support files should
  182. // be stored.
  183. FOUNDATION_EXTERN RLM_VISIBLE
  184. NSString *RLMDefaultDirectoryForBundleIdentifier(NSString *bundleIdentifier);
  185. // Get a NSDateFormatter for ISO8601-formatted strings
  186. NSDateFormatter *RLMISO8601Formatter();
  187. template<typename Fn>
  188. static auto RLMTranslateError(Fn&& fn) {
  189. try {
  190. return fn();
  191. }
  192. catch (std::exception const& e) {
  193. @throw RLMException(e);
  194. }
  195. }
  196. static inline bool numberIsInteger(__unsafe_unretained NSNumber *const obj) {
  197. char data_type = [obj objCType][0];
  198. return data_type == *@encode(bool) ||
  199. data_type == *@encode(char) ||
  200. data_type == *@encode(short) ||
  201. data_type == *@encode(int) ||
  202. data_type == *@encode(long) ||
  203. data_type == *@encode(long long) ||
  204. data_type == *@encode(unsigned short) ||
  205. data_type == *@encode(unsigned int) ||
  206. data_type == *@encode(unsigned long) ||
  207. data_type == *@encode(unsigned long long);
  208. }
  209. static inline bool numberIsBool(__unsafe_unretained NSNumber *const obj) {
  210. // @encode(BOOL) is 'B' on iOS 64 and 'c'
  211. // objcType is always 'c'. Therefore compare to "c".
  212. if ([obj objCType][0] == 'c') {
  213. return true;
  214. }
  215. if (numberIsInteger(obj)) {
  216. int value = [obj intValue];
  217. return value == 0 || value == 1;
  218. }
  219. return false;
  220. }
  221. static inline bool numberIsFloat(__unsafe_unretained NSNumber *const obj) {
  222. char data_type = [obj objCType][0];
  223. return data_type == *@encode(float) ||
  224. data_type == *@encode(short) ||
  225. data_type == *@encode(int) ||
  226. data_type == *@encode(long) ||
  227. data_type == *@encode(long long) ||
  228. data_type == *@encode(unsigned short) ||
  229. data_type == *@encode(unsigned int) ||
  230. data_type == *@encode(unsigned long) ||
  231. data_type == *@encode(unsigned long long) ||
  232. // A double is like float if it fits within float bounds or is NaN.
  233. (data_type == *@encode(double) && (ABS([obj doubleValue]) <= FLT_MAX || isnan([obj doubleValue])));
  234. }
  235. static inline bool numberIsDouble(__unsafe_unretained NSNumber *const obj) {
  236. char data_type = [obj objCType][0];
  237. return data_type == *@encode(double) ||
  238. data_type == *@encode(float) ||
  239. data_type == *@encode(short) ||
  240. data_type == *@encode(int) ||
  241. data_type == *@encode(long) ||
  242. data_type == *@encode(long long) ||
  243. data_type == *@encode(unsigned short) ||
  244. data_type == *@encode(unsigned int) ||
  245. data_type == *@encode(unsigned long) ||
  246. data_type == *@encode(unsigned long long);
  247. }
  248. class RLMUnfairMutex {
  249. public:
  250. RLMUnfairMutex() = default;
  251. void lock() noexcept {
  252. os_unfair_lock_lock(&_lock);
  253. }
  254. bool try_lock() noexcept {
  255. return os_unfair_lock_trylock(&_lock);
  256. }
  257. void unlock() noexcept {
  258. os_unfair_lock_unlock(&_lock);
  259. }
  260. private:
  261. os_unfair_lock _lock = OS_UNFAIR_LOCK_INIT;
  262. RLMUnfairMutex(RLMUnfairMutex const&) = delete;
  263. RLMUnfairMutex& operator=(RLMUnfairMutex const&) = delete;
  264. };
  265. RLM_HIDDEN_END