mirror of https://gitee.com/bigwinds/arangodb
1112 lines
41 KiB
C
1112 lines
41 KiB
C
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief compare methods used for skiplist indexes
|
|
///
|
|
/// @file
|
|
///
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright by triAGENS GmbH - All rights reserved.
|
|
///
|
|
/// The Programs (which include both the software and documentation)
|
|
/// contain proprietary information of triAGENS GmbH; they are
|
|
/// provided under a license agreement containing restrictions on use and
|
|
/// disclosure and are also protected by copyright, patent and other
|
|
/// intellectual and industrial property laws. Reverse engineering,
|
|
/// disassembly or decompilation of the Programs, except to the extent
|
|
/// required to obtain interoperability with other independently created
|
|
/// software or as specified by law, is prohibited.
|
|
///
|
|
/// The Programs are not intended for use in any nuclear, aviation, mass
|
|
/// transit, medical, or other inherently dangerous applications. It shall
|
|
/// be the licensee's responsibility to take all appropriate fail-safe,
|
|
/// backup, redundancy, and other measures to ensure the safe use of such
|
|
/// applications if the Programs are used for such purposes, and triAGENS
|
|
/// GmbH disclaims liability for any damages caused by such use of
|
|
/// the Programs.
|
|
///
|
|
/// This software is the confidential and proprietary information of
|
|
/// triAGENS GmbH. You shall not disclose such confidential and
|
|
/// proprietary information and shall use it only in accordance with the
|
|
/// terms of the license agreement you entered into with triAGENS GmbH.
|
|
///
|
|
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// @author Anonymous
|
|
/// @author Copyright 2011, triagens GmbH, Cologne, Germany
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef TRIAGENS_DURHAM_VOC_BASE_SKIPLIST_EX_COMPARE_H
|
|
#define TRIAGENS_DURHAM_VOC_BASE_SKIPLIST_EX_COMPARE_H 1
|
|
|
|
#include "ShapedJson/json-shaper.h"
|
|
#include "ShapedJson/shaped-json.h"
|
|
#include "VocBase/primary-collection.h"
|
|
#include "BasicsC/utf8-helper.h"
|
|
|
|
#ifdef TRI_SKIPLIST_EX
|
|
|
|
#define USE_STATIC_SKIPLIST_EX_COMPARE 1
|
|
|
|
#define SKIPLIST_EX_ELEMENT_TYPE(a,b) \
|
|
struct a { \
|
|
size_t numFields; \
|
|
TRI_shaped_json_t* fields; \
|
|
void* data; \
|
|
void* collection; \
|
|
} b
|
|
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
static int IndexStaticCopyElementElement (TRI_skiplistEx_base_t* skiplist, void* left, void* right) {
|
|
typedef SKIPLIST_EX_ELEMENT_TYPE(LocalElement_s,LocalElement_t);
|
|
|
|
LocalElement_t* leftElement = (LocalElement_t*)(left);
|
|
LocalElement_t* rightElement = (LocalElement_t*)(right);
|
|
|
|
if (leftElement == NULL || rightElement == NULL) {
|
|
assert(0);
|
|
return TRI_ERROR_INTERNAL;
|
|
}
|
|
|
|
leftElement->numFields = rightElement->numFields;
|
|
leftElement->data = rightElement->data;
|
|
leftElement->collection = rightElement->collection;
|
|
leftElement->fields = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_shaped_json_t) * leftElement->numFields, false);
|
|
|
|
if (leftElement->fields == NULL) {
|
|
return TRI_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
memcpy(leftElement->fields, rightElement->fields, sizeof(TRI_shaped_json_t) * leftElement->numFields);
|
|
|
|
return TRI_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief destroys an element -- removing any allocated memory within the structure
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void IndexStaticDestroyElement(TRI_skiplistEx_base_t* skiplist, void* element) {
|
|
typedef SKIPLIST_EX_ELEMENT_TYPE(LocalElement_s,LocalElement_t);
|
|
|
|
// ...........................................................................
|
|
// Each 'field' in the hElement->fields is a TRI_shaped_json_t object, this
|
|
// structure has internal structure of its own -- which also has memory
|
|
// allocated -- HOWEVER we DO NOT deallocate this memory here since it
|
|
// is actually part of the document structure. This memory should be deallocated
|
|
// when the document has been destroyed.
|
|
// ...........................................................................
|
|
|
|
LocalElement_t* hElement = (LocalElement_t*)(element);
|
|
if (element != NULL) {
|
|
if (hElement->fields != NULL) {
|
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, hElement->fields);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// .............................................................................
|
|
// left < right return -1
|
|
// left > right return 1
|
|
// left == right return 0
|
|
// .............................................................................
|
|
|
|
typedef struct weighted_attribute_s {
|
|
TRI_shape_aid_t _aid;
|
|
int64_t _weight;
|
|
TRI_shaped_json_t _value;
|
|
//const TRI_shape_t* _shape;
|
|
//const char* _aname;
|
|
const TRI_shaper_t* _shaper;
|
|
} weighted_attribute_t;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Helper method to deal with freeing memory associated with
|
|
/// the weight comparisions
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void freeShapeTypeJsonArrayHelper(weighted_attribute_t** leftWeightedList,
|
|
weighted_attribute_t** rightWeightedList) {
|
|
if (*leftWeightedList != NULL) {
|
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, *leftWeightedList);
|
|
*leftWeightedList = NULL;
|
|
}
|
|
if (*rightWeightedList != NULL) {
|
|
TRI_Free(TRI_UNKNOWN_MEM_ZONE, *rightWeightedList);
|
|
*rightWeightedList = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
// return the number of entries
|
|
static int compareShapeTypeJsonArrayHelper(const TRI_shape_t* shape, const TRI_shaper_t* shaper,
|
|
const TRI_shaped_json_t* shapedJson,
|
|
weighted_attribute_t** attributeArray) {
|
|
char* charShape = (char*)(shape);
|
|
TRI_shape_size_t fixedEntries; // the number of entries in the JSON array whose value is of a fixed size
|
|
TRI_shape_size_t variableEntries; // the number of entries in the JSON array whose value is not of a known fixed size
|
|
TRI_shape_size_t j;
|
|
int jj;
|
|
const TRI_shape_aid_t* aids;
|
|
const TRI_shape_sid_t* sids;
|
|
const TRI_shape_size_t* offsets;
|
|
|
|
// .............................................................................
|
|
// Ensure we return an empty array - in case of funny business below
|
|
// .............................................................................
|
|
|
|
*attributeArray = NULL;
|
|
|
|
|
|
// .............................................................................
|
|
// Determine the number of fixed sized values
|
|
// .............................................................................
|
|
|
|
charShape = charShape + sizeof(TRI_shape_t);
|
|
fixedEntries = *((TRI_shape_size_t*)(charShape));
|
|
|
|
|
|
// .............................................................................
|
|
// Determine the number of variable sized values
|
|
// .............................................................................
|
|
|
|
charShape = charShape + sizeof(TRI_shape_size_t);
|
|
variableEntries = *((TRI_shape_size_t*)(charShape));
|
|
|
|
|
|
// .............................................................................
|
|
// It may happen that the shaped_json_array is 'empty {}'
|
|
// .............................................................................
|
|
|
|
if ((fixedEntries + variableEntries) == 0) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
// .............................................................................
|
|
// Allocate memory to hold the attribute information required for comparison
|
|
// .............................................................................
|
|
|
|
*attributeArray = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, (sizeof(weighted_attribute_t) * (fixedEntries + variableEntries)), false);
|
|
if (*attributeArray == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
|
|
// .............................................................................
|
|
// Determine the list of shape identifiers
|
|
// .............................................................................
|
|
|
|
charShape = charShape + sizeof(TRI_shape_size_t);
|
|
sids = (const TRI_shape_sid_t*)(charShape);
|
|
|
|
charShape = charShape + (sizeof(TRI_shape_sid_t) * (fixedEntries + variableEntries));
|
|
aids = (const TRI_shape_aid_t*)(charShape);
|
|
|
|
charShape = charShape + (sizeof(TRI_shape_aid_t) * (fixedEntries + variableEntries));
|
|
offsets = (const TRI_shape_size_t*)(charShape);
|
|
|
|
for (j = 0; j < fixedEntries; ++j) {
|
|
(*attributeArray)[j]._aid = aids[j];
|
|
(*attributeArray)[j]._weight = shaper->lookupAttributeWeight((TRI_shaper_t*)(shaper),aids[j]);
|
|
//(*attributeArray)[j]._shape = shaper->lookupShapeId((TRI_shaper_t*)(shaper), sids[j]);
|
|
(*attributeArray)[j]._value._sid = sids[j];
|
|
(*attributeArray)[j]._value._data.data = shapedJson->_data.data + offsets[j];
|
|
(*attributeArray)[j]._value._data.length = offsets[j + 1] - offsets[j];
|
|
(*attributeArray)[j]._shaper = shaper;
|
|
//(*attributeArray)[j]._aname = NULL;
|
|
}
|
|
|
|
offsets = (const TRI_shape_size_t*)(shapedJson->_data.data);
|
|
for (j = 0; j < variableEntries; ++j) {
|
|
jj = j + fixedEntries;
|
|
(*attributeArray)[jj]._aid = aids[jj];
|
|
(*attributeArray)[jj]._weight = shaper->lookupAttributeWeight((TRI_shaper_t*)(shaper),aids[jj]);
|
|
//(*attributeArray)[jj]._shape = shaper->lookupShapeId((TRI_shaper_t*)(shaper), sids[jj]);
|
|
(*attributeArray)[jj]._value._sid = sids[jj];
|
|
(*attributeArray)[jj]._value._data.data = shapedJson->_data.data + offsets[j];
|
|
(*attributeArray)[jj]._value._data.length = offsets[j + 1] - offsets[j];
|
|
(*attributeArray)[jj]._shaper = shaper;
|
|
//(*attributeArray)[jj]._aname = NULL;
|
|
}
|
|
|
|
return (fixedEntries + variableEntries);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Compares to weighted attributes
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int attributeWeightCompareFunction(const void* leftItem, const void* rightItem) {
|
|
const weighted_attribute_t* l = (const weighted_attribute_t*)(leftItem);
|
|
const weighted_attribute_t* r = (const weighted_attribute_t*)(rightItem);
|
|
|
|
if (l->_weight < r->_weight) { return -1; }
|
|
if (l->_weight > r->_weight) { return 1; }
|
|
return 0;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Helper method for recursion for CompareShapedJsonShapedJson
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
static int CompareShapeTypes (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right, TRI_shaper_t* leftShaper, TRI_shaper_t* rightShaper) {
|
|
|
|
int result;
|
|
int i;
|
|
size_t j;
|
|
TRI_shape_type_t leftType;
|
|
TRI_shape_type_t rightType;
|
|
const TRI_shape_t* leftShape;
|
|
const TRI_shape_t* rightShape;
|
|
size_t leftListLength;
|
|
size_t rightListLength;
|
|
size_t listLength;
|
|
TRI_shaped_json_t leftElement;
|
|
TRI_shaped_json_t rightElement;
|
|
char* leftString;
|
|
char* rightString;
|
|
weighted_attribute_t* leftWeightedList;
|
|
weighted_attribute_t* rightWeightedList;
|
|
int leftNumWeightedList;
|
|
int rightNumWeightedList;
|
|
int numWeightedList;
|
|
|
|
leftShape = leftShaper->lookupShapeId(leftShaper, left->_sid);
|
|
rightShape = rightShaper->lookupShapeId(rightShaper, right->_sid);
|
|
leftType = leftShape->_type;
|
|
rightType = rightShape->_type;
|
|
|
|
switch (leftType) {
|
|
|
|
case TRI_SHAPE_ILLEGAL: {
|
|
switch (rightType) {
|
|
case TRI_SHAPE_ILLEGAL: {
|
|
return 0;
|
|
}
|
|
case TRI_SHAPE_NULL:
|
|
case TRI_SHAPE_BOOLEAN:
|
|
case TRI_SHAPE_NUMBER:
|
|
case TRI_SHAPE_SHORT_STRING:
|
|
case TRI_SHAPE_LONG_STRING:
|
|
case TRI_SHAPE_ARRAY:
|
|
case TRI_SHAPE_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: {
|
|
return -1;
|
|
}
|
|
} // end of switch (rightType)
|
|
} // end of case TRI_SHAPE_ILLEGAL
|
|
|
|
|
|
case TRI_SHAPE_NULL: {
|
|
switch (rightType) {
|
|
case TRI_SHAPE_ILLEGAL: {
|
|
return 1;
|
|
}
|
|
case TRI_SHAPE_NULL: {
|
|
return 0;
|
|
}
|
|
case TRI_SHAPE_BOOLEAN:
|
|
case TRI_SHAPE_NUMBER:
|
|
case TRI_SHAPE_SHORT_STRING:
|
|
case TRI_SHAPE_LONG_STRING:
|
|
case TRI_SHAPE_ARRAY:
|
|
case TRI_SHAPE_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: {
|
|
return -1;
|
|
}
|
|
} // end of switch (rightType)
|
|
} // end of case TRI_SHAPE_NULL
|
|
|
|
|
|
case TRI_SHAPE_BOOLEAN: {
|
|
switch (rightType) {
|
|
case TRI_SHAPE_ILLEGAL:
|
|
case TRI_SHAPE_NULL: {
|
|
return 1;
|
|
}
|
|
case TRI_SHAPE_BOOLEAN: {
|
|
// check which is false and which is true!
|
|
if ( *((TRI_shape_boolean_t*)(left->_data.data)) == *((TRI_shape_boolean_t*)(right->_data.data)) ) {
|
|
return 0;
|
|
}
|
|
if ( *((TRI_shape_boolean_t*)(left->_data.data)) < *((TRI_shape_boolean_t*)(right->_data.data)) ) {
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
case TRI_SHAPE_NUMBER:
|
|
case TRI_SHAPE_SHORT_STRING:
|
|
case TRI_SHAPE_LONG_STRING:
|
|
case TRI_SHAPE_ARRAY:
|
|
case TRI_SHAPE_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: {
|
|
return -1;
|
|
}
|
|
} // end of switch (rightType)
|
|
} // end of case TRI_SHAPE_BOOLEAN
|
|
|
|
|
|
case TRI_SHAPE_NUMBER: {
|
|
switch (rightType) {
|
|
case TRI_SHAPE_ILLEGAL:
|
|
case TRI_SHAPE_NULL:
|
|
case TRI_SHAPE_BOOLEAN: {
|
|
return 1;
|
|
}
|
|
case TRI_SHAPE_NUMBER: {
|
|
// compare the numbers
|
|
if ( *((TRI_shape_number_t*)(left->_data.data)) == *((TRI_shape_number_t*)(right->_data.data)) ) {
|
|
return 0;
|
|
}
|
|
if ( *((TRI_shape_number_t*)(left->_data.data)) < *((TRI_shape_number_t*)(right->_data.data)) ) {
|
|
return -1;
|
|
}
|
|
return 1;
|
|
}
|
|
case TRI_SHAPE_SHORT_STRING:
|
|
case TRI_SHAPE_LONG_STRING:
|
|
case TRI_SHAPE_ARRAY:
|
|
case TRI_SHAPE_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: {
|
|
return -1;
|
|
}
|
|
} // end of switch (rightType)
|
|
} // end of case TRI_SHAPE_NUMBER
|
|
|
|
|
|
|
|
case TRI_SHAPE_SHORT_STRING:
|
|
case TRI_SHAPE_LONG_STRING: {
|
|
switch (rightType) {
|
|
case TRI_SHAPE_ILLEGAL:
|
|
case TRI_SHAPE_NULL:
|
|
case TRI_SHAPE_BOOLEAN:
|
|
case TRI_SHAPE_NUMBER: {
|
|
return 1;
|
|
}
|
|
case TRI_SHAPE_SHORT_STRING:
|
|
case TRI_SHAPE_LONG_STRING: {
|
|
// compare strings
|
|
// extract the strings
|
|
if (leftType == TRI_SHAPE_SHORT_STRING) {
|
|
leftString = (char*)(sizeof(TRI_shape_length_short_string_t) + left->_data.data);
|
|
}
|
|
else {
|
|
leftString = (char*)(sizeof(TRI_shape_length_long_string_t) + left->_data.data);
|
|
}
|
|
|
|
if (rightType == TRI_SHAPE_SHORT_STRING) {
|
|
rightString = (char*)(sizeof(TRI_shape_length_short_string_t) + right->_data.data);
|
|
}
|
|
else {
|
|
rightString = (char*)(sizeof(TRI_shape_length_long_string_t) + right->_data.data);
|
|
}
|
|
|
|
#ifdef TRI_HAVE_ICU
|
|
result = TRI_compare_utf8(leftString,rightString);
|
|
#else
|
|
result = strcmp(leftString,rightString);
|
|
#endif
|
|
return result;
|
|
}
|
|
case TRI_SHAPE_ARRAY:
|
|
case TRI_SHAPE_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST: {
|
|
return -1;
|
|
}
|
|
} // end of switch (rightType)
|
|
} // end of case TRI_SHAPE_LONG/SHORT_STRING
|
|
|
|
|
|
case TRI_SHAPE_HOMOGENEOUS_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST:
|
|
case TRI_SHAPE_LIST: {
|
|
switch (rightType) {
|
|
case TRI_SHAPE_ILLEGAL:
|
|
case TRI_SHAPE_NULL:
|
|
case TRI_SHAPE_BOOLEAN:
|
|
case TRI_SHAPE_NUMBER:
|
|
case TRI_SHAPE_SHORT_STRING:
|
|
case TRI_SHAPE_LONG_STRING: {
|
|
return 1;
|
|
}
|
|
case TRI_SHAPE_HOMOGENEOUS_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST:
|
|
case TRI_SHAPE_LIST: {
|
|
// unfortunately recursion: check the types of all the entries
|
|
leftListLength = *((TRI_shape_length_list_t*)(left->_data.data));
|
|
rightListLength = *((TRI_shape_length_list_t*)(right->_data.data));
|
|
|
|
// determine the smallest list
|
|
if (leftListLength > rightListLength) {
|
|
listLength = rightListLength;
|
|
}
|
|
else {
|
|
listLength = leftListLength;
|
|
}
|
|
|
|
for (j = 0; j < listLength; ++j) {
|
|
|
|
if (leftType == TRI_SHAPE_HOMOGENEOUS_LIST) {
|
|
TRI_AtHomogeneousListShapedJson((const TRI_homogeneous_list_shape_t*)(leftShape),
|
|
left,j,&leftElement);
|
|
}
|
|
else if (leftType == TRI_SHAPE_HOMOGENEOUS_SIZED_LIST) {
|
|
TRI_AtHomogeneousSizedListShapedJson((const TRI_homogeneous_sized_list_shape_t*)(leftShape),
|
|
left,j,&leftElement);
|
|
}
|
|
else {
|
|
TRI_AtListShapedJson((const TRI_list_shape_t*)(leftShape),left,j,&leftElement);
|
|
}
|
|
|
|
|
|
if (rightType == TRI_SHAPE_HOMOGENEOUS_LIST) {
|
|
TRI_AtHomogeneousListShapedJson((const TRI_homogeneous_list_shape_t*)(rightShape),
|
|
right,j,&rightElement);
|
|
}
|
|
else if (rightType == TRI_SHAPE_HOMOGENEOUS_SIZED_LIST) {
|
|
TRI_AtHomogeneousSizedListShapedJson((const TRI_homogeneous_sized_list_shape_t*)(rightShape),
|
|
right,j,&rightElement);
|
|
}
|
|
else {
|
|
TRI_AtListShapedJson((const TRI_list_shape_t*)(rightShape),right,j,&rightElement);
|
|
}
|
|
|
|
result = CompareShapeTypes (&leftElement, &rightElement, leftShaper, rightShaper);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// up to listLength everything matches
|
|
if (leftListLength < rightListLength) {
|
|
return -1;
|
|
}
|
|
else if (leftListLength > rightListLength) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
case TRI_SHAPE_ARRAY:
|
|
{
|
|
return -1;
|
|
}
|
|
} // end of switch (rightType)
|
|
} // end of case TRI_SHAPE_LIST ...
|
|
|
|
|
|
|
|
case TRI_SHAPE_ARRAY: {
|
|
switch (rightType) {
|
|
case TRI_SHAPE_ILLEGAL:
|
|
case TRI_SHAPE_NULL:
|
|
case TRI_SHAPE_BOOLEAN:
|
|
case TRI_SHAPE_NUMBER:
|
|
case TRI_SHAPE_SHORT_STRING:
|
|
case TRI_SHAPE_LONG_STRING:
|
|
case TRI_SHAPE_HOMOGENEOUS_LIST:
|
|
case TRI_SHAPE_HOMOGENEOUS_SIZED_LIST:
|
|
case TRI_SHAPE_LIST: {
|
|
return 1;
|
|
}
|
|
|
|
case TRI_SHAPE_ARRAY: {
|
|
assert(0);
|
|
// ............................................................................
|
|
// We are comparing a left JSON array with another JSON array on the right
|
|
// The comparison works as follows:
|
|
//
|
|
// Suppose that leftShape has m key/value pairs and that the
|
|
// rightShape has n key/value pairs
|
|
//
|
|
// Extract the m key aids (attribute identifiers) from the leftShape
|
|
// Extract the n key aids (attribute identifiers) from the rightShape
|
|
//
|
|
// Sort the key aids for both the left and right shape
|
|
// according to the weight of the key (attribute)
|
|
//
|
|
// Let lw_j denote the weight of the jth key from the sorted leftShape key list
|
|
// and rw_j the corresponding rightShape.
|
|
//
|
|
// If lw_j < rw_j return -1
|
|
// If lw_j > rw_j return 1
|
|
// If lw_j == rw_j, then we extract the values and compare the values
|
|
// using recursion.
|
|
//
|
|
// If lv_j < rv_j return -1
|
|
// If lv_j > rv_j return 1
|
|
// If lv_j == rv_j, then repeat the process with j+1.
|
|
// ............................................................................
|
|
|
|
|
|
// ............................................................................
|
|
// generate the left and right lists.
|
|
// ............................................................................
|
|
|
|
leftNumWeightedList = compareShapeTypeJsonArrayHelper(leftShape, leftShaper, left, &leftWeightedList);
|
|
rightNumWeightedList = compareShapeTypeJsonArrayHelper(rightShape, rightShaper, right, &rightWeightedList);
|
|
|
|
|
|
// ............................................................................
|
|
// If the left and right both resulted in errors, we return equality for want
|
|
// of something better.
|
|
// ............................................................................
|
|
|
|
if ( (leftNumWeightedList < 0) && (rightNumWeightedList < 0) ) { // probably out of memory error
|
|
freeShapeTypeJsonArrayHelper(&leftWeightedList, &rightWeightedList);
|
|
return 0;
|
|
}
|
|
|
|
// ............................................................................
|
|
// If the left had an error, we rank the left as the smallest item in the order
|
|
// ............................................................................
|
|
|
|
if (leftNumWeightedList < 0) { // probably out of memory error
|
|
freeShapeTypeJsonArrayHelper(&leftWeightedList, &rightWeightedList);
|
|
return -1; // attempt to compare as low as possible
|
|
}
|
|
|
|
|
|
// ............................................................................
|
|
// If the right had an error, we rank the right as the largest item in the order
|
|
// ............................................................................
|
|
|
|
if (rightNumWeightedList < 0) {
|
|
freeShapeTypeJsonArrayHelper(&leftWeightedList, &rightWeightedList);
|
|
return 1;
|
|
}
|
|
|
|
|
|
// ............................................................................
|
|
// Are we comparing two empty shaped_json_arrays?
|
|
// ............................................................................
|
|
|
|
if ( (leftNumWeightedList == 0) && (rightNumWeightedList == 0) ) {
|
|
freeShapeTypeJsonArrayHelper(&leftWeightedList, &rightWeightedList);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ............................................................................
|
|
// If the left is empty, then it is smaller than the right, right?
|
|
// ............................................................................
|
|
|
|
if (leftNumWeightedList == 0) {
|
|
freeShapeTypeJsonArrayHelper(&leftWeightedList, &rightWeightedList);
|
|
return -1;
|
|
}
|
|
|
|
|
|
// ............................................................................
|
|
// ...and the opposite of the above.
|
|
// ............................................................................
|
|
|
|
if (rightNumWeightedList == 0) {
|
|
freeShapeTypeJsonArrayHelper(&leftWeightedList, &rightWeightedList);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
// ..............................................................................
|
|
// We now have to sort the left and right weighted list according to attribute weight
|
|
// ..............................................................................
|
|
|
|
qsort(leftWeightedList, leftNumWeightedList, sizeof(weighted_attribute_t), attributeWeightCompareFunction);
|
|
qsort(rightWeightedList, rightNumWeightedList, sizeof(weighted_attribute_t), attributeWeightCompareFunction);
|
|
|
|
|
|
// ..............................................................................
|
|
// check the weight and if equal check the values. Notice that numWeightedList
|
|
// below MUST be greater or equal to 1.
|
|
// ..............................................................................
|
|
|
|
numWeightedList = (leftNumWeightedList < rightNumWeightedList ? leftNumWeightedList: rightNumWeightedList);
|
|
|
|
for (i = 0; i < numWeightedList; ++i) {
|
|
|
|
if (leftWeightedList[i]._weight != rightWeightedList[i]._weight) {
|
|
result = (leftWeightedList[i]._weight < rightWeightedList[i]._weight ? -1: 1);
|
|
break;
|
|
}
|
|
|
|
result = CompareShapeTypes (&(leftWeightedList[i]._value), &(rightWeightedList[i]._value), leftShaper, rightShaper);
|
|
if (result != 0) {
|
|
break;
|
|
}
|
|
|
|
// the attributes are equal now check for the values
|
|
/* start oreste debug
|
|
const char* name = leftShaper->lookupAttributeId(leftShaper,leftWeightedList[i]._aid);
|
|
printf("%s:%u:w=%ld:%s\n",__FILE__,__LINE__,leftWeightedList[i]._weight,name);
|
|
const char* name = rightShaper->lookupAttributeId(rightShaper,rightWeightedList[i]._aid);
|
|
printf("%s:%u:w=%ld:%s\n",__FILE__,__LINE__,rightWeightedList[i]._weight,name);
|
|
end oreste debug */
|
|
}
|
|
|
|
|
|
if (result == 0) {
|
|
// ............................................................................
|
|
// The comparisions above indicate that the shaped_json_arrays are equal,
|
|
// however one more check to determine if the number of elements in the arrays
|
|
// are equal.
|
|
// ............................................................................
|
|
if (leftNumWeightedList < rightNumWeightedList) {
|
|
result = -1;
|
|
}
|
|
else if (leftNumWeightedList > rightNumWeightedList) {
|
|
result = 1;
|
|
}
|
|
}
|
|
|
|
|
|
// ..............................................................................
|
|
// Deallocate any memory for the comparisions and return the result
|
|
// ..............................................................................
|
|
|
|
freeShapeTypeJsonArrayHelper(&leftWeightedList, &rightWeightedList);
|
|
return result;
|
|
}
|
|
} // end of switch (rightType)
|
|
} // end of case TRI_SHAPE_ARRAY
|
|
|
|
} // end of switch (leftType)
|
|
|
|
assert(false);
|
|
|
|
return 0; //shut the vc++ up
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Compare a shapded json object recursively if necessary
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int CompareShapedJsonShapedJson (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right, TRI_shaper_t* leftShaper, TRI_shaper_t* rightShaper) {
|
|
|
|
int result;
|
|
|
|
// ............................................................................
|
|
// the following order is currently defined for placing an order on documents
|
|
// undef < null < boolean < number < strings < lists < hash arrays
|
|
// note: undefined will be treated as NULL pointer not NULL JSON OBJECT
|
|
// within each type class we have the following order
|
|
// boolean: false < true
|
|
// number: natural order
|
|
// strings: lexicographical
|
|
// lists: lexicorgraphically and within each slot according to these rules.
|
|
// ............................................................................
|
|
|
|
|
|
if (left == NULL && right == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (left == NULL && right != NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (left != NULL && right == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
result = CompareShapeTypes (left, right, leftShaper, rightShaper);
|
|
|
|
|
|
// ............................................................................
|
|
// In the above function CompareShaeTypes we use strcmp which may return
|
|
// an integer greater than 1 or less than -1. From this function we only
|
|
// need to know whether we have equality (0), less than (-1) or greater than (1)
|
|
// ............................................................................
|
|
|
|
if (result < 0) {
|
|
result = -1;
|
|
}
|
|
else if (result > 0) {
|
|
result = 1;
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
} // end of function CompareShapedJsonShapedJson
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief compares two elements in a skip list
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int IndexStaticCompareElementElement (struct TRI_skiplistEx_s* skiplist, void* leftElement, void* rightElement, int defaultEqual) {
|
|
typedef SKIPLIST_EX_ELEMENT_TYPE(LocalElement_s,LocalElement_t);
|
|
// .............................................................................
|
|
// Compare two elements and determines:
|
|
// left < right : return -1
|
|
// left == right : return 0
|
|
// left > right : return 1
|
|
// .............................................................................
|
|
int compareResult;
|
|
LocalElement_t* hLeftElement = (LocalElement_t*)(leftElement);
|
|
LocalElement_t* hRightElement = (LocalElement_t*)(rightElement);
|
|
TRI_shaper_t* leftShaper;
|
|
TRI_shaper_t* rightShaper;
|
|
size_t j;
|
|
|
|
// ............................................................................
|
|
// the following order is currently defined for placing an order on documents
|
|
// undef < null < boolean < number < strings < lists < hash arrays
|
|
// note: undefined will be treated as NULL pointer not NULL JSON OBJECT
|
|
// within each type class we have the following order
|
|
// boolean: false < true
|
|
// number: natural order
|
|
// strings: lexicographical
|
|
// lists: lexicographically and within each slot according to these rules.
|
|
// ............................................................................
|
|
|
|
if (leftElement == NULL && rightElement == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (leftElement != NULL && rightElement == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
if (leftElement == NULL && rightElement != NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (leftElement == rightElement) {
|
|
return 0;
|
|
}
|
|
|
|
// ............................................................................
|
|
// This call back function is used when we insert and remove unique skip
|
|
// list entries.
|
|
// ............................................................................
|
|
|
|
if (hLeftElement->numFields != hRightElement->numFields) {
|
|
assert(false);
|
|
}
|
|
|
|
|
|
// ............................................................................
|
|
// The document could be the same -- so no further comparison is required.
|
|
// ............................................................................
|
|
if (hLeftElement->data == hRightElement->data) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
leftShaper = ((TRI_primary_collection_t*)(hLeftElement->collection))->_shaper;
|
|
rightShaper = ((TRI_primary_collection_t*)(hRightElement->collection))->_shaper;
|
|
|
|
for (j = 0; j < hLeftElement->numFields; j++) {
|
|
compareResult = CompareShapedJsonShapedJson((j + hLeftElement->fields), (j + hRightElement->fields), leftShaper, rightShaper);
|
|
if (compareResult != 0) {
|
|
return compareResult;
|
|
}
|
|
}
|
|
|
|
// ............................................................................
|
|
// This is where the difference between CompareKeyElement (below) and
|
|
// CompareElementElement comes into play. Here if the 'keys' are the same,
|
|
// but the doc ptr is different (which it is since we are here), then
|
|
// we return what was requested to be returned: 0,-1 or 1. What is returned
|
|
// depends on the purpose of calling this callback.
|
|
// ............................................................................
|
|
|
|
return defaultEqual;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief compares a key and an element
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int IndexStaticCompareKeyElement (struct TRI_skiplistEx_s* skiplist, void* leftElement, void* rightElement, int defaultEqual) {
|
|
typedef SKIPLIST_EX_ELEMENT_TYPE(LocalElement_s,LocalElement_t);
|
|
|
|
// .............................................................................
|
|
// Compare two elements and determines:
|
|
// left < right : return -1
|
|
// left == right : return 0
|
|
// left > right : return 1
|
|
// .............................................................................
|
|
int compareResult;
|
|
size_t numFields;
|
|
LocalElement_t* hLeftElement = (LocalElement_t*)(leftElement);
|
|
LocalElement_t* hRightElement = (LocalElement_t*)(rightElement);
|
|
TRI_shaper_t* leftShaper;
|
|
TRI_shaper_t* rightShaper;
|
|
size_t j;
|
|
|
|
// ............................................................................
|
|
// the following order is currently defined for placing an order on documents
|
|
// undef < null < boolean < number < strings < lists < hash arrays
|
|
// note: undefined will be treated as NULL pointer not NULL JSON OBJECT
|
|
// within each type class we have the following order
|
|
// boolean: false < true
|
|
// number: natural order
|
|
// strings: lexicographical
|
|
// lists: lexicorgraphically and within each slot according to these rules.
|
|
// associative array: ordered keys followed by value of key
|
|
// ............................................................................
|
|
|
|
if (leftElement == NULL && rightElement == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (leftElement == NULL && rightElement != NULL) {
|
|
return -1;
|
|
}
|
|
|
|
if (leftElement != NULL && rightElement == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
if (leftElement == rightElement) {
|
|
return 0;
|
|
}
|
|
|
|
// ............................................................................
|
|
// The document could be the same -- so no further comparison is required.
|
|
// ............................................................................
|
|
if (hLeftElement->data == hRightElement->data) {
|
|
return 0;
|
|
}
|
|
|
|
// ............................................................................
|
|
// This call back function is used when we query the index, as such
|
|
// the number of fields which we are using for the query may be less than
|
|
// the number of fields that the index is defined with.
|
|
// ............................................................................
|
|
|
|
|
|
if (hLeftElement->numFields < hRightElement->numFields) {
|
|
numFields = hLeftElement->numFields;
|
|
}
|
|
else {
|
|
numFields = hRightElement->numFields;
|
|
}
|
|
|
|
|
|
leftShaper = ((TRI_primary_collection_t*)(hLeftElement->collection))->_shaper;
|
|
rightShaper = ((TRI_primary_collection_t*)(hRightElement->collection))->_shaper;
|
|
|
|
for (j = 0; j < numFields; j++) {
|
|
compareResult = CompareShapedJsonShapedJson((j + hLeftElement->fields),
|
|
(j + hRightElement->fields),
|
|
leftShaper,
|
|
rightShaper);
|
|
if (compareResult != 0) {
|
|
return compareResult;
|
|
}
|
|
}
|
|
|
|
// ............................................................................
|
|
// The 'keys' match -- however, we may only have a partial match in reality
|
|
// if not all keys comprising index have been used.
|
|
// ............................................................................
|
|
return defaultEqual;
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------
|
|
//--------------------------------------------------------------------------------
|
|
// Non-unique skiplist
|
|
//--------------------------------------------------------------------------------
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief used to determine the order of two elements
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int IndexStaticMultiCompareElementElement (TRI_skiplistEx_multi_t* multiSkiplist, void* leftElement, void* rightElement, int defaultEqual) {
|
|
typedef SKIPLIST_EX_ELEMENT_TYPE(LocalElement_s,LocalElement_t);
|
|
|
|
int compareResult;
|
|
LocalElement_t* hLeftElement = (LocalElement_t*)(leftElement);
|
|
LocalElement_t* hRightElement = (LocalElement_t*)(rightElement);
|
|
TRI_shaper_t* leftShaper;
|
|
TRI_shaper_t* rightShaper;
|
|
size_t j;
|
|
|
|
|
|
if (leftElement == NULL && rightElement == NULL) {
|
|
return TRI_SKIPLIST_EX_COMPARE_STRICTLY_EQUAL;
|
|
}
|
|
|
|
if (leftElement != NULL && rightElement == NULL) {
|
|
return TRI_SKIPLIST_EX_COMPARE_STRICTLY_GREATER;
|
|
}
|
|
|
|
if (leftElement == NULL && rightElement != NULL) {
|
|
return TRI_SKIPLIST_EX_COMPARE_STRICTLY_LESS;
|
|
}
|
|
|
|
if (leftElement == rightElement) {
|
|
return TRI_SKIPLIST_EX_COMPARE_STRICTLY_EQUAL;
|
|
}
|
|
|
|
if (hLeftElement->numFields != hRightElement->numFields) {
|
|
assert(false);
|
|
}
|
|
|
|
if (hLeftElement->data == hRightElement->data) {
|
|
return TRI_SKIPLIST_EX_COMPARE_STRICTLY_EQUAL;
|
|
}
|
|
|
|
|
|
leftShaper = ((TRI_primary_collection_t*)(hLeftElement->collection))->_shaper;
|
|
rightShaper = ((TRI_primary_collection_t*)(hRightElement->collection))->_shaper;
|
|
|
|
for (j = 0; j < hLeftElement->numFields; j++) {
|
|
compareResult = CompareShapedJsonShapedJson((j + hLeftElement->fields), (j + hRightElement->fields), leftShaper, rightShaper);
|
|
if (compareResult != 0) {
|
|
|
|
// ......................................................................
|
|
// The function CompareShaedJsonShapedJson can only return 0, -1, or 1
|
|
// that is, TRI_SKIPLIST_COMPARE_STRICTLY_EQUAL (0)
|
|
// TRI_SKIPLIST_COMPARE_STRICTLY_LESS (-1)
|
|
// TRI_SKIPLIST_COMPARE_STRICTLY_GREATER (1)
|
|
// ......................................................................
|
|
|
|
return compareResult;
|
|
|
|
}
|
|
}
|
|
|
|
return defaultEqual;
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief used to determine the order of two keys
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static int IndexStaticMultiCompareKeyElement (TRI_skiplistEx_multi_t* multiSkiplist, void* leftElement, void* rightElement, int defaultEqual) {
|
|
typedef SKIPLIST_EX_ELEMENT_TYPE(LocalElement_s,LocalElement_t);
|
|
|
|
int compareResult;
|
|
size_t numFields;
|
|
LocalElement_t* hLeftElement = (LocalElement_t*)(leftElement);
|
|
LocalElement_t* hRightElement = (LocalElement_t*)(rightElement);
|
|
TRI_shaper_t* leftShaper;
|
|
TRI_shaper_t* rightShaper;
|
|
size_t j;
|
|
|
|
if (leftElement == NULL && rightElement == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (leftElement != NULL && rightElement == NULL) {
|
|
return 1;
|
|
}
|
|
|
|
if (leftElement == NULL && rightElement != NULL) {
|
|
return -1;
|
|
}
|
|
|
|
|
|
// ............................................................................
|
|
// The document could be the same -- so no further comparison is required.
|
|
// ............................................................................
|
|
|
|
if (hLeftElement->data == hRightElement->data) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
// ............................................................................
|
|
// This call back function is used when we query the index, as such
|
|
// the number of fields which we are using for the query may be less than
|
|
// the number of fields that the index is defined with.
|
|
// ............................................................................
|
|
|
|
if (hLeftElement->numFields < hRightElement->numFields) {
|
|
numFields = hLeftElement->numFields;
|
|
}
|
|
else {
|
|
numFields = hRightElement->numFields;
|
|
}
|
|
|
|
leftShaper = ((TRI_primary_collection_t*)(hLeftElement->collection))->_shaper;
|
|
rightShaper = ((TRI_primary_collection_t*)(hRightElement->collection))->_shaper;
|
|
|
|
for (j = 0; j < numFields; j++) {
|
|
compareResult = CompareShapedJsonShapedJson((j + hLeftElement->fields), (j + hRightElement->fields), leftShaper, rightShaper);
|
|
if (compareResult != 0) {
|
|
return compareResult;
|
|
}
|
|
}
|
|
|
|
return defaultEqual;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief used to determine the order of two keys
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool IndexStaticMultiEqualElementElement (TRI_skiplistEx_multi_t* multiSkiplist, void* leftElement, void* rightElement) {
|
|
typedef SKIPLIST_EX_ELEMENT_TYPE(LocalElement_s,LocalElement_t);
|
|
|
|
LocalElement_t* hLeftElement = (LocalElement_t*)(leftElement);
|
|
LocalElement_t* hRightElement = (LocalElement_t*)(rightElement);
|
|
|
|
if (leftElement == rightElement) {
|
|
return true;
|
|
}
|
|
|
|
return (hLeftElement->data == hRightElement->data);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
// Local Variables:
|
|
// mode: outline-minor
|
|
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
|
|
// End:
|
|
|