1
0
Fork 0
arangodb/PriorityQueue/pqueueindex.c

1065 lines
34 KiB
C

////////////////////////////////////////////////////////////////////////////////
/// @brief priority queue index
///
/// @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 Dr. O
/// @author Copyright 2011, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "pqueueindex.h"
#include "ShapedJson/shaped-json.h"
#include "ShapedJson/json-shaper.h"
#include "VocBase/document-collection.h"
#include <BasicsC/hashes.h>
#include <BasicsC/logging.h>
// -----------------------------------------------------------------------------
// --SECTION-- priority queue index some useful forward declarations
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup PriorityQueueIndex
/// @{
////////////////////////////////////////////////////////////////////////////////
// callbacks for the priority queue
static void ClearStoragePQIndex(TRI_pqueue_t*, void*);
static uint64_t GetStoragePQIndex(TRI_pqueue_t*, void*);
static bool IsLessPQIndex(TRI_pqueue_t*,void*, void*);
static void UpdateStoragePQIndex(TRI_pqueue_t*, void*, uint64_t);
// callbacks for the associative array
static void ClearElementPQIndex(TRI_associative_array_t*, void*);
static uint64_t HashKeyPQIndex(TRI_associative_array_t*, void*);
static uint64_t HashElementPQIndex(TRI_associative_array_t*, void*);
static bool IsEmptyElementPQIndex(TRI_associative_array_t*, void*);
static bool IsEqualElementElementPQIndex(TRI_associative_array_t*, void*, void*);
static bool IsEqualKeyElementPQIndex(TRI_associative_array_t*, void*, void*);
// comparison helpers
static int CompareShapedJsonShapedJson (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right,
TRI_shaper_t* leftShaper, TRI_shaper_t* rightShaper);
static int CompareShapeTypes (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right,
TRI_shaper_t* leftShaper, TRI_shaper_t* rightShaper);
// ...............................................................................
// some internal error numbers which can be mapped later to global error numbers
// ...............................................................................
enum {
PQIndex_InvalidIndexError = -1,
PQIndex_InvalidElementError = -10,
PQIndex_ElementMissingAssociativeArrayError = 1,
PQIndex_DuplicateElement = 10,
PQIndex_RemoveInternalError = 1001
} PQueueIndexErrors;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- priority queue index constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup PriorityQueueIndex
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief removes any allocated memory internal to the index structure
////////////////////////////////////////////////////////////////////////////////
void PQueueIndex_destroy(PQIndex* idx) {
if (idx == NULL) {
return;
}
TRI_FreePQueue(idx->_pq);
TRI_FreeAssociativeArray(TRI_UNKNOWN_MEM_ZONE, idx->_aa);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the index and frees any allocated memory
////////////////////////////////////////////////////////////////////////////////
void PQueueIndex_free(PQIndex* idx) {
if (idx == NULL) {
return;
}
PQueueIndex_destroy(idx);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a priority queue index
////////////////////////////////////////////////////////////////////////////////
PQIndex* PQueueIndex_new (void) {
PQIndex* idx;
bool ok;
// ..........................................................................
// Allocate the Priority Que Index
// ..........................................................................
idx = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(PQIndex), false);
if (idx == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
LOG_ERROR("out of memory when creating priority queue index");
return NULL;
}
// ..........................................................................
// Allocate the priority que
// Remember to add any additional structure you need
// ..........................................................................
idx->_pq = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_pqueue_t) + sizeof(void*), false);
if (idx->_pq == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx);
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
LOG_ERROR("out of memory when creating priority queue index");
return NULL;
}
// ..........................................................................
// Allocate the associative array
// ..........................................................................
idx->_aa = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_associative_array_t), false);
if (idx->_aa == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx->_pq);
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
LOG_ERROR("out of memory when creating priority queue index");
return NULL;
}
// ..........................................................................
// Initialise the priority que
// ..........................................................................
ok = TRI_InitPQueue(idx->_pq, 100, sizeof(PQIndexElement), false,
ClearStoragePQIndex,
GetStoragePQIndex,
IsLessPQIndex,
UpdateStoragePQIndex);
if (! ok) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx->_pq);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx->_aa);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, idx);
return NULL;
}
// ..........................................................................
// Initialise the associative array
// ..........................................................................
TRI_InitAssociativeArray(idx->_aa,
TRI_UNKNOWN_MEM_ZONE,
sizeof(PQIndexElement),
HashKeyPQIndex,
HashElementPQIndex,
ClearElementPQIndex,
IsEmptyElementPQIndex,
IsEqualKeyElementPQIndex,
IsEqualElementElementPQIndex);
// ..........................................................................
// Add the associative array at the end of the pq so that we can access later
//memcpy((char*)(idx->_pq) + sizeof(TRI_pqueue_t),&(idx->_aa),sizeof(TRI_associative_array_t*));
// ..........................................................................
*((TRI_associative_array_t**)((char*)(idx->_pq) + sizeof(TRI_pqueue_t))) = idx->_aa;
return idx;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- Priority Queue Index public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup PriorityQueueIndex
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief inserts an item into a priority queue
////////////////////////////////////////////////////////////////////////////////
int PQIndex_add(PQIndex* idx, PQIndexElement* element) {
if (idx == NULL) {
return TRI_ERROR_INTERNAL;
}
if (element == NULL) {
return TRI_ERROR_INTERNAL;
}
// ...........................................................................
// Check if item is already added to the associative array
// ...........................................................................
if (TRI_FindByKeyAssociativeArray(idx->_aa, element->data) != NULL) {
// attempt to add duplicate document to the priority queue
return TRI_ERROR_ARANGO_INDEX_PQ_INSERT_FAILED;
}
// ...........................................................................
// Initialise the priority queue array storage pointer
// ...........................................................................
element->pqSlot = 0;
// ...........................................................................
// Add item to associative array
// ...........................................................................
if (!TRI_InsertElementAssociativeArray(idx->_aa, element, false)) {
// can not add item to associative array -- give up on insert
return TRI_ERROR_ARANGO_INDEX_PQ_INSERT_FAILED;
}
if (!idx->_pq->add(idx->_pq, element)) {
TRI_RemoveElementAssociativeArray(idx->_aa, element, NULL);
// can not add item to priority queue array -- give up on insert
return TRI_ERROR_ARANGO_INDEX_PQ_INSERT_FAILED;
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief inserts an item into a priority queue (same as add method above)
////////////////////////////////////////////////////////////////////////////////
int PQIndex_insert(PQIndex* idx, PQIndexElement* element) {
return PQIndex_add(idx, element);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an item from the priority queue (not necessarily the top most)
////////////////////////////////////////////////////////////////////////////////
int PQIndex_remove(PQIndex* idx, PQIndexElement* element) {
PQIndexElement* item;
bool ok;
if (idx == NULL) {
return TRI_ERROR_ARANGO_INDEX_PQ_REMOVE_FAILED;
}
if (element == NULL) {
return TRI_ERROR_ARANGO_INDEX_PQ_REMOVE_FAILED;
}
// ...........................................................................
// Check if item exists in the associative array.
// ...........................................................................
item = TRI_FindByKeyAssociativeArray(idx->_aa, element->data);
if (item == NULL) {
return TRI_ERROR_ARANGO_INDEX_PQ_REMOVE_ITEM_MISSING;
}
// ...........................................................................
// Remove item from the priority queue
// ...........................................................................
ok = idx->_pq->remove(idx->_pq,item->pqSlot, true);
// ...........................................................................
// Remove item from associative array
// Must come after remove above, since update storage will be called.
// ...........................................................................
ok = TRI_RemoveElementAssociativeArray(idx->_aa,item,NULL) && ok;
if (!ok) {
return TRI_ERROR_ARANGO_INDEX_PQ_REMOVE_FAILED;
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the top most item without removing it from the queue
////////////////////////////////////////////////////////////////////////////////
PQIndexElements* PQIndex_top(PQIndex* idx, uint64_t numElements) {
PQIndexElements* result;
PQIndexElements tempResult;
PQIndexElement* element;
uint64_t j;
bool ok;
uint64_t numCopied;
if (idx == NULL) {
return NULL;
}
if (numElements < 1) {
return NULL;
}
// .............................................................................
// Optimise for the common case where we remove only a single element
// .............................................................................
if (numElements == 1) {
result = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(PQIndexElements), false);
if (result == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}
result->_elements = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(PQIndexElement) * numElements, false);
if (result->_elements == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, result);
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}
result->_numElements = numElements;
result->_elements[0] = *((PQIndexElement*)(idx->_pq->top(idx->_pq)));
return result;
}
// .............................................................................
// Two or more elements are 'topped'
// .............................................................................
tempResult._elements = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(PQIndexElement) * numElements, false);
if (tempResult._elements == NULL) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}
ok = true;
numCopied = 0;
for (j = 0; j < numElements; ++j) {
element = (PQIndexElement*)(idx->_pq->top(idx->_pq));
if (element == NULL) {
break;
}
tempResult._elements[j] = *element;
ok = idx->_pq->remove(idx->_pq,element->pqSlot, false);
if (!ok) {
break;
}
++numCopied;
}
result = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(PQIndexElements), false);
if (result == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, tempResult._elements);
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}
result->_elements = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(PQIndexElement) * numCopied, false);
if (result->_elements == NULL) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, tempResult._elements);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, result);
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
return NULL;
}
result->_numElements = numCopied;
for (j = 0; j < numCopied; ++j) {
result->_elements[j] = tempResult._elements[j];
result->_elements[j].pqSlot = 0;
idx->_pq->add(idx->_pq, &(result->_elements[j]));
}
TRI_Free(TRI_UNKNOWN_MEM_ZONE, tempResult._elements);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an item and inserts a new item
////////////////////////////////////////////////////////////////////////////////
bool PQIndex_update(PQIndex* idx, const PQIndexElement* oldElement, const PQIndexElement* newElement) {
assert(false);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- priority queue index implementation of callbacks
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup PriorityQueueIndex
/// @{
////////////////////////////////////////////////////////////////////////////////
// .............................................................................
// callbacks for the priority queue
// .............................................................................
static void ClearStoragePQIndex(TRI_pqueue_t* pq, void* item) {
PQIndexElement* element;
element = (PQIndexElement*)(item);
if (element == 0) {
return;
}
TRI_Free(TRI_UNKNOWN_MEM_ZONE, element->fields);
return;
}
static uint64_t GetStoragePQIndex(TRI_pqueue_t* pq, void* item) {
PQIndexElement* element;
element = (PQIndexElement*)(item);
if (element == 0) {
return 0;
}
return element->pqSlot;
}
// .............................................................................
// True if the leftItem is less than the rightItem
// .............................................................................
static bool IsLessPQIndex(TRI_pqueue_t* pq, void* leftItem, void* rightItem) {
size_t maxNumFields;
PQIndexElement* leftElement = (PQIndexElement*)(leftItem);
PQIndexElement* rightElement = (PQIndexElement*)(rightItem);
TRI_shaper_t* leftShaper;
TRI_shaper_t* rightShaper;
size_t j;
int compareResult;
if (leftElement == NULL && rightElement == NULL) {
return false;
}
if (leftElement == NULL && rightElement != NULL) {
return true;
}
if (leftElement != NULL && rightElement == NULL) {
return false;
}
if (leftElement == rightElement) {
return false;
}
// ............................................................................
// The document could be the same -- so no further comparison is required.
// ............................................................................
if (leftElement->data == rightElement->data) {
return false;
}
if (leftElement->numFields < rightElement->numFields) {
maxNumFields = leftElement->numFields;
}
else {
maxNumFields = rightElement->numFields;
}
leftShaper = ((TRI_doc_collection_t*)(leftElement->collection))->_shaper;
rightShaper = ((TRI_doc_collection_t*)(rightElement->collection))->_shaper;
compareResult = 0;
leftShaper->lookupShapeId(leftShaper, (leftElement->fields)->_sid);
for (j = 0; j < maxNumFields; j++) {
/*
printf("%s:%u:%f:%f,%u:%u\n",__FILE__,__LINE__,
*((double*)((j + leftElement->fields)->_data.data)),
*((double*)((j + rightElement->fields)->_data.data)),
(uint64_t)(leftElement->data),
(uint64_t)(rightElement->data)
);
*/
compareResult = CompareShapedJsonShapedJson((j + leftElement->fields),
(j + rightElement->fields),
leftShaper, rightShaper);
if (compareResult != 0) {
break;
}
}
if (compareResult < 0) {
return true;
}
return false;
}
static void UpdateStoragePQIndex(TRI_pqueue_t* pq, void* item, uint64_t position) {
PQIndexElement* element;
TRI_associative_array_t* aa;
element = (PQIndexElement*)(item);
if (element == 0) {
LOG_ERROR("invalid priority queue element received");
return;
}
element->pqSlot = position;
// ...........................................................................
// Since the items stored in the hash array are pointers, we must update these
// as well. The associative array is stored at the end of the Priority Queue
// structure.
// ...........................................................................
aa = *((TRI_associative_array_t**)((char*)(pq) + sizeof(TRI_pqueue_t)));
element = (PQIndexElement*)(TRI_FindByElementAssociativeArray(aa, item));
if (element == 0) {
LOG_ERROR("invalid priority queue/ associative array element received");
return;
}
element->pqSlot = position;
}
// .............................................................................
// callbacks for the associative array
// .............................................................................
static void ClearElementPQIndex(TRI_associative_array_t* aa, void* item) {
if (item == NULL) {
return;
}
memset(item, 0, sizeof(PQIndexElement));
}
static uint64_t HashKeyPQIndex(TRI_associative_array_t* aa, void* key) {
uint64_t hash;
hash = TRI_FnvHashBlockInitial();
hash = TRI_FnvHashBlock(hash, key, sizeof(void*));
return hash;
}
static uint64_t HashElementPQIndex(TRI_associative_array_t* aa, void* item) {
PQIndexElement* element;
uint64_t hash;
element = (PQIndexElement*)(item);
if (element == 0) {
return 0;
}
hash = TRI_FnvHashBlockInitial();
hash = TRI_FnvHashBlock(hash, element->data, sizeof(void*));
return hash;
}
static bool IsEmptyElementPQIndex(TRI_associative_array_t* aa, void* item) {
PQIndexElement* element;
if (item == NULL) {
// should never happen
return false;
}
element = (PQIndexElement*)(item);
if (element->data == NULL) {
return true;
}
return false;
}
static bool IsEqualElementElementPQIndex(TRI_associative_array_t* aa, void* leftItem, void* rightItem) {
PQIndexElement* leftElement;
PQIndexElement* rightElement;
if (leftItem == NULL || rightItem == NULL) {
// should never happen
return false;
}
leftElement = (PQIndexElement*)(leftItem);
rightElement = (PQIndexElement*)(rightItem);
if (leftElement->data == rightElement->data) {
return true;
}
return false;
}
static bool IsEqualKeyElementPQIndex(TRI_associative_array_t* aa, void* key, void* item) {
PQIndexElement* element;
if (item == NULL) {
return false; // should never happen
}
element = (PQIndexElement*)(item);
if (element->data == key) {
return true;
}
return false;
}
// .............................................................................
// implementation of compare functions
// .............................................................................
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;
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;
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)
}
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)
}
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)
}
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)
}
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);
}
result = strcmp(leftString,rightString);
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)
}
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)
}
case TRI_SHAPE_ARRAY:
{
/* start oreste:
char* shape = (char*)(leftShape);
uint64_t fixedEntries;
uint64_t variableEntries;
uint64_t ssid;
uint64_t aaid;
char* name;
TRI_shape_t* newShape;
shape = shape + sizeof(TRI_shape_t);
fixedEntries = *((TRI_shape_size_t*)(shape));
shape = shape + sizeof(TRI_shape_size_t);
variableEntries = *((TRI_shape_size_t*)(shape));
shape = shape + sizeof(TRI_shape_size_t);
ssid = *((TRI_shape_sid_t*)(shape));
shape = shape + (sizeof(TRI_shape_sid_t) * (fixedEntries + variableEntries));
aaid = *((TRI_shape_aid_t*)(shape));
shape = shape + (sizeof(TRI_shape_aid_t) * (fixedEntries + variableEntries));
name = leftShaper->lookupAttributeId(leftShaper,aaid);
newShape = leftShaper->lookupShapeId(leftShaper, ssid);
printf("%s:%u:_fixedEntries:%u\n",__FILE__,__LINE__,fixedEntries);
printf("%s:%u:_variableEntries:%u\n",__FILE__,__LINE__,variableEntries);
printf("%s:%u:_sids[0]:%u\n",__FILE__,__LINE__,ssid);
printf("%s:%u:_aids[0]:%u\n",__FILE__,__LINE__,aaid);
printf("%s:%u:name:%s\n",__FILE__,__LINE__,name);
printf("%s:%u:type:%d\n",__FILE__,__LINE__,newShape->_type);
end oreste */
assert(false);
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(false);
result = 0;
return result;
}
} // end of switch (rightType)
}
}
assert(false);
}
////////////////////////////////////////////////////////////////////////////////
/// @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);
return result;
} // end of function CompareShapedJsonShapedJson
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End: