Пример #1
0
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
}
Пример #2
0
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;
    }
  }
}
Пример #3
0
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();
}
Пример #4
0
static TRI_json_t* GetMergedKeyArray (TRI_json_t const* lhs,
                                      TRI_json_t const* rhs) {
    TRI_ASSERT(lhs->_type == TRI_JSON_OBJECT);
    TRI_ASSERT(rhs->_type == TRI_JSON_OBJECT);

    size_t n = TRI_LengthVector(&lhs->_value._objects) + TRI_LengthVector(&rhs->_value._objects);

    std::unique_ptr<TRI_json_t> keys(TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE, n));

    if (keys == nullptr) {
        return nullptr;
    }

    if (TRI_CapacityVector(&(keys.get()->_value._objects)) < n) {
        return nullptr;
    }

    n = TRI_LengthVector(&lhs->_value._objects);

    for (size_t i = 0 ; i < n; i += 2) {
        auto key = static_cast<TRI_json_t const*>(TRI_AtVector(&lhs->_value._objects, i));

        TRI_ASSERT(TRI_IsStringJson(key));
        TRI_PushBackArrayJson(TRI_UNKNOWN_MEM_ZONE, keys.get(), key);
    }


    n = TRI_LengthVector(&rhs->_value._objects);

    for (size_t i = 0 ; i < n; i += 2) {
        auto key = static_cast<TRI_json_t const*>(TRI_AtVector(&rhs->_value._objects, i));

        TRI_ASSERT(TRI_IsStringJson(key));
        TRI_PushBackArrayJson(TRI_UNKNOWN_MEM_ZONE, keys.get(), key);
    }

    // sort the key array in place
    TRI_SortArrayJson(keys.get());

    // array is now sorted
    return TRI_UniquifyArrayJson(keys.get());
}
Пример #5
0
TRI_json_t* TRI_LookupArrayJson (TRI_json_t const* array, size_t pos) {
  TRI_ASSERT(array->_type == TRI_JSON_ARRAY);

  size_t const n = TRI_LengthVector(&array->_value._objects);

  if (pos >= n) {
    // out of bounds
    return nullptr;
  }

  return static_cast<TRI_json_t*>(TRI_AtVector(&array->_value._objects, pos));
}
Пример #6
0
int TRI_CopyToJson (TRI_memory_zone_t* zone,
                    TRI_json_t* dst,
                    TRI_json_t const* src) {
  dst->_type = src->_type;

  switch (src->_type) {
    case TRI_JSON_UNUSED:
    case TRI_JSON_NULL:
      break;

    case TRI_JSON_BOOLEAN:
      dst->_value._boolean = src->_value._boolean;
      break;

    case TRI_JSON_NUMBER:
      dst->_value._number = src->_value._number;
      break;

    case TRI_JSON_STRING:
      return TRI_CopyToBlob(zone, &dst->_value._string, &src->_value._string);

    case TRI_JSON_STRING_REFERENCE:
      return TRI_AssignToBlob(zone, &dst->_value._string, &src->_value._string);

    case TRI_JSON_OBJECT:
    case TRI_JSON_ARRAY: {
      size_t const n = TRI_LengthVector(&src->_value._objects);

      TRI_InitVector(&dst->_value._objects, zone, sizeof(TRI_json_t));
      int res = TRI_ResizeVector(&dst->_value._objects, n);

      if (res != TRI_ERROR_NO_ERROR) {
        return res;
      }

      for (size_t i = 0;  i < n;  ++i) {
        auto const* v = static_cast<TRI_json_t const*>(TRI_AtVector(&src->_value._objects, i));
        auto* w = static_cast<TRI_json_t*>(TRI_AtVector(&dst->_value._objects, i));

        res = TRI_CopyToJson(zone, w, v);

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      break;
    }
  }

  return TRI_ERROR_NO_ERROR;
}
Пример #7
0
TRI_json_t* TRI_SortArrayJson (TRI_json_t* array) {
    TRI_ASSERT(array != nullptr);
    TRI_ASSERT(array->_type == TRI_JSON_ARRAY);

    size_t const n = TRI_LengthVector(&array->_value._objects);

    if (n > 1) {
        // only sort if more than one value in array
        qsort(TRI_BeginVector(&array->_value._objects), n, sizeof(TRI_json_t), &CompareJson);
    }

    return array;
}
Пример #8
0
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;
}
Пример #9
0
bool TRI_DeleteObjectJson (TRI_memory_zone_t* zone, TRI_json_t* object, char const* name) {
  TRI_ASSERT(object->_type == TRI_JSON_OBJECT);
  TRI_ASSERT(name != nullptr);

  size_t const n = TRI_LengthVector(&object->_value._objects);

  for (size_t i = 0;  i < n;  i += 2) {
    TRI_json_t* key = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i));

    if (! IsString(key)) {
      continue;
    }

    if (TRI_EqualString(key->_value._string.data, name)) {
      // remove key
      TRI_json_t* old = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i));

      if (old != nullptr) {
        TRI_DestroyJson(zone, old);
      }

      TRI_RemoveVector(&object->_value._objects, i);

      // remove value
      old = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i));

      if (old != nullptr) {
        TRI_DestroyJson(zone, old);
      }

      TRI_RemoveVector(&object->_value._objects, i);

      return true;
    }
  }

  return false;
}
Пример #10
0
bool TRI_ReplaceObjectJson (TRI_memory_zone_t* zone, 
                            TRI_json_t* object, 
                            char const* name, 
                            TRI_json_t const* replacement) {
  TRI_ASSERT(object->_type == TRI_JSON_OBJECT);
  TRI_ASSERT(name != nullptr);

  size_t const n = TRI_LengthVector(&object->_value._objects);

  for (size_t i = 0;  i < n;  i += 2) {
    TRI_json_t* key = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i));

    if (! IsString(key)) {
      continue;
    }

    if (TRI_EqualString(key->_value._string.data, name)) {
      // retrieve the old element
      TRI_json_t* old = static_cast<TRI_json_t*>(TRI_AtVector(&object->_value._objects, i + 1));

      if (old != nullptr) {
        TRI_DestroyJson(zone, old);
      }

      TRI_json_t copy;
      TRI_CopyToJson(zone, &copy, replacement);
      TRI_SetVector(&object->_value._objects, i + 1, &copy);
      return true;
    }
  }

  // object not found in array, now simply add it
  TRI_Insert2ObjectJson(zone, object, name, replacement);

  return false;
}
Пример #11
0
static bool CompactifyDocumentCollection (TRI_document_collection_t* document) {
  TRI_primary_collection_t* primary;
  TRI_vector_t vector;
  int64_t numAlive;
  size_t i, n;
  bool compactNext;

  compactNext = false;
  primary = &document->base;

  // if we cannot acquire the read lock instantly, we will exit directly.
  // otherwise we'll risk a multi-thread deadlock between synchroniser,
  // compactor and data-modification threads (e.g. POST /_api/document)
  if (! TRI_TRY_READ_LOCK_DATAFILES_DOC_COLLECTION(primary)) {
    return false;
  }

  n = primary->base._datafiles._length;

  if (primary->base._compactors._length > 0 || n == 0) {
    // we already have created a compactor file in progress.
    // if this happens, then a previous compaction attempt for this collection failed

    // additionally, if there are no datafiles, then there's no need to compact
    TRI_READ_UNLOCK_DATAFILES_DOC_COLLECTION(primary);
    
    return false;
  }

  // copy datafile information
  TRI_InitVector(&vector, TRI_UNKNOWN_MEM_ZONE, sizeof(compaction_info_t));
  numAlive = 0;

  for (i = 0;  i < n;  ++i) {
    TRI_datafile_t* df;
    TRI_doc_datafile_info_t* dfi;
    compaction_info_t compaction;
    bool shouldCompact;
  
    df = primary->base._datafiles._buffer[i];

    assert(df != NULL);

    dfi = TRI_FindDatafileInfoPrimaryCollection(primary, df->_fid, true);

    if (dfi == NULL) {
      continue;
    }
  
    shouldCompact = false;
  
    if (! compactNext && 
        df->_maximalSize < COMPACTOR_MIN_SIZE && 
        i < n - 1) {
      // very small datafile. let's compact it so it's merged with others
      shouldCompact = true;
      compactNext = true;
    }
    else if (numAlive == 0 && dfi->_numberDeletion > 0) {
      // compact first datafile already if it has got some deletions
      shouldCompact = true;
      compactNext = true;
    }
    else {
      // in all other cases, only check the number and size of "dead" objects
      if (dfi->_sizeDead >= (int64_t) COMPACTOR_DEAD_SIZE_THRESHOLD) {
        shouldCompact = true;
        compactNext = true;
      }
      else if (dfi->_sizeDead > 0) {
        // the size of dead objects is above some threshold
        double share = (double) dfi->_sizeDead / ((double) dfi->_sizeDead + (double) dfi->_sizeAlive);
    
        if (share >= COMPACTOR_DEAD_SIZE_SHARE) {
          // the size of dead objects is above some share
          shouldCompact = true;
          compactNext = true;
        }
      }
    }

    if (! shouldCompact) {
      // only use those datafiles that contain dead objects

      if (! compactNext) {
        numAlive += (int64_t) dfi->_numberAlive;
        continue;
      }
    }
    
    LOG_TRACE("found datafile eligible for compaction. fid: %llu, size: %llu "
              "numberDead: %llu, numberAlive: %llu, numberTransaction: %llu, numberDeletion: %llu, "
              "sizeDead: %llu, sizeAlive: %llu, sizeTransaction: %llu",
              (unsigned long long) df->_fid,
              (unsigned long long) df->_maximalSize,
              (unsigned long long) dfi->_numberDead,
              (unsigned long long) dfi->_numberAlive,
              (unsigned long long) dfi->_numberTransaction,
              (unsigned long long) dfi->_numberDeletion,
              (unsigned long long) dfi->_sizeDead,
              (unsigned long long) dfi->_sizeAlive,
              (unsigned long long) dfi->_sizeTransaction);

    compaction._datafile = df;
    compaction._keepDeletions = (numAlive > 0 && i > 0);

    TRI_PushBackVector(&vector, &compaction);
   
    // we stop at the first few datafiles.
    // this is better than going over all datafiles in a collection in one go
    // because the compactor is single-threaded, and collecting all datafiles
    // might take a long time (it might even be that there is a request to
    // delete the collection in the middle of compaction, but the compactor
    // will not pick this up as it is read-locking the collection status)

    if (TRI_LengthVector(&vector) >= COMPACTOR_MAX_FILES) {
      // found enough to compact
      break;
    }
        
    numAlive += (int64_t) dfi->_numberAlive;
  }
  
  // can now continue without the lock
  TRI_READ_UNLOCK_DATAFILES_DOC_COLLECTION(primary);

  if (vector._length == 0) {
    // cleanup local variables
    TRI_DestroyVector(&vector);

    return false;
  }

  // handle datafiles with dead objects
  n = vector._length;
  assert(n >= 1);
    
  CompactifyDatafiles(document, &vector); 

  // cleanup local variables
  TRI_DestroyVector(&vector);

  return true;
}
Пример #12
0
static TRI_json_t* MergeRecursive (TRI_memory_zone_t* zone,
                                   TRI_json_t const* lhs,
                                   TRI_json_t const* rhs,
                                   bool nullMeansRemove,
                                   bool mergeObjects) {
    TRI_ASSERT(lhs != nullptr);

    std::unique_ptr<TRI_json_t> result(TRI_CopyJson(zone, lhs));

    if (result == nullptr) {
        return nullptr;
    }

    auto r = result.get(); // shortcut variable

    size_t const n = TRI_LengthVector(&rhs->_value._objects);

    for (size_t i = 0; i < n; i += 2) {
        // enumerate all the replacement values
        auto key   = static_cast<TRI_json_t const*>(TRI_AtVector(&rhs->_value._objects, i));
        auto value = static_cast<TRI_json_t const*>(TRI_AtVector(&rhs->_value._objects, i + 1));

        if (value->_type == TRI_JSON_NULL && nullMeansRemove) {
            // replacement value is a null and we don't want to store nulls => delete attribute from the result
            TRI_DeleteObjectJson(zone, r, key->_value._string.data);
        }
        else {
            // replacement value is not a null or we want to store nulls
            TRI_json_t const* lhsValue = TRI_LookupObjectJson(lhs, key->_value._string.data);

            if (lhsValue == nullptr) {
                // existing array does not have the attribute => append new attribute
                if (value->_type == TRI_JSON_OBJECT && nullMeansRemove) {
                    TRI_json_t empty;
                    TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &empty);
                    TRI_json_t* merged = MergeRecursive(zone, &empty, value, nullMeansRemove, mergeObjects);

                    if (merged == nullptr) {
                        return nullptr;
                    }

                    TRI_json_t* copy = TRI_CopyJson(zone, value);

                    if (copy == nullptr) {
                        return nullptr;
                    }

                    TRI_Insert3ObjectJson(zone, r, key->_value._string.data, copy);
                }
                else {
                    TRI_Insert3ObjectJson(zone, r, key->_value._string.data, TRI_CopyJson(zone, value));
                }
            }
            else {
                // existing array already has the attribute => replace attribute
                if (lhsValue->_type == TRI_JSON_OBJECT && value->_type == TRI_JSON_OBJECT && mergeObjects) {
                    TRI_json_t* merged = MergeRecursive(zone, lhsValue, value, nullMeansRemove, mergeObjects);

                    if (merged == nullptr) {
                        return nullptr;
                    }

                    TRI_ReplaceObjectJson(zone, r, key->_value._string.data, merged);
                    TRI_FreeJson(zone, merged);
                }
                else {
                    TRI_ReplaceObjectJson(zone, r, key->_value._string.data, value);
                }
            }
        }

    }

    return result.release();
}
Пример #13
0
size_t TRI_LengthVectorJson (TRI_json_t const* json) {
  TRI_ASSERT(json != nullptr && 
             (json->_type == TRI_JSON_ARRAY || json->_type == TRI_JSON_OBJECT));
  return TRI_LengthVector(&json->_value._objects);
}
Пример #14
0
static int StringifyJson (TRI_memory_zone_t* zone,
                          TRI_string_buffer_t* buffer,
                          TRI_json_t const* object,
                          bool braces) {
  int res;

  switch (object->_type) {
    case TRI_JSON_UNUSED: {
      break;
    }

    case TRI_JSON_NULL: {
      res = TRI_AppendString2StringBuffer(buffer, "null", 4); // strlen("null")

      if (res != TRI_ERROR_NO_ERROR) {
        return res;
      }

      break;
    }

    case TRI_JSON_BOOLEAN: {
      if (object->_value._boolean) {
        res = TRI_AppendString2StringBuffer(buffer, "true", 4); // strlen("true")
      }
      else {
        res = TRI_AppendString2StringBuffer(buffer, "false", 5); // strlen("false")
      }

      if (res != TRI_ERROR_NO_ERROR) {
        return res;
      }

      break;
    }

    case TRI_JSON_NUMBER: {
      res = TRI_AppendDoubleStringBuffer(buffer, object->_value._number);

      if (res != TRI_ERROR_NO_ERROR) {
        return res;
      }

      break;
    }

    case TRI_JSON_STRING:
    case TRI_JSON_STRING_REFERENCE: {
      res = TRI_AppendCharStringBuffer(buffer, '\"');

      if (res != TRI_ERROR_NO_ERROR) {
        return res;
      }

      if (object->_value._string.length > 0) {
        // optimisation for the empty string
        res =  TRI_AppendJsonEncodedStringStringBuffer(buffer, object->_value._string.data, object->_value._string.length - 1, false);

        if (res != TRI_ERROR_NO_ERROR) {
          return TRI_ERROR_OUT_OF_MEMORY;
        }
      }

      res = TRI_AppendCharStringBuffer(buffer, '\"');

      if (res != TRI_ERROR_NO_ERROR) {
        return res;
      }

      break;
    }

    case TRI_JSON_OBJECT: {
      if (braces) {
        res = TRI_AppendCharStringBuffer(buffer, '{');

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      size_t const n = TRI_LengthVector(&object->_value._objects);

      for (size_t i = 0;  i < n;  i += 2) {
        if (0 < i) {
          res = TRI_AppendCharStringBuffer(buffer, ',');

          if (res != TRI_ERROR_NO_ERROR) {
            return res;
          }
        }

        res = StringifyJson(zone, buffer, static_cast<TRI_json_t const*>(TRI_AtVector(&object->_value._objects, i)), true);

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }

        res = TRI_AppendCharStringBuffer(buffer, ':');

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }

        res = StringifyJson(zone, buffer, static_cast<TRI_json_t const*>(TRI_AtVector(&object->_value._objects, i + 1)), true);

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      if (braces) {
        res = TRI_AppendCharStringBuffer(buffer, '}');

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      break;
    }

    case TRI_JSON_ARRAY: {
      if (braces) {
        res = TRI_AppendCharStringBuffer(buffer, '[');

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      size_t const n = TRI_LengthVector(&object->_value._objects);

      for (size_t i = 0;  i < n;  ++i) {
        if (0 < i) {
          res = TRI_AppendCharStringBuffer(buffer, ',');

          if (res != TRI_ERROR_NO_ERROR) {
            return res;
          }
        }

        res = StringifyJson(zone, buffer, static_cast<TRI_json_t const*>(TRI_AtVector(&object->_value._objects, i)), true);

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      if (braces) {
        res = TRI_AppendCharStringBuffer(buffer, ']');

        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      break;
    }
  }

  return TRI_ERROR_NO_ERROR;
}
Пример #15
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;
}
Пример #16
0
bool TRI_HasDuplicateKeyJson (TRI_json_t const* object) {
    if (object && object->_type == TRI_JSON_OBJECT) {
        size_t const n = TRI_LengthVector(&object->_value._objects);
        const bool hasMultipleElements = (n > 2);

        // if we don't have attributes, we do not need to check for duplicates
        // if we only have one attribute, we don't need to check for duplicates in
        // the array, but we need to recursively validate the array values (if
        // array value itself is an array)
        if (n > 0) {
            TRI_associative_pointer_t hash;
            size_t i;

            if (hasMultipleElements) {
                TRI_InitAssociativePointer(&hash,
                                           TRI_UNKNOWN_MEM_ZONE,
                                           &TRI_HashStringKeyAssociativePointer,
                                           &TRI_HashStringKeyAssociativePointer,
                                           &TRI_EqualStringKeyAssociativePointer,
                                           0);
            }

            for (i = 0;  i < n; i += 2) {
                auto key = static_cast<TRI_json_t const*>(TRI_AtVector(&object->_value._objects, i));

                if (! TRI_IsStringJson(key)) {
                    continue;
                }

                auto value = static_cast<TRI_json_t const*>(TRI_AtVector(&object->_value._objects, i + 1));

                // recursively check sub-array elements
                if (value->_type == TRI_JSON_OBJECT && TRI_HasDuplicateKeyJson(value)) {
                    // duplicate found in sub-array
                    if (hasMultipleElements) {
                        TRI_DestroyAssociativePointer(&hash);
                    }

                    return true;
                }

                if (hasMultipleElements) {
                    void* previous = TRI_InsertKeyAssociativePointer(&hash, key->_value._string.data, key->_value._string.data, false);

                    if (previous != nullptr) {
                        // duplicate found
                        TRI_DestroyAssociativePointer(&hash);

                        return true;
                    }
                }
            }

            if (hasMultipleElements) {
                TRI_DestroyAssociativePointer(&hash);
            }
        }
    }

    // no duplicate found
    return false;
}
Пример #17
0
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
}