//////////////////////////////////////////////////////////////////////////////// /// @brief json shaper used to compute the shape of an json object /// /// @file /// /// DISCLAIMER /// /// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler /// @author Martin Schoenert /// @author Copyright 2006-2013, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "json-shaper.h" #include "BasicsC/associative.h" #include "BasicsC/hashes.h" #include "BasicsC/logging.h" #include "BasicsC/string-buffer.h" #include "BasicsC/tri-strings.h" #include "BasicsC/vector.h" // #define DEBUG_JSON_SHAPER 1 // ----------------------------------------------------------------------------- // --SECTION-- GLOBALS // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief basic shape types (shared between all shapers) //////////////////////////////////////////////////////////////////////////////// static TRI_basic_shapes_t BasicShapes; // ----------------------------------------------------------------------------- // --SECTION-- ARRAY SHAPER // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // --SECTION-- private types // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief attribute identifier mapping //////////////////////////////////////////////////////////////////////////////// typedef struct attribute_2_id_s { TRI_shape_aid_t _aid; // attribute identifier TRI_shape_size_t _size; // size of the attribute name in name[] including '\0' // char name[] } attribute_2_id_t; //////////////////////////////////////////////////////////////////////////////// /// @brief simple, array-based shaper //////////////////////////////////////////////////////////////////////////////// typedef struct array_shaper_s { TRI_shaper_t base; TRI_associative_pointer_t _attributeNames; TRI_vector_pointer_t _attributes; TRI_associative_pointer_t _shapeDictionary; TRI_vector_pointer_t _shapes; // todo: add attribute weight structure } array_shaper_t; // ----------------------------------------------------------------------------- // --SECTION-- private functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief hashs the attribute path identifier //////////////////////////////////////////////////////////////////////////////// static uint64_t HashPidKeyAttributePath (TRI_associative_synced_t* array, void const* key) { return TRI_FnvHashPointer(key, sizeof(TRI_shape_pid_t)); } //////////////////////////////////////////////////////////////////////////////// /// @brief hashs the attribute path //////////////////////////////////////////////////////////////////////////////// static uint64_t HashPidElementAttributePath (TRI_associative_synced_t* array, void const* element) { TRI_shape_path_t const* e; e = (TRI_shape_path_t const*) element; return TRI_FnvHashPointer(&e->_pid, sizeof(TRI_shape_pid_t)); } //////////////////////////////////////////////////////////////////////////////// /// @brief compares an attribute path identifier and an attribute path //////////////////////////////////////////////////////////////////////////////// static bool EqualPidKeyAttributePath (TRI_associative_synced_t* array, void const* key, void const* element) { TRI_shape_pid_t const* k; TRI_shape_path_t const* e; k = (TRI_shape_pid_t const*) key; e = (TRI_shape_path_t const*) element; return *k == e->_pid; } //////////////////////////////////////////////////////////////////////////////// /// @brief looks up an attribute path by identifier //////////////////////////////////////////////////////////////////////////////// static TRI_shape_path_t const* LookupPidAttributePath (TRI_shaper_t* shaper, TRI_shape_pid_t pid) { return TRI_LookupByKeyAssociativeSynced(&shaper->_attributePathsByPid, &pid); } //////////////////////////////////////////////////////////////////////////////// /// @brief hashs the attribute path name //////////////////////////////////////////////////////////////////////////////// static uint64_t HashNameKeyAttributePath (TRI_associative_synced_t* array, void const* key) { char const* k; k = (char const*) key; return TRI_FnvHashString(k); } //////////////////////////////////////////////////////////////////////////////// /// @brief hashs the attribute path //////////////////////////////////////////////////////////////////////////////// static uint64_t HashNameElementAttributePath (TRI_associative_synced_t* array, void const* element) { char const* e; TRI_shape_path_t const* ee; e = (char const*) element; ee = (TRI_shape_path_t const*) element; return TRI_FnvHashPointer(e + sizeof(TRI_shape_path_t) + ee->_aidLength * sizeof(TRI_shape_aid_t), ee->_nameLength - 1); } //////////////////////////////////////////////////////////////////////////////// /// @brief compares an attribute name and an attribute //////////////////////////////////////////////////////////////////////////////// static bool EqualNameKeyAttributePath (TRI_associative_synced_t* array, void const* key, void const* element) { char const* k; char const* e; TRI_shape_path_t const* ee; k = (char const*) key; e = (char const*) element; ee = (TRI_shape_path_t const*) element; return TRI_EqualString(k,e + sizeof(TRI_shape_path_t) + ee->_aidLength * sizeof(TRI_shape_aid_t)); } //////////////////////////////////////////////////////////////////////////////// /// @brief looks up a shape path by identifier //////////////////////////////////////////////////////////////////////////////// static TRI_shape_path_t const* FindShapePathByName (TRI_shaper_t* shaper, char const* name, bool create, bool isLocked) { TRI_shape_aid_t* aids; TRI_shape_path_t* result; size_t count; size_t len; size_t total; char* buffer; char* end; char* prev; char* ptr; void const* f; void const* p; assert(name != NULL); p = TRI_LookupByKeyAssociativeSynced(&shaper->_attributePathsByName, name); if (p != NULL) { return (TRI_shape_path_t const*) p; } // create a attribute path len = strlen(name); // lock the index and check that the element is still missing TRI_LockMutex(&shaper->_attributePathLock); // if the element appeared, return the pid p = TRI_LookupByKeyAssociativeSynced(&shaper->_attributePathsByName, name); if (p != NULL) { TRI_UnlockMutex(&shaper->_attributePathLock); return (TRI_shape_path_t const*) p; } // split path into attribute pieces count = 0; aids = TRI_Allocate(shaper->_memoryZone, len * sizeof(TRI_shape_aid_t), false); if (aids == NULL) { TRI_UnlockMutex(&shaper->_attributePathLock); LOG_ERROR("out of memory in shaper"); return NULL; } buffer = ptr = TRI_DuplicateString2Z(shaper->_memoryZone, name, len); if (buffer == NULL) { TRI_UnlockMutex(&shaper->_attributePathLock); TRI_Free(shaper->_memoryZone, aids); LOG_ERROR("out of memory in shaper"); return NULL; } end = buffer + len + 1; prev = buffer; for (; ptr < end; ++ptr) { if (*ptr == '.' || *ptr == '\0') { *ptr = '\0'; if (ptr != prev) { if (create) { aids[count++] = shaper->findOrCreateAttributeByName(shaper, prev, isLocked); } else { aids[count] = shaper->lookupAttributeByName(shaper, prev); if (aids[count] == 0) { TRI_FreeString(shaper->_memoryZone, buffer); TRI_UnlockMutex(&shaper->_attributePathLock); TRI_Free(shaper->_memoryZone, aids); return NULL; } ++count; } } prev = ptr + 1; } } TRI_FreeString(shaper->_memoryZone, buffer); // create element total = sizeof(TRI_shape_path_t) + (len + 1) + (count * sizeof(TRI_shape_aid_t)); result = TRI_Allocate(shaper->_memoryZone, total, false); if (result == NULL) { TRI_UnlockMutex(&shaper->_attributePathLock); TRI_Free(shaper->_memoryZone, aids); LOG_ERROR("out of memory in shaper"); return NULL; } result->_pid = shaper->_nextPid++; result->_nameLength = (uint32_t) len + 1; result->_aidLength = count; memcpy(((char*) result) + sizeof(TRI_shape_path_t), aids, count * sizeof(TRI_shape_aid_t)); memcpy(((char*) result) + sizeof(TRI_shape_path_t) + count * sizeof(TRI_shape_aid_t), name, len + 1); TRI_Free(shaper->_memoryZone, aids); f = TRI_InsertKeyAssociativeSynced(&shaper->_attributePathsByName, name, result); assert(f == NULL); f = TRI_InsertKeyAssociativeSynced(&shaper->_attributePathsByPid, &result->_pid, result); assert(f == NULL); // return pid TRI_UnlockMutex(&shaper->_attributePathLock); return result; } //////////////////////////////////////////////////////////////////////////////// /// @brief finds an attribute path by identifier //////////////////////////////////////////////////////////////////////////////// static TRI_shape_pid_t FindOrCreateAttributePathByName (TRI_shaper_t* shaper, char const* name, bool isLocked) { TRI_shape_path_t const* path = FindShapePathByName(shaper, name, true, isLocked); return path == NULL ? 0 : path->_pid; } //////////////////////////////////////////////////////////////////////////////// /// @brief looks up an attribute path by identifier //////////////////////////////////////////////////////////////////////////////// static TRI_shape_pid_t LookupAttributePathByName (TRI_shaper_t* shaper, char const* name) { TRI_shape_path_t const* path = FindShapePathByName(shaper, name, false, true); return path == NULL ? 0 : path->_pid; } // ----------------------------------------------------------------------------- // --SECTION-- SHAPER // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // --SECTION-- public functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief creates the attribute path //////////////////////////////////////////////////////////////////////////////// char const* TRI_AttributeNameShapePid (TRI_shaper_t* shaper, TRI_shape_pid_t pid) { TRI_shape_path_t const* path; char const* e; path = shaper->lookupAttributePathByPid(shaper, pid); e = (char const*) path; return e + sizeof(TRI_shape_path_t) + path->_aidLength * sizeof(TRI_shape_aid_t); } // ----------------------------------------------------------------------------- // --SECTION-- protected functions // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// /// @brief initialises the shaper //////////////////////////////////////////////////////////////////////////////// int TRI_InitShaper (TRI_shaper_t* shaper, TRI_memory_zone_t* zone) { int res; shaper->_memoryZone = zone; res = TRI_InitAssociativeSynced(&shaper->_attributePathsByName, zone, HashNameKeyAttributePath, HashNameElementAttributePath, EqualNameKeyAttributePath, 0); if (res != TRI_ERROR_NO_ERROR) { return res; } res = TRI_InitAssociativeSynced(&shaper->_attributePathsByPid, zone, HashPidKeyAttributePath, HashPidElementAttributePath, EqualPidKeyAttributePath, 0); if (res != TRI_ERROR_NO_ERROR) { TRI_DestroyAssociativeSynced(&shaper->_attributePathsByName); return res; } TRI_InitMutex(&shaper->_attributePathLock); shaper->_nextPid = 1; shaper->lookupAttributePathByPid = LookupPidAttributePath; shaper->findOrCreateAttributePathByName = FindOrCreateAttributePathByName; shaper->lookupAttributePathByName = LookupAttributePathByName; return TRI_ERROR_NO_ERROR; } //////////////////////////////////////////////////////////////////////////////// /// @brief destroys the shaper //////////////////////////////////////////////////////////////////////////////// void TRI_DestroyShaper (TRI_shaper_t* shaper) { size_t n = shaper->_attributePathsByName._nrAlloc; size_t i; // only free pointers in attributePathsByName // (attributePathsByPid contains the same pointers!) for (i = 0; i < n; ++i) { void* data = shaper->_attributePathsByName._table[i]; if (data) { TRI_Free(shaper->_memoryZone, data); } } TRI_DestroyAssociativeSynced(&shaper->_attributePathsByName); TRI_DestroyAssociativeSynced(&shaper->_attributePathsByPid); TRI_DestroyMutex(&shaper->_attributePathLock); } //////////////////////////////////////////////////////////////////////////////// /// @brief frees the shaper //////////////////////////////////////////////////////////////////////////////// void TRI_FreeShaper (TRI_shaper_t* shaper) { TRI_DestroyShaper(shaper); TRI_Free(shaper->_memoryZone, shaper); } //////////////////////////////////////////////////////////////////////////////// /// @brief return the sid for a basic type //////////////////////////////////////////////////////////////////////////////// TRI_shape_sid_t TRI_LookupBasicSidShaper (TRI_shape_type_e type) { switch (type) { case TRI_SHAPE_NULL: return BasicShapes._sidNull; case TRI_SHAPE_BOOLEAN: return BasicShapes._sidBoolean; case TRI_SHAPE_NUMBER: return BasicShapes._sidNumber; case TRI_SHAPE_SHORT_STRING: return BasicShapes._sidShortString; case TRI_SHAPE_LONG_STRING: return BasicShapes._sidLongString; case TRI_SHAPE_LIST: return BasicShapes._sidList; default: { } } LOG_ERROR("encountered an illegal shape type"); assert(false); return TRI_SHAPE_ILLEGAL; } //////////////////////////////////////////////////////////////////////////////// /// @brief checks whether a shape is of primitive type //////////////////////////////////////////////////////////////////////////////// TRI_shape_t* TRI_LookupSidBasicShapeShaper (TRI_shape_sid_t sid) { if (sid == BasicShapes._sidNull) { return &BasicShapes._shapeNull; } else if (sid == BasicShapes._sidBoolean) { return &BasicShapes._shapeBoolean; } else if (sid == BasicShapes._sidNumber) { return &BasicShapes._shapeNumber; } else if (sid == BasicShapes._sidShortString) { return &BasicShapes._shapeShortString; } else if (sid == BasicShapes._sidLongString) { return &BasicShapes._shapeLongString; } else if (sid == BasicShapes._sidList) { return &BasicShapes._shapeList; } return NULL; } //////////////////////////////////////////////////////////////////////////////// /// @brief checks whether a shape is of primitive type //////////////////////////////////////////////////////////////////////////////// TRI_shape_t* TRI_LookupBasicShapeShaper (TRI_shape_t const* shape) { if (shape->_type == TRI_SHAPE_NULL) { return &BasicShapes._shapeNull; } else if (shape->_type == TRI_SHAPE_BOOLEAN) { return &BasicShapes._shapeBoolean; } else if (shape->_type == TRI_SHAPE_NUMBER) { return &BasicShapes._shapeNumber; } else if (shape->_type == TRI_SHAPE_SHORT_STRING) { return &BasicShapes._shapeShortString; } else if (shape->_type == TRI_SHAPE_LONG_STRING) { return &BasicShapes._shapeLongString; } else if (shape->_type == TRI_SHAPE_LIST) { return &BasicShapes._shapeList; } return NULL; } //////////////////////////////////////////////////////////////////////////////// /// @brief initialises global basic shape types //////////////////////////////////////////////////////////////////////////////// void TRI_InitialiseShaper () { TRI_shape_t* shape; memset(&BasicShapes, 0, sizeof(TRI_basic_shapes_t)); // NULL shape = &BasicShapes._shapeNull; shape->_size = sizeof(TRI_null_shape_t); shape->_type = TRI_SHAPE_NULL; shape->_dataSize = 0; shape->_sid = BasicShapes._sidNull = 1; // BOOLEAN shape = &BasicShapes._shapeBoolean; shape->_size = sizeof(TRI_boolean_shape_t); shape->_type = TRI_SHAPE_BOOLEAN; shape->_dataSize = sizeof(TRI_shape_boolean_t); shape->_sid = BasicShapes._sidBoolean = 2; // NUMBER shape = &BasicShapes._shapeNumber; shape->_size = sizeof(TRI_number_shape_t); shape->_type = TRI_SHAPE_NUMBER; shape->_dataSize = sizeof(TRI_shape_number_t); shape->_sid = BasicShapes._sidNumber = 3; // SHORT STRING shape = &BasicShapes._shapeShortString; shape->_size = sizeof(TRI_short_string_shape_t); shape->_type = TRI_SHAPE_SHORT_STRING; shape->_dataSize = sizeof(TRI_shape_length_short_string_t) + TRI_SHAPE_SHORT_STRING_CUT; shape->_sid = BasicShapes._sidShortString = 4; // LONG STRING shape = &BasicShapes._shapeLongString; shape->_size = sizeof(TRI_long_string_shape_t); shape->_type = TRI_SHAPE_LONG_STRING; shape->_dataSize = TRI_SHAPE_SIZE_VARIABLE; shape->_sid = BasicShapes._sidLongString = 5; // LIST shape = &BasicShapes._shapeList; shape->_size = sizeof(TRI_list_shape_t); shape->_type = TRI_SHAPE_LIST; shape->_dataSize = TRI_SHAPE_SIZE_VARIABLE; shape->_sid = BasicShapes._sidList = 6; } //////////////////////////////////////////////////////////////////////////////// /// @brief shutdown shaper //////////////////////////////////////////////////////////////////////////////// void TRI_ShutdownShaper () { // nothing to do } // Local Variables: // mode: outline-minor // outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}" // End: