TRI_json_t* TRI_BetweenListJson (const TRI_json_t* const list, const TRI_json_t* const lower, const bool includeLower, const TRI_json_t* const upper, const bool includeUpper) { TRI_json_t* result; size_t i, n; TRI_ASSERT(list); TRI_ASSERT(list->_type == TRI_JSON_LIST); TRI_ASSERT(lower || upper); // create result list result = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE); if (result == NULL) { return NULL; } n = list->_value._objects._length; for (i = 0; i < n; ++i) { TRI_json_t* p = TRI_AtVector(&list->_value._objects, i); if (lower) { // lower bound is set int compareResult = TRI_CompareValuesJson(lower, p); if (compareResult > 0 || (compareResult == 0 && ! includeLower)) { // element is bigger than lower bound continue; } } if (upper) { // upper bound is set int compareResult = TRI_CompareValuesJson(p, upper); if (compareResult > 0 || (compareResult == 0 && ! includeUpper)) { // element is smaller than upper bound continue; } } // element is between lower and upper bound TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p); } return result; }
TRI_json_t* TRI_UniquifyListJson (const TRI_json_t* const list) { TRI_json_t* last = NULL; TRI_json_t* result; size_t i, n; assert(list); assert(list->_type == TRI_JSON_LIST); // create result list result = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE); if (!result) { return NULL; } n = list->_value._objects._length; for (i = 0; i < n; ++i) { TRI_json_t* p = TRI_AtVector(&list->_value._objects, i); // don't push value if it is the same as the last value if (!last || TRI_CompareValuesJson(p, last) > 0) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p); // remember last element last = p; } } return result; }
TRI_json_t* TRI_UniquifyArrayJson (TRI_json_t const* array) { TRI_ASSERT(array != nullptr); TRI_ASSERT(array->_type == TRI_JSON_ARRAY); // create result array std::unique_ptr<TRI_json_t> result(TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE)); if (result == nullptr) { return nullptr; } size_t const n = TRI_LengthVector(&array->_value._objects); TRI_json_t const* last = nullptr; for (size_t i = 0; i < n; ++i) { auto p = static_cast<TRI_json_t const*>(TRI_AtVector(&array->_value._objects, i)); // don't push value if it is the same as the last value if (last == nullptr || TRI_CompareValuesJson(p, last, false) != 0) { TRI_PushBackArrayJson(TRI_UNKNOWN_MEM_ZONE, result.get(), p); // remember last element last = p; } } return result.release(); }
static int CompareJson (TRI_json_t* lhs, TRI_json_t* rhs, size_t size) { return TRI_CompareValuesJson((TRI_json_t*) lhs, (TRI_json_t*) rhs); }
TRI_json_t* TRI_IntersectListsJson (const TRI_json_t* const list1, const TRI_json_t* const list2, const bool unique) { TRI_json_t* last = NULL; TRI_json_t* result; size_t i1, i2; size_t n1, n2; assert(list1); assert(list1->_type == TRI_JSON_LIST); assert(list2); assert(list2->_type == TRI_JSON_LIST); // create result list result = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE); if (!result) { return NULL; } n1 = list1->_value._objects._length; n2 = list2->_value._objects._length; // special case for empty lists if (n1 == 0 || n2 == 0) { return result; } // reset positions i1 = 0; i2 = 0; // iterate over lists while (i1 < n1 && i2 < n2) { // pointers to elements in both lists TRI_json_t* p1 = TRI_AtVector(&list1->_value._objects, i1); TRI_json_t* p2 = TRI_AtVector(&list2->_value._objects, i2); int compareResult = TRI_CompareValuesJson(p1, p2); if (compareResult < 0) { // left element is smaller ++i1; } else if (compareResult > 0) { // right element is smaller ++i2; } else { // both elements are equal if (!unique || !last || TRI_CompareValuesJson(p1, last) > 0) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p1); last = p1; if (!unique) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p2); } } ++i1; ++i2; } } return result; }
TRI_json_t* TRI_UnionizeListsJson (const TRI_json_t* const list1, const TRI_json_t* const list2, const bool unique) { TRI_json_t* last = NULL; TRI_json_t* result; size_t i1, i2; size_t n1, n2; assert(list1); assert(list1->_type == TRI_JSON_LIST); assert(list2); assert(list2->_type == TRI_JSON_LIST); n1 = list1->_value._objects._length; n2 = list2->_value._objects._length; // special cases for empty lists if (n1 == 0 && !unique) { return TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, (TRI_json_t*) list2); } if (n2 == 0 && !unique) { return TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, (TRI_json_t*) list1); } // create result list result = TRI_CreateListJson(TRI_UNKNOWN_MEM_ZONE); if (!result) { return NULL; } // reset positions i1 = 0; i2 = 0; // iterate over lists while (true) { // pointers to elements in both lists TRI_json_t* p1; TRI_json_t* p2; if (i1 < n1 && i2 < n2) { int compareResult; // both lists not yet exhausted p1 = TRI_AtVector(&list1->_value._objects, i1); p2 = TRI_AtVector(&list2->_value._objects, i2); compareResult = TRI_CompareValuesJson(p1, p2); if (compareResult < 0) { // left element is smaller if (!unique || !last || TRI_CompareValuesJson(p1, last) > 0) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p1); last = p1; } ++i1; } else if (compareResult > 0) { // right element is smaller if (!unique || !last || TRI_CompareValuesJson(p2, last) > 0) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p2); last = p2; } ++i2; } else { // both elements are equal if (!unique || !last || TRI_CompareValuesJson(p1, last) > 0) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p1); last = p1; if (!unique) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p2); } } ++i1; ++i2; } } else if (i1 < n1 && i2 >= n2) { // only right list is exhausted p1 = TRI_AtVector(&list1->_value._objects, i1); if (!unique || !last || TRI_CompareValuesJson(p1, last) > 0) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p1); last = p1; } ++i1; } else if (i1 >= n1 && i2 < n2) { // only left list is exhausted p2 = TRI_AtVector(&list2->_value._objects, i2); if (!unique || !last || TRI_CompareValuesJson(p2, last) > 0) { TRI_PushBackListJson(TRI_UNKNOWN_MEM_ZONE, result, p2); last = p2; } ++i2; } else { // both lists exhausted, stop! break; } } return result; }
bool TRI_CheckSameValueJson (const TRI_json_t* const lhs, const TRI_json_t* const rhs) { return (TRI_CompareValuesJson(lhs, rhs) == 0); }
int TRI_CompareValuesJson (const TRI_json_t* const lhs, const TRI_json_t* const rhs) { // note: both lhs and rhs may be NULL! int lWeight = TypeWeight(lhs); int rWeight = TypeWeight(rhs); if (lWeight < rWeight) { return -1; } if (lWeight > rWeight) { return 1; } // lhs and rhs have equal weights if (lhs == NULL) { // both lhs and rhs are NULL, so they are equal return 0; } switch (lhs->_type) { case TRI_JSON_UNUSED: case TRI_JSON_NULL: return 0; // null == null; case TRI_JSON_BOOLEAN: if (lhs->_value._boolean == rhs->_value._boolean) { return 0; } if (!lhs->_value._boolean && rhs->_value._boolean) { return -1; } return 1; case TRI_JSON_NUMBER: if (lhs->_value._number == rhs->_value._number) { return 0; } if (lhs->_value._number < rhs->_value._number) { return -1; } return 1; case TRI_JSON_STRING: return strcmp(lhs->_value._string.data, rhs->_value._string.data); case TRI_JSON_LIST: { size_t nl = lhs->_value._objects._length; size_t nr = rhs->_value._objects._length; size_t n; size_t i; if (nl > nr) { n = nl; } else { n = nr; } for (i = 0; i < n; ++i) { TRI_json_t* lhsValue; TRI_json_t* rhsValue; int result; lhsValue = (i >= nl) ? NULL : TRI_AtVector(&lhs->_value._objects, i); rhsValue = (i >= nr) ? NULL : TRI_AtVector(&rhs->_value._objects, i); result = TRI_CompareValuesJson(lhsValue, rhsValue); if (result != 0) { return result; } } return 0; } case TRI_JSON_ARRAY: { TRI_json_t* keys; assert(lhs->_type == TRI_JSON_ARRAY); assert(rhs->_type == TRI_JSON_ARRAY); keys = GetMergedKeyList(lhs, rhs); if (keys != NULL) { size_t i, n; n = keys->_value._objects._length; for (i = 0; i < n; ++i) { TRI_json_t* keyElement; TRI_json_t* lhsValue; TRI_json_t* rhsValue; int result; keyElement = TRI_AtVector(&keys->_value._objects, i); assert(keyElement->_type == TRI_JSON_STRING); assert(keyElement->_value._string.data); lhsValue = TRI_LookupArrayJson((TRI_json_t*) lhs, keyElement->_value._string.data); // may be NULL rhsValue = TRI_LookupArrayJson((TRI_json_t*) rhs, keyElement->_value._string.data); // may be NULL result = TRI_CompareValuesJson(lhsValue, rhsValue); if (result != 0) { TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, keys); return result; } } TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, keys); } return 0; } default: return 0; } }
bool TRI_CheckSameValueJson (TRI_json_t const* lhs, TRI_json_t const* rhs) { return (TRI_CompareValuesJson(lhs, rhs, false) == 0); }
int TRI_CompareValuesJson (TRI_json_t const* lhs, TRI_json_t const* rhs, bool useUTF8) { // note: both lhs and rhs may be NULL! { int lWeight = TypeWeight(lhs); int rWeight = TypeWeight(rhs); if (lWeight < rWeight) { return -1; } if (lWeight > rWeight) { return 1; } TRI_ASSERT_EXPENSIVE(lWeight == rWeight); } // lhs and rhs have equal weights if (lhs == nullptr || rhs == nullptr) { // either lhs or rhs is a nullptr. we cannot be sure here that both are nullptrs. // there can also exist the situation that lhs is a nullptr and rhs is a JSON null value // (or vice versa). Anyway, the compare value is the same for both, return 0; } switch (lhs->_type) { case TRI_JSON_UNUSED: case TRI_JSON_NULL: { return 0; // null == null; } case TRI_JSON_BOOLEAN: { if (lhs->_value._boolean == rhs->_value._boolean) { return 0; } if (! lhs->_value._boolean && rhs->_value._boolean) { return -1; } return 1; } case TRI_JSON_NUMBER: { if (lhs->_value._number == rhs->_value._number) { return 0; } if (lhs->_value._number < rhs->_value._number) { return -1; } return 1; } case TRI_JSON_STRING: case TRI_JSON_STRING_REFERENCE: { // same for STRING and STRING_REFERENCE TRI_ASSERT(lhs->_value._string.data != nullptr); TRI_ASSERT(rhs->_value._string.data != nullptr); int res; size_t const nl = lhs->_value._string.length - 1; size_t const nr = rhs->_value._string.length - 1; if (useUTF8) { res = TRI_compare_utf8(lhs->_value._string.data, nl, rhs->_value._string.data, nr); } else { // beware of strings containing NUL bytes size_t len = nl < nr ? nl : nr; res = memcmp(lhs->_value._string.data, rhs->_value._string.data, len); } if (res < 0) { return -1; } else if (res > 0) { return 1; } // res == 0 if (nl == nr) { return 0; } // res == 0, but different string lengths return nl < nr ? -1 : 1; } case TRI_JSON_ARRAY: { size_t const nl = TRI_LengthVector(&lhs->_value._objects); size_t const nr = TRI_LengthVector(&rhs->_value._objects); size_t n; if (nl > nr) { n = nl; } else { n = nr; } for (size_t i = 0; i < n; ++i) { auto lhsValue = (i >= nl) ? nullptr : static_cast<TRI_json_t const*>(TRI_AtVector(&lhs->_value._objects, i)); auto rhsValue = (i >= nr) ? nullptr : static_cast<TRI_json_t const*>(TRI_AtVector(&rhs->_value._objects, i)); int result = TRI_CompareValuesJson(lhsValue, rhsValue, useUTF8); if (result != 0) { return result; } } return 0; } case TRI_JSON_OBJECT: { TRI_ASSERT(lhs->_type == TRI_JSON_OBJECT); TRI_ASSERT(rhs->_type == TRI_JSON_OBJECT); std::unique_ptr<TRI_json_t> keys(GetMergedKeyArray(lhs, rhs)); if (keys != nullptr) { auto json = keys.get(); size_t const n = TRI_LengthVector(&json->_value._objects); for (size_t i = 0; i < n; ++i) { auto keyElement = static_cast<TRI_json_t const*>(TRI_AtVector(&json->_value._objects, i)); TRI_ASSERT(TRI_IsStringJson(keyElement)); TRI_json_t const* lhsValue = TRI_LookupObjectJson(lhs, keyElement->_value._string.data); // may be NULL TRI_json_t const* rhsValue = TRI_LookupObjectJson(rhs, keyElement->_value._string.data); // may be NULL int result = TRI_CompareValuesJson(lhsValue, rhsValue, useUTF8); if (result != 0) { return result; } } } // fall-through to returning 0 } } return 0; }
static int CompareJson (void const* lhs, void const* rhs) { return TRI_CompareValuesJson(static_cast<TRI_json_t const*>(lhs), static_cast<TRI_json_t const*>(rhs), true); }