static uint64_t FastHashJsonRecursive (uint64_t hash, TRI_json_t const* object) { if (nullptr == object) { return fasthash64(static_cast<const void*>("null"), 4, hash); } switch (object->_type) { case TRI_JSON_UNUSED: { return hash; } case TRI_JSON_NULL: { return fasthash64(static_cast<const void*>("null"), 4, hash); } case TRI_JSON_BOOLEAN: { if (object->_value._boolean) { return fasthash64(static_cast<const void*>("true"), 4, hash); } return fasthash64(static_cast<const void*>("false"), 5, hash); } case TRI_JSON_NUMBER: { return fasthash64(static_cast<const void*>(&object->_value._number), sizeof(object->_value._number), hash); } case TRI_JSON_STRING: case TRI_JSON_STRING_REFERENCE: { return fasthash64(static_cast<const void*>(object->_value._string.data), object->_value._string.length, hash); } case TRI_JSON_OBJECT: { hash = fasthash64(static_cast<const void*>("object"), 6, hash); size_t const n = TRI_LengthVector(&object->_value._objects); for (size_t i = 0; i < n; i += 2) { auto subjson = static_cast<TRI_json_t const*>(TRI_AddressVector(&object->_value._objects, i)); TRI_ASSERT(TRI_IsStringJson(subjson)); hash = FastHashJsonRecursive(hash, subjson); subjson = static_cast<TRI_json_t const*>(TRI_AddressVector(&object->_value._objects, i + 1)); hash = FastHashJsonRecursive(hash, subjson); } return hash; } case TRI_JSON_ARRAY: { hash = fasthash64(static_cast<const void*>("array"), 5, hash); size_t const n = TRI_LengthVector(&object->_value._objects); for (size_t i = 0; i < n; ++i) { auto subjson = static_cast<TRI_json_t const*>(TRI_AddressVector(&object->_value._objects, i)); hash = FastHashJsonRecursive(hash, subjson); } } } return hash; // never reached }
void TRI_DestroyJson (TRI_memory_zone_t* zone, TRI_json_t* object) { switch (object->_type) { case TRI_JSON_UNUSED: case TRI_JSON_NULL: case TRI_JSON_BOOLEAN: case TRI_JSON_NUMBER: case TRI_JSON_STRING_REFERENCE: break; case TRI_JSON_STRING: TRI_DestroyBlob(zone, &object->_value._string); break; case TRI_JSON_OBJECT: case TRI_JSON_ARRAY: { size_t const n = TRI_LengthVector(&object->_value._objects); for (size_t i = 0; i < n; ++i) { auto v = static_cast<TRI_json_t*>(TRI_AddressVector(&object->_value._objects, i)); TRI_DestroyJson(zone, v); } TRI_DestroyVector(&object->_value._objects); break; } } }
TRI_json_t* TRI_LookupObjectJson (TRI_json_t const* object, char const* name) { if (object == nullptr) { return nullptr; } TRI_ASSERT(object->_type == TRI_JSON_OBJECT); TRI_ASSERT(name != nullptr); size_t const n = TRI_LengthVector(&object->_value._objects); if (n >= 16) { // if we have many attributes, try an algorithm that compares string length first // calculate string length once size_t const length = strlen(name) + 1; for (size_t i = 0; i < n; i += 2) { auto key = static_cast<TRI_json_t const*>(TRI_AddressVector(&object->_value._objects, i)); if (! IsString(key)) { continue; } // check string length first, and contents only if string lengths are equal if (key->_value._string.length == length && strcmp(key->_value._string.data, name) == 0) { return static_cast<TRI_json_t*>(TRI_AddressVector(&object->_value._objects, i + 1)); } } } else { // simple case for smaller objects for (size_t i = 0; i < n; i += 2) { auto key = static_cast<TRI_json_t const*>(TRI_AddressVector(&object->_value._objects, i)); if (! IsString(key)) { continue; } if (strcmp(key->_value._string.data, name) == 0) { return static_cast<TRI_json_t*>(TRI_AddressVector(&object->_value._objects, i + 1)); } } } return nullptr; }
static uint64_t HashJsonRecursive (uint64_t hash, TRI_json_t const* object) { if (nullptr == object) { return HashBlock(hash, "null", 4); // strlen("null") } switch (object->_type) { case TRI_JSON_UNUSED: { return hash; } case TRI_JSON_NULL: { return HashBlock(hash, "null", 4); // strlen("null") } case TRI_JSON_BOOLEAN: { if (object->_value._boolean) { return HashBlock(hash, "true", 4); // strlen("true") } else { return HashBlock(hash, "false", 5); // strlen("true") } } case TRI_JSON_NUMBER: { return HashBlock(hash, (char const*) &(object->_value._number), sizeof(object->_value._number)); } case TRI_JSON_STRING: case TRI_JSON_STRING_REFERENCE: { return HashBlock(hash, object->_value._string.data, object->_value._string.length); } case TRI_JSON_OBJECT: { hash = HashBlock(hash, "array", 5); // strlen("array") size_t const n = TRI_LengthVector(&object->_value._objects); uint64_t tmphash = hash; for (size_t i = 0; i < n; i += 2) { auto subjson = static_cast<TRI_json_t const*>(TRI_AddressVector(&object->_value._objects, i)); TRI_ASSERT(TRI_IsStringJson(subjson)); tmphash ^= HashJsonRecursive(hash, subjson); subjson = static_cast<TRI_json_t const*>(TRI_AddressVector(&object->_value._objects, i + 1)); tmphash ^= HashJsonRecursive(hash, subjson); } return tmphash; } case TRI_JSON_ARRAY: { hash = HashBlock(hash, "list", 4); // strlen("list") size_t const n = TRI_LengthVector(&object->_value._objects); for (size_t i = 0; i < n; ++i) { auto subjson = static_cast<TRI_json_t const*>(TRI_AddressVector(&object->_value._objects, i)); hash = HashJsonRecursive(hash, subjson); } return hash; } } return hash; // never reached }