static int FillShapeValueArray (v8::Isolate* isolate, VocShaper* shaper, TRI_shape_value_t* dst, v8::Handle<v8::Object> const json, size_t level, set<int>& seenHashes, vector<v8::Handle<v8::Object>>& seenObjects, bool create) { v8::HandleScope scope(isolate); TRI_shape_value_t* values; TRI_shape_value_t* p; TRI_shape_value_t* e; TRI_array_shape_t* a; TRI_shape_sid_t* sids; TRI_shape_aid_t* aids; TRI_shape_size_t* offsetsF; TRI_shape_size_t* offsetsV; TRI_shape_size_t offset; TRI_shape_t const* found; char* ptr; // number of attributes v8::Handle<v8::Array> names = json->GetOwnPropertyNames(); uint32_t n = names->Length(); // convert into TRI_shape_value_t array p = (values = static_cast<TRI_shape_value_t*>(TRI_Allocate(shaper->memoryZone(), n * sizeof(TRI_shape_value_t), true))); if (p == nullptr) { return TRI_ERROR_OUT_OF_MEMORY; } size_t total = 0; size_t f = 0; size_t v = 0; for (uint32_t i = 0; i < n; ++i, ++p) { v8::Handle<v8::Value> key = names->Get(i); // first find an identifier for the name TRI_Utf8ValueNFC keyStr(TRI_UNKNOWN_MEM_ZONE, key); if (*keyStr == 0 || keyStr.length() == 0) { --p; continue; } if ((*keyStr)[0] == '_' && level == 0) { // on top level, strip reserved attributes before shaping char const* k = (*keyStr); if (strcmp(k, "_key") == 0 || strcmp(k, "_rev") == 0 || strcmp(k, "_id") == 0 || strcmp(k, "_from") == 0 || strcmp(k, "_to") == 0) { // found a reserved attribute - discard it --p; continue; } } if (create) { p->_aid = shaper->findOrCreateAttributeByName(*keyStr); } else { p->_aid = shaper->lookupAttributeByName(*keyStr); } int res; // convert value if (p->_aid == 0) { if (create) { res = TRI_ERROR_INTERNAL; } else { res = TRI_RESULT_ELEMENT_NOT_FOUND; } } else { v8::Handle<v8::Value> val = json->Get(key); res = FillShapeValueJson(isolate, shaper, p, val, level + 1, seenHashes, seenObjects, create); } if (res != TRI_ERROR_NO_ERROR) { for (e = p, p = values; p < e; ++p) { if (p->_value != nullptr) { TRI_Free(shaper->memoryZone(), p->_value); } } TRI_Free(shaper->memoryZone(), values); return res; } total += static_cast<size_t>(p->_size); // count fixed and variable sized values if (p->_fixedSized) { ++f; } else { ++v; } } // adjust n n = (uint32_t) (f + v); // add variable offset table size total += (v + 1) * sizeof(TRI_shape_size_t); // now sort the shape entries if (n > 1) { TRI_SortShapeValues(values, (size_t) n); } #ifdef DEBUG_JSON_SHAPER printf("shape values\n------------\ntotal: %u, fixed: %u, variable: %u\n", (unsigned int) n, (unsigned int) f, (unsigned int) v); TRI_PrintShapeValues(values, n); printf("\n"); #endif // generate shape structure size_t const totalSize = sizeof(TRI_array_shape_t) + n * sizeof(TRI_shape_sid_t) + n * sizeof(TRI_shape_aid_t) + (f + 1) * sizeof(TRI_shape_size_t); a = (TRI_array_shape_t*) (ptr = (char*) TRI_Allocate(shaper->memoryZone(), totalSize, true)); if (ptr == nullptr) { e = values + n; for (p = values; p < e; ++p) { if (p->_value != nullptr) { TRI_Free(shaper->memoryZone(), p->_value); } } TRI_Free(shaper->memoryZone(), values); return TRI_ERROR_OUT_OF_MEMORY; } a->base._type = TRI_SHAPE_ARRAY; a->base._size = (TRI_shape_size_t) totalSize; a->base._dataSize = (v == 0) ? total : TRI_SHAPE_SIZE_VARIABLE; a->_fixedEntries = f; a->_variableEntries = v; ptr += sizeof(TRI_array_shape_t); // array of shape identifiers sids = (TRI_shape_sid_t*) ptr; ptr += n * sizeof(TRI_shape_sid_t); // array of attribute identifiers aids = (TRI_shape_aid_t*) ptr; ptr += n * sizeof(TRI_shape_aid_t); // array of offsets for fixed part (within the shape) offset = (v + 1) * sizeof(TRI_shape_size_t); offsetsF = (TRI_shape_size_t*) ptr; // fill destination (except sid) dst->_type = TRI_SHAPE_ARRAY; dst->_fixedSized = true; dst->_size = total; dst->_value = (ptr = static_cast<char*>(TRI_Allocate(shaper->memoryZone(), dst->_size, true))); if (ptr == nullptr) { e = values + n; for (p = values; p < e; ++p) { if (p->_value != nullptr) { TRI_Free(shaper->memoryZone(), p->_value); } } TRI_Free(shaper->memoryZone(), values); TRI_Free(shaper->memoryZone(), a); return TRI_ERROR_OUT_OF_MEMORY; } // array of offsets for variable part (within the value) offsetsV = (TRI_shape_size_t*) ptr; ptr += (v + 1) * sizeof(TRI_shape_size_t); // and fill in attributes e = values + n; for (p = values; p < e; ++p) { *aids++ = p->_aid; *sids++ = p->_sid; if (p->_value != nullptr) { memcpy(ptr, p->_value, static_cast<size_t>(p->_size)); } ptr += p->_size; dst->_fixedSized &= p->_fixedSized; if (p->_fixedSized) { *offsetsF++ = offset; offset += p->_size; *offsetsF = offset; } else { *offsetsV++ = offset; offset += p->_size; *offsetsV = offset; } } // free TRI_shape_value_t array for (p = values; p < e; ++p) { if (p->_value != nullptr) { TRI_Free(shaper->memoryZone(), p->_value); } } TRI_Free(shaper->memoryZone(), values); // lookup this shape found = shaper->findShape(&a->base, create); if (found == nullptr) { LOG_TRACE("shaper failed to find shape %d", (int) a->base._type); TRI_Free(shaper->memoryZone(), dst->_value); TRI_Free(shaper->memoryZone(), a); if (! create) { return TRI_RESULT_ELEMENT_NOT_FOUND; } return TRI_ERROR_INTERNAL; } // and finally add the sid dst->_sid = found->_sid; return TRI_ERROR_NO_ERROR; }
static bool FillShapeValueArray (TRI_shaper_t* shaper, TRI_shape_value_t* dst, v8::Handle<v8::Object> json, set<int>& seenHashes, vector< v8::Handle<v8::Object> >& seenObjects) { size_t n; size_t i; size_t total; size_t f; size_t v; TRI_shape_value_t* values; TRI_shape_value_t* p; TRI_shape_value_t* e; TRI_array_shape_t* a; TRI_shape_sid_t* sids; TRI_shape_aid_t* aids; TRI_shape_size_t* offsetsF; TRI_shape_size_t* offsetsV; TRI_shape_size_t offset; TRI_shape_t const* found; char* ptr; // number of attributes v8::Handle<v8::Array> names = json->GetOwnPropertyNames(); n = names->Length(); // convert into TRI_shape_value_t array p = (values = (TRI_shape_value_t*) TRI_Allocate(shaper->_memoryZone, n * sizeof(TRI_shape_value_t), true)); if (p == NULL) { return false; } total = 0; f = 0; v = 0; for (i = 0; i < n; ++i, ++p) { v8::Handle<v8::Value> key = names->Get(i); v8::Handle<v8::Value> val = json->Get(key); bool ok; // first find an identifier for the name TRI_Utf8ValueNFC keyStr(TRI_UNKNOWN_MEM_ZONE, key); if (*keyStr == 0) { --p; continue; } if ((*keyStr)[0] == '_') { --p; continue; } p->_aid = shaper->findAttributeName(shaper, *keyStr); // convert value if (p->_aid == 0) { ok = false; } else { ok = FillShapeValueJson(shaper, p, val, seenHashes, seenObjects); } if (! ok) { for (e = p, p = values; p < e; ++p) { if (p->_value != 0) { TRI_Free(shaper->_memoryZone, p->_value); } } TRI_Free(shaper->_memoryZone, values); return false; } total += p->_size; // count fixed and variable sized values if (p->_fixedSized) { ++f; } else { ++v; } } n = f + v; // add variable offset table size total += (v + 1) * sizeof(TRI_shape_size_t); // now sort the shape entries TRI_SortShapeValues(values, n); #ifdef DEBUG_JSON_SHAPER printf("shape values\n------------\ntotal: %u, fixed: %u, variable: %u\n", (unsigned int) n, (unsigned int) f, (unsigned int) v); PrintShapeValues(values, n); printf("\n"); #endif // generate shape structure i = sizeof(TRI_array_shape_t) + n * sizeof(TRI_shape_sid_t) + n * sizeof(TRI_shape_aid_t) + (f + 1) * sizeof(TRI_shape_size_t); a = (TRI_array_shape_t*) (ptr = (char*) TRI_Allocate(shaper->_memoryZone, i, true)); if (ptr == NULL) { e = values + n; for (p = values; p < e; ++p) { if (p->_value != NULL) { TRI_Free(shaper->_memoryZone, p->_value); } } TRI_Free(shaper->_memoryZone, values); return false; } a->base._type = TRI_SHAPE_ARRAY; a->base._size = i; a->base._dataSize = (v == 0) ? total : TRI_SHAPE_SIZE_VARIABLE; a->_fixedEntries = f; a->_variableEntries = v; ptr += sizeof(TRI_array_shape_t); // array of shape identifiers sids = (TRI_shape_sid_t*) ptr; ptr += n * sizeof(TRI_shape_sid_t); // array of attribute identifiers aids = (TRI_shape_aid_t*) ptr; ptr += n * sizeof(TRI_shape_aid_t); // array of offsets for fixed part (within the shape) offset = (v + 1) * sizeof(TRI_shape_size_t); offsetsF = (TRI_shape_size_t*) ptr; // fill destination (except sid) dst->_type = TRI_SHAPE_ARRAY; dst->_fixedSized = true; dst->_size = total; dst->_value = (ptr = (char*) TRI_Allocate(shaper->_memoryZone, dst->_size, true)); if (ptr == NULL) { e = values + n; for (p = values; p < e; ++p) { if (p->_value != NULL) { TRI_Free(shaper->_memoryZone, p->_value); } } TRI_Free(shaper->_memoryZone, values); TRI_Free(shaper->_memoryZone, a); return false; } // array of offsets for variable part (within the value) offsetsV = (TRI_shape_size_t*) ptr; ptr += (v + 1) * sizeof(TRI_shape_size_t); // and fill in attributes e = values + n; for (p = values; p < e; ++p) { *aids++ = p->_aid; *sids++ = p->_sid; memcpy(ptr, p->_value, p->_size); ptr += p->_size; dst->_fixedSized &= p->_fixedSized; if (p->_fixedSized) { *offsetsF++ = offset; offset += p->_size; *offsetsF = offset; } else { *offsetsV++ = offset; offset += p->_size; *offsetsV = offset; } } // free TRI_shape_value_t array for (p = values; p < e; ++p) { if (p->_value != 0) { TRI_Free(shaper->_memoryZone, p->_value); } } TRI_Free(shaper->_memoryZone, values); // lookup this shape found = shaper->findShape(shaper, &a->base); if (found == 0) { TRI_Free(shaper->_memoryZone, a); return false; } // and finally add the sid dst->_sid = found->_sid; return true; }