added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / query_conditions.hpp
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
19 #ifndef REALM_QUERY_CONDITIONS_HPP
20 #define REALM_QUERY_CONDITIONS_HPP
21
22 #include <cstdint>
23 #include <string>
24
25 #include <realm/unicode.hpp>
26 #include <realm/binary_data.hpp>
27 #include <realm/utilities.hpp>
28
29 namespace realm {
30
31 // Array::VTable only uses the first 4 conditions (enums) in an array of function pointers
32 enum { cond_Equal, cond_NotEqual, cond_Greater, cond_Less, cond_VTABLE_FINDER_COUNT, cond_None, cond_LeftNotNull };
33
34 // Quick hack to make "Queries with Integer null columns" able to compile in Visual Studio 2015 which doesn't full
35 // support sfinae
36 // (real cause hasn't been investigated yet, cannot exclude that we don't obey c++11 standard)
37 struct HackClass {
38     template <class A, class B, class C>
39     bool can_match(A, B, C)
40     {
41         REALM_ASSERT(false);
42         return false;
43     }
44     template <class A, class B, class C>
45     bool will_match(A, B, C)
46     {
47         REALM_ASSERT(false);
48         return false;
49     }
50 };
51
52 // Does v2 contain v1?
53 struct Contains : public HackClass {
54     bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const
55     {
56         return v2.contains(v1);
57     }
58     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
59     {
60         return v2.contains(v1);
61     }
62     bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const
63     {
64         return v2.contains(v1);
65     }
66     bool operator()(StringData v1, const std::array<uint8_t, 256> &charmap, StringData v2) const
67     {
68         return v2.contains(v1, charmap);
69     }
70
71     template <class A, class B>
72     bool operator()(A, B) const
73     {
74         REALM_ASSERT(false);
75         return false;
76     }
77     template <class A, class B, class C, class D>
78     bool operator()(A, B, C, D) const
79     {
80         REALM_ASSERT(false);
81         return false;
82     }
83     bool operator()(int64_t, int64_t, bool, bool) const
84     {
85         REALM_ASSERT(false);
86         return false;
87     }
88
89     static std::string description()
90     {
91         return "CONTAINS";
92     }
93
94     static const int condition = -1;
95 };
96
97 // Does v2 contain something like v1 (wildcard matching)?
98 struct Like : public HackClass {
99     bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const
100     {
101         return v2.like(v1);
102     }
103     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
104     {
105         return v2.like(v1);
106     }
107     bool operator()(BinaryData, BinaryData, bool = false, bool = false) const
108     {
109         REALM_ASSERT(false);
110         return false;
111     }
112
113     template <class A, class B>
114     bool operator()(A, B) const
115     {
116         REALM_ASSERT(false);
117         return false;
118     }
119
120     template <class A, class B, class C, class D>
121     bool operator()(A, B, C, D) const
122     {
123         REALM_ASSERT(false);
124         return false;
125     }
126
127     bool operator()(int64_t, int64_t, bool, bool) const
128     {
129         REALM_ASSERT(false);
130         return false;
131     }
132
133     static std::string description()
134     {
135         return "LIKE";
136     }
137
138     static const int condition = -1;
139 };
140
141 // Does v2 begin with v1?
142 struct BeginsWith : public HackClass {
143     bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const
144     {
145         return v2.begins_with(v1);
146     }
147     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
148     {
149         return v2.begins_with(v1);
150     }
151     bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const
152     {
153         return v2.begins_with(v1);
154     }
155
156     template <class A, class B, class C, class D>
157     bool operator()(A, B, C, D) const
158     {
159         REALM_ASSERT(false);
160         return false;
161     }
162     template <class A, class B>
163     bool operator()(A, B) const
164     {
165         REALM_ASSERT(false);
166         return false;
167     }
168
169     static std::string description()
170     {
171         return "BEGINSWITH";
172     }
173
174     static const int condition = -1;
175 };
176
177 // Does v2 end with v1?
178 struct EndsWith : public HackClass {
179     bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const
180     {
181         return v2.ends_with(v1);
182     }
183     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
184     {
185         return v2.ends_with(v1);
186     }
187     bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const
188     {
189         return v2.ends_with(v1);
190     }
191
192     template <class A, class B>
193     bool operator()(A, B) const
194     {
195         REALM_ASSERT(false);
196         return false;
197     }
198     template <class A, class B, class C, class D>
199     bool operator()(A, B, C, D) const
200     {
201         REALM_ASSERT(false);
202         return false;
203     }
204
205     static std::string description()
206     {
207         return "ENDSWITH";
208     }
209
210     static const int condition = -1;
211 };
212
213 struct Equal {
214     static const int avx = 0x00; // _CMP_EQ_OQ
215     //    bool operator()(const bool v1, const bool v2, bool v1null = false, bool v2null = false) const { return v1 ==
216     //    v2; }
217     bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const
218     {
219         return v1 == v2;
220     }
221     bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const
222     {
223         return v1 == v2;
224     }
225
226     template <class T>
227     bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
228     {
229         return (v1null && v2null) || (!v1null && !v2null && v1 == v2);
230     }
231     static const int condition = cond_Equal;
232     bool can_match(int64_t v, int64_t lbound, int64_t ubound)
233     {
234         return (v >= lbound && v <= ubound);
235     }
236     bool will_match(int64_t v, int64_t lbound, int64_t ubound)
237     {
238         return (v == 0 && ubound == 0 && lbound == 0);
239     }
240
241     static std::string description()
242     {
243         return "==";
244     }
245 };
246
247 struct NotEqual {
248     static const int avx = 0x0B; // _CMP_FALSE_OQ
249     bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const
250     {
251         return v1 != v2;
252     }
253     // bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const { return v1 != v2; }
254
255     template <class T>
256     bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
257     {
258         if (!v1null && !v2null)
259             return v1 != v2;
260
261         if (v1null && v2null)
262             return false;
263
264         return true;
265     }
266
267     static const int condition = cond_NotEqual;
268     bool can_match(int64_t v, int64_t lbound, int64_t ubound)
269     {
270         return !(v == 0 && ubound == 0 && lbound == 0);
271     }
272     bool will_match(int64_t v, int64_t lbound, int64_t ubound)
273     {
274         return (v > ubound || v < lbound);
275     }
276
277     template <class A, class B, class C, class D>
278     bool operator()(A, B, C, D) const
279     {
280         REALM_ASSERT(false);
281         return false;
282     }
283
284     static std::string description()
285     {
286         return "!=";
287     }
288 };
289
290 // Does v2 contain v1?
291 struct ContainsIns : public HackClass {
292     bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false,
293                     bool = false) const
294     {
295         if (v2.is_null() && !v1.is_null())
296             return false;
297
298         if (v1.size() == 0 && !v2.is_null())
299             return true;
300
301         return search_case_fold(v2, v1_upper, v1_lower, v1.size()) != v2.size();
302     }
303
304     // Slow version, used if caller hasn't stored an upper and lower case version
305     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
306     {
307         if (v2.is_null() && !v1.is_null())
308             return false;
309
310         if (v1.size() == 0 && !v2.is_null())
311             return true;
312
313         std::string v1_upper = case_map(v1, true, IgnoreErrors);
314         std::string v1_lower = case_map(v1, false, IgnoreErrors);
315         return search_case_fold(v2, v1_upper.c_str(), v1_lower.c_str(), v1.size()) != v2.size();
316     }
317     
318     // Case insensitive Boyer-Moore version
319     bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, const std::array<uint8_t, 256> &charmap, StringData v2) const
320     {
321         if (v2.is_null() && !v1.is_null())
322             return false;
323         
324         if (v1.size() == 0 && !v2.is_null())
325             return true;
326         
327         return contains_ins(v2, v1_upper, v1_lower, v1.size(), charmap);
328     }
329
330
331     template <class A, class B>
332     bool operator()(A, B) const
333     {
334         REALM_ASSERT(false);
335         return false;
336     }
337     template <class A, class B, class C, class D>
338     bool operator()(A, B, C, D) const
339     {
340         REALM_ASSERT(false);
341         return false;
342     }
343     bool operator()(int64_t, int64_t, bool, bool) const
344     {
345         REALM_ASSERT(false);
346         return false;
347     }
348
349     static std::string description()
350     {
351         return "CONTAINS[c]";
352     }
353
354     static const int condition = -1;
355 };
356
357 // Does v2 contain something like v1 (wildcard matching)?
358 struct LikeIns : public HackClass {
359     bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false,
360                     bool = false) const
361     {
362         if (v2.is_null() || v1.is_null()) {
363             return (v2.is_null() && v1.is_null());
364         }
365
366         return string_like_ins(v2, v1_lower, v1_upper);
367     }
368
369     // Slow version, used if caller hasn't stored an upper and lower case version
370     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
371     {
372         if (v2.is_null() || v1.is_null()) {
373             return (v2.is_null() && v1.is_null());
374         }
375
376         std::string v1_upper = case_map(v1, true, IgnoreErrors);
377         std::string v1_lower = case_map(v1, false, IgnoreErrors);
378         return string_like_ins(v2, v1_lower, v1_upper);
379     }
380
381     template <class A, class B>
382     bool operator()(A, B) const
383     {
384         REALM_ASSERT(false);
385         return false;
386     }
387     template <class A, class B, class C, class D>
388     bool operator()(A, B, C, D) const
389     {
390         REALM_ASSERT(false);
391         return false;
392     }
393     bool operator()(int64_t, int64_t, bool, bool) const
394     {
395         REALM_ASSERT(false);
396         return false;
397     }
398
399     static std::string description()
400     {
401         return "LIKE[c]";
402     }
403
404     static const int condition = -1;
405 };
406
407 // Does v2 begin with v1?
408 struct BeginsWithIns : public HackClass {
409     bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false,
410                     bool = false) const
411     {
412         if (v2.is_null() && !v1.is_null())
413             return false;
414         return v1.size() <= v2.size() && equal_case_fold(v2.prefix(v1.size()), v1_upper, v1_lower);
415     }
416
417     // Slow version, used if caller hasn't stored an upper and lower case version
418     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
419     {
420         if (v2.is_null() && !v1.is_null())
421             return false;
422
423         if (v1.size() > v2.size())
424             return false;
425         std::string v1_upper = case_map(v1, true, IgnoreErrors);
426         std::string v1_lower = case_map(v1, false, IgnoreErrors);
427         return equal_case_fold(v2.prefix(v1.size()), v1_upper.c_str(), v1_lower.c_str());
428     }
429
430     template <class A, class B>
431     bool operator()(A, B) const
432     {
433         REALM_ASSERT(false);
434         return false;
435     }
436     template <class A, class B, class C, class D>
437     bool operator()(A, B, C, D) const
438     {
439         REALM_ASSERT(false);
440         return false;
441     }
442     bool operator()(int64_t, int64_t, bool, bool) const
443     {
444         REALM_ASSERT(false);
445         return false;
446     }
447
448     static std::string description()
449     {
450         return "BEGINSWITH[c]";
451     }
452
453     static const int condition = -1;
454 };
455
456 // Does v2 end with v1?
457 struct EndsWithIns : public HackClass {
458     bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false,
459                     bool = false) const
460     {
461         if (v2.is_null() && !v1.is_null())
462             return false;
463
464         return v1.size() <= v2.size() && equal_case_fold(v2.suffix(v1.size()), v1_upper, v1_lower);
465     }
466
467     // Slow version, used if caller hasn't stored an upper and lower case version
468     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
469     {
470         if (v2.is_null() && !v1.is_null())
471             return false;
472
473         if (v1.size() > v2.size())
474             return false;
475         std::string v1_upper = case_map(v1, true, IgnoreErrors);
476         std::string v1_lower = case_map(v1, false, IgnoreErrors);
477         return equal_case_fold(v2.suffix(v1.size()), v1_upper.c_str(), v1_lower.c_str());
478     }
479
480     template <class A, class B>
481     bool operator()(A, B) const
482     {
483         REALM_ASSERT(false);
484         return false;
485     }
486     template <class A, class B, class C, class D>
487     bool operator()(A, B, C, D) const
488     {
489         REALM_ASSERT(false);
490         return false;
491     }
492     bool operator()(int64_t, int64_t, bool, bool) const
493     {
494         REALM_ASSERT(false);
495         return false;
496     }
497
498     static std::string description()
499     {
500         return "ENDSWITH[c]";
501     }
502
503     static const int condition = -1;
504 };
505
506 struct EqualIns : public HackClass {
507     bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false,
508                     bool = false) const
509     {
510         if (v1.is_null() != v2.is_null())
511             return false;
512
513         return v1.size() == v2.size() && equal_case_fold(v2, v1_upper, v1_lower);
514     }
515
516     // Slow version, used if caller hasn't stored an upper and lower case version
517     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
518     {
519         if (v1.is_null() != v2.is_null())
520             return false;
521
522         if (v1.size() != v2.size())
523             return false;
524         std::string v1_upper = case_map(v1, true, IgnoreErrors);
525         std::string v1_lower = case_map(v1, false, IgnoreErrors);
526         return equal_case_fold(v2, v1_upper.c_str(), v1_lower.c_str());
527     }
528
529     template <class A, class B>
530     bool operator()(A, B) const
531     {
532         REALM_ASSERT(false);
533         return false;
534     }
535     template <class A, class B, class C, class D>
536     bool operator()(A, B, C, D) const
537     {
538         REALM_ASSERT(false);
539         return false;
540     }
541     bool operator()(int64_t, int64_t, bool, bool) const
542     {
543         REALM_ASSERT(false);
544         return false;
545     }
546
547     static std::string description()
548     {
549         return "==[c]";
550     }
551
552     static const int condition = -1;
553 };
554
555 struct NotEqualIns : public HackClass {
556     bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false,
557                     bool = false) const
558     {
559         if (v1.is_null() != v2.is_null())
560             return true;
561         return v1.size() != v2.size() || !equal_case_fold(v2, v1_upper, v1_lower);
562     }
563
564     // Slow version, used if caller hasn't stored an upper and lower case version
565     bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
566     {
567         if (v1.is_null() != v2.is_null())
568             return true;
569
570         if (v1.size() != v2.size())
571             return true;
572         std::string v1_upper = case_map(v1, true, IgnoreErrors);
573         std::string v1_lower = case_map(v1, false, IgnoreErrors);
574         return !equal_case_fold(v2, v1_upper.c_str(), v1_lower.c_str());
575     }
576
577     template <class A, class B>
578     bool operator()(A, B) const
579     {
580         REALM_ASSERT(false);
581         return false;
582     }
583     template <class A, class B, class C, class D>
584     bool operator()(A, B, C, D) const
585     {
586         REALM_ASSERT(false);
587         return false;
588     }
589
590     static std::string description()
591     {
592         return "!=[c]";
593     }
594
595     static const int condition = -1;
596 };
597
598 struct Greater {
599     static const int avx = 0x1E; // _CMP_GT_OQ
600     template <class T>
601     bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
602     {
603         if (v1null || v2null)
604             return false;
605
606         return v1 > v2;
607     }
608     static const int condition = cond_Greater;
609     template <class A, class B, class C, class D>
610     bool operator()(A, B, C, D) const
611     {
612         REALM_ASSERT(false);
613         return false;
614     }
615
616     bool can_match(int64_t v, int64_t lbound, int64_t ubound)
617     {
618         static_cast<void>(lbound);
619         return ubound > v;
620     }
621     bool will_match(int64_t v, int64_t lbound, int64_t ubound)
622     {
623         static_cast<void>(ubound);
624         return lbound > v;
625     }
626
627     static std::string description()
628     {
629         return ">";
630     }
631 };
632
633 struct None {
634     template <class T>
635     bool operator()(const T&, const T&, bool = false, bool = false) const
636     {
637         return true;
638     }
639     static const int condition = cond_None;
640     template <class A, class B, class C, class D>
641     bool operator()(A, B, C, D) const
642     {
643         REALM_ASSERT(false);
644         return false;
645     }
646     bool can_match(int64_t v, int64_t lbound, int64_t ubound)
647     {
648         static_cast<void>(lbound);
649         static_cast<void>(ubound);
650         static_cast<void>(v);
651         return true;
652     }
653     bool will_match(int64_t v, int64_t lbound, int64_t ubound)
654     {
655         static_cast<void>(lbound);
656         static_cast<void>(ubound);
657         static_cast<void>(v);
658         return true;
659     }
660
661     static std::string description()
662     {
663         return "none";
664     }
665 };
666
667 struct NotNull {
668     template <class T>
669     bool operator()(const T&, const T&, bool v = false, bool = false) const
670     {
671         return !v;
672     }
673     static const int condition = cond_LeftNotNull;
674     template <class A, class B, class C, class D>
675     bool operator()(A, B, C, D) const
676     {
677         REALM_ASSERT(false);
678         return false;
679     }
680     bool can_match(int64_t v, int64_t lbound, int64_t ubound)
681     {
682         static_cast<void>(lbound);
683         static_cast<void>(ubound);
684         static_cast<void>(v);
685         return true;
686     }
687     bool will_match(int64_t v, int64_t lbound, int64_t ubound)
688     {
689         static_cast<void>(lbound);
690         static_cast<void>(ubound);
691         static_cast<void>(v);
692         return true;
693     }
694     static std::string description()
695     {
696         return "!= NULL";
697     }
698 };
699
700
701 struct Less {
702     static const int avx = 0x11; // _CMP_LT_OQ
703     template <class T>
704     bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
705     {
706         if (v1null || v2null)
707             return false;
708
709         return v1 < v2;
710     }
711     template <class A, class B, class C, class D>
712     bool operator()(A, B, C, D) const
713     {
714         REALM_ASSERT(false);
715         return false;
716     }
717     static const int condition = cond_Less;
718     bool can_match(int64_t v, int64_t lbound, int64_t ubound)
719     {
720         static_cast<void>(ubound);
721         return lbound < v;
722     }
723     bool will_match(int64_t v, int64_t lbound, int64_t ubound)
724     {
725         static_cast<void>(lbound);
726         return ubound < v;
727     }
728     static std::string description()
729     {
730         return "<";
731     }
732 };
733
734 struct LessEqual : public HackClass {
735     static const int avx = 0x12; // _CMP_LE_OQ
736     template <class T>
737     bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
738     {
739         if (v1null && v2null)
740             return true;
741
742         return (!v1null && !v2null && v1 <= v2);
743     }
744     template <class A, class B, class C, class D>
745     bool operator()(A, B, C, D) const
746     {
747         REALM_ASSERT(false);
748         return false;
749     }
750     static std::string description()
751     {
752         return "<=";
753     }
754     static const int condition = -1;
755 };
756
757 struct GreaterEqual : public HackClass {
758     static const int avx = 0x1D; // _CMP_GE_OQ
759     template <class T>
760     bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
761     {
762         if (v1null && v2null)
763             return true;
764
765         return (!v1null && !v2null && v1 >= v2);
766     }
767     template <class A, class B, class C, class D>
768     bool operator()(A, B, C, D) const
769     {
770         REALM_ASSERT(false);
771         return false;
772     }
773     static std::string description()
774     {
775         return ">=";
776     }
777     static const int condition = -1;
778 };
779
780
781 // CompareLess is a temporary hack to have a generalized way to compare any realm types. Todo, enable correct <
782 // operator of StringData (currently gives circular header dependency with utf8.hpp)
783 template <class T>
784 struct CompareLess {
785     static bool compare(T v1, T v2, bool = false, bool = false)
786     {
787         return v1 < v2;
788     }
789 };
790 template <>
791 struct CompareLess<StringData> {
792     static bool compare(StringData v1, StringData v2, bool = false, bool = false)
793     {
794         bool ret = utf8_compare(v1.data(), v2.data());
795         return ret;
796     }
797 };
798
799 } // namespace realm
800
801 #endif // REALM_QUERY_CONDITIONS_HPP