1 /*************************************************************************
3 * Copyright 2016 Realm Inc.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 **************************************************************************/
19 #ifndef REALM_QUERY_CONDITIONS_HPP
20 #define REALM_QUERY_CONDITIONS_HPP
25 #include <realm/unicode.hpp>
26 #include <realm/binary_data.hpp>
27 #include <realm/utilities.hpp>
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 };
34 // Quick hack to make "Queries with Integer null columns" able to compile in Visual Studio 2015 which doesn't full
36 // (real cause hasn't been investigated yet, cannot exclude that we don't obey c++11 standard)
38 template <class A, class B, class C>
39 bool can_match(A, B, C)
44 template <class A, class B, class C>
45 bool will_match(A, B, C)
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
56 return v2.contains(v1);
58 bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
60 return v2.contains(v1);
62 bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const
64 return v2.contains(v1);
66 bool operator()(StringData v1, const std::array<uint8_t, 256> &charmap, StringData v2) const
68 return v2.contains(v1, charmap);
71 template <class A, class B>
72 bool operator()(A, B) const
77 template <class A, class B, class C, class D>
78 bool operator()(A, B, C, D) const
83 bool operator()(int64_t, int64_t, bool, bool) const
89 static std::string description()
94 static const int condition = -1;
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
103 bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
107 bool operator()(BinaryData, BinaryData, bool = false, bool = false) const
113 template <class A, class B>
114 bool operator()(A, B) const
120 template <class A, class B, class C, class D>
121 bool operator()(A, B, C, D) const
127 bool operator()(int64_t, int64_t, bool, bool) const
133 static std::string description()
138 static const int condition = -1;
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
145 return v2.begins_with(v1);
147 bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
149 return v2.begins_with(v1);
151 bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const
153 return v2.begins_with(v1);
156 template <class A, class B, class C, class D>
157 bool operator()(A, B, C, D) const
162 template <class A, class B>
163 bool operator()(A, B) const
169 static std::string description()
174 static const int condition = -1;
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
181 return v2.ends_with(v1);
183 bool operator()(StringData v1, StringData v2, bool = false, bool = false) const
185 return v2.ends_with(v1);
187 bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const
189 return v2.ends_with(v1);
192 template <class A, class B>
193 bool operator()(A, B) const
198 template <class A, class B, class C, class D>
199 bool operator()(A, B, C, D) const
205 static std::string description()
210 static const int condition = -1;
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 ==
217 bool operator()(StringData v1, const char*, const char*, StringData v2, bool = false, bool = false) const
221 bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const
227 bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
229 return (v1null && v2null) || (!v1null && !v2null && v1 == v2);
231 static const int condition = cond_Equal;
232 bool can_match(int64_t v, int64_t lbound, int64_t ubound)
234 return (v >= lbound && v <= ubound);
236 bool will_match(int64_t v, int64_t lbound, int64_t ubound)
238 return (v == 0 && ubound == 0 && lbound == 0);
241 static std::string description()
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
253 // bool operator()(BinaryData v1, BinaryData v2, bool = false, bool = false) const { return v1 != v2; }
256 bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
258 if (!v1null && !v2null)
261 if (v1null && v2null)
267 static const int condition = cond_NotEqual;
268 bool can_match(int64_t v, int64_t lbound, int64_t ubound)
270 return !(v == 0 && ubound == 0 && lbound == 0);
272 bool will_match(int64_t v, int64_t lbound, int64_t ubound)
274 return (v > ubound || v < lbound);
277 template <class A, class B, class C, class D>
278 bool operator()(A, B, C, D) const
284 static std::string description()
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,
295 if (v2.is_null() && !v1.is_null())
298 if (v1.size() == 0 && !v2.is_null())
301 return search_case_fold(v2, v1_upper, v1_lower, v1.size()) != v2.size();
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
307 if (v2.is_null() && !v1.is_null())
310 if (v1.size() == 0 && !v2.is_null())
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();
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
321 if (v2.is_null() && !v1.is_null())
324 if (v1.size() == 0 && !v2.is_null())
327 return contains_ins(v2, v1_upper, v1_lower, v1.size(), charmap);
331 template <class A, class B>
332 bool operator()(A, B) const
337 template <class A, class B, class C, class D>
338 bool operator()(A, B, C, D) const
343 bool operator()(int64_t, int64_t, bool, bool) const
349 static std::string description()
351 return "CONTAINS[c]";
354 static const int condition = -1;
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,
362 if (v2.is_null() || v1.is_null()) {
363 return (v2.is_null() && v1.is_null());
366 return string_like_ins(v2, v1_lower, v1_upper);
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
372 if (v2.is_null() || v1.is_null()) {
373 return (v2.is_null() && v1.is_null());
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);
381 template <class A, class B>
382 bool operator()(A, B) const
387 template <class A, class B, class C, class D>
388 bool operator()(A, B, C, D) const
393 bool operator()(int64_t, int64_t, bool, bool) const
399 static std::string description()
404 static const int condition = -1;
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,
412 if (v2.is_null() && !v1.is_null())
414 return v1.size() <= v2.size() && equal_case_fold(v2.prefix(v1.size()), v1_upper, v1_lower);
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
420 if (v2.is_null() && !v1.is_null())
423 if (v1.size() > v2.size())
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());
430 template <class A, class B>
431 bool operator()(A, B) const
436 template <class A, class B, class C, class D>
437 bool operator()(A, B, C, D) const
442 bool operator()(int64_t, int64_t, bool, bool) const
448 static std::string description()
450 return "BEGINSWITH[c]";
453 static const int condition = -1;
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,
461 if (v2.is_null() && !v1.is_null())
464 return v1.size() <= v2.size() && equal_case_fold(v2.suffix(v1.size()), v1_upper, v1_lower);
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
470 if (v2.is_null() && !v1.is_null())
473 if (v1.size() > v2.size())
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());
480 template <class A, class B>
481 bool operator()(A, B) const
486 template <class A, class B, class C, class D>
487 bool operator()(A, B, C, D) const
492 bool operator()(int64_t, int64_t, bool, bool) const
498 static std::string description()
500 return "ENDSWITH[c]";
503 static const int condition = -1;
506 struct EqualIns : public HackClass {
507 bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false,
510 if (v1.is_null() != v2.is_null())
513 return v1.size() == v2.size() && equal_case_fold(v2, v1_upper, v1_lower);
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
519 if (v1.is_null() != v2.is_null())
522 if (v1.size() != v2.size())
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());
529 template <class A, class B>
530 bool operator()(A, B) const
535 template <class A, class B, class C, class D>
536 bool operator()(A, B, C, D) const
541 bool operator()(int64_t, int64_t, bool, bool) const
547 static std::string description()
552 static const int condition = -1;
555 struct NotEqualIns : public HackClass {
556 bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false,
559 if (v1.is_null() != v2.is_null())
561 return v1.size() != v2.size() || !equal_case_fold(v2, v1_upper, v1_lower);
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
567 if (v1.is_null() != v2.is_null())
570 if (v1.size() != v2.size())
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());
577 template <class A, class B>
578 bool operator()(A, B) const
583 template <class A, class B, class C, class D>
584 bool operator()(A, B, C, D) const
590 static std::string description()
595 static const int condition = -1;
599 static const int avx = 0x1E; // _CMP_GT_OQ
601 bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
603 if (v1null || v2null)
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
616 bool can_match(int64_t v, int64_t lbound, int64_t ubound)
618 static_cast<void>(lbound);
621 bool will_match(int64_t v, int64_t lbound, int64_t ubound)
623 static_cast<void>(ubound);
627 static std::string description()
635 bool operator()(const T&, const T&, bool = false, bool = false) const
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
646 bool can_match(int64_t v, int64_t lbound, int64_t ubound)
648 static_cast<void>(lbound);
649 static_cast<void>(ubound);
650 static_cast<void>(v);
653 bool will_match(int64_t v, int64_t lbound, int64_t ubound)
655 static_cast<void>(lbound);
656 static_cast<void>(ubound);
657 static_cast<void>(v);
661 static std::string description()
669 bool operator()(const T&, const T&, bool v = false, bool = false) const
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
680 bool can_match(int64_t v, int64_t lbound, int64_t ubound)
682 static_cast<void>(lbound);
683 static_cast<void>(ubound);
684 static_cast<void>(v);
687 bool will_match(int64_t v, int64_t lbound, int64_t ubound)
689 static_cast<void>(lbound);
690 static_cast<void>(ubound);
691 static_cast<void>(v);
694 static std::string description()
702 static const int avx = 0x11; // _CMP_LT_OQ
704 bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
706 if (v1null || v2null)
711 template <class A, class B, class C, class D>
712 bool operator()(A, B, C, D) const
717 static const int condition = cond_Less;
718 bool can_match(int64_t v, int64_t lbound, int64_t ubound)
720 static_cast<void>(ubound);
723 bool will_match(int64_t v, int64_t lbound, int64_t ubound)
725 static_cast<void>(lbound);
728 static std::string description()
734 struct LessEqual : public HackClass {
735 static const int avx = 0x12; // _CMP_LE_OQ
737 bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
739 if (v1null && v2null)
742 return (!v1null && !v2null && v1 <= v2);
744 template <class A, class B, class C, class D>
745 bool operator()(A, B, C, D) const
750 static std::string description()
754 static const int condition = -1;
757 struct GreaterEqual : public HackClass {
758 static const int avx = 0x1D; // _CMP_GE_OQ
760 bool operator()(const T& v1, const T& v2, bool v1null = false, bool v2null = false) const
762 if (v1null && v2null)
765 return (!v1null && !v2null && v1 >= v2);
767 template <class A, class B, class C, class D>
768 bool operator()(A, B, C, D) const
773 static std::string description()
777 static const int condition = -1;
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)
785 static bool compare(T v1, T v2, bool = false, bool = false)
791 struct CompareLess<StringData> {
792 static bool compare(StringData v1, StringData v2, bool = false, bool = false)
794 bool ret = utf8_compare(v1.data(), v2.data());
801 #endif // REALM_QUERY_CONDITIONS_HPP