common/util/cpp/cdynamic.cpp (133 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. #include "cpp/cdynamic.h" #include <folly/dynamic.h> #include <folly/json.h> #include <string.h> #include "cpp/Destructible.h" using namespace folly; namespace facebook { namespace hs { /** * Read the type and value of a dynamic. If the dynamic is array or object, * its size is returned as the value. */ void readDynamic(const dynamic* d, DType* ty, DValue* val) noexcept { switch (d->type()) { case dynamic::STRING: *ty = tString; val->string = d->c_str(); break; case dynamic::BOOL: *ty = tBool; val->boolean = d->asBool(); break; case dynamic::DOUBLE: *ty = tDouble; val->doubl = d->asDouble(); break; case dynamic::INT64: *ty = tInt64; val->int64 = d->asInt(); break; case dynamic::ARRAY: *ty = tArray; val->size = d->size(); break; case dynamic::OBJECT: *ty = tObject; val->size = d->size(); break; case dynamic::NULLT: *ty = tNull; val->null = nullptr; break; } } /** * Read the fields of a dynamic array. Memory for the array is * allocated by the caller. The size of the array to allocate is * returned by readDynamic(). */ int readDynamicArray( const dynamic* d, size_t /*size*/, const dynamic** elems) noexcept { if ((*d).type() != dynamic::ARRAY) return 0; int i = 0; for (const auto& e : *d) { elems[i++] = &e; } return i; } /** * Read the fields of a dynamic object. Memory for the arrays are * allocated by the caller. The size of the arrays to allocate is * returned by readDynamic(). */ int readDynamicObject( const dynamic* d, size_t /*size*/, const dynamic** keys, const dynamic** vals) noexcept { if ((*d).type() != dynamic::OBJECT) return 0; // Relying on the iterator referring to elements by reference here. auto it = (*d).items(); int i = 0; for (auto j = it.begin(); j != it.end(); ++j, ++i) { keys[i] = &(j->first); vals[i] = &(j->second); } return i; } /** * Create a dynamic with nullptr, boolean, double or const char*. * It's caller's responsibility to allocate and free the memory. */ void createDynamic(dynamic* ret, DType ty, DValue* val) noexcept { switch (static_cast<dynamic::Type>(ty)) { case dynamic::NULLT: new (ret) dynamic(nullptr); break; case dynamic::BOOL: new (ret) dynamic(val->boolean != 0); break; case dynamic::INT64: new (ret) dynamic(val->int64); break; case dynamic::DOUBLE: new (ret) dynamic(val->doubl); break; case dynamic::STRING: new (ret) dynamic(val->string); break; case dynamic::ARRAY: folly::terminate_with<std::invalid_argument>( "call writeDynamicArray for dynamic::ARRAY"); case dynamic::OBJECT: folly::terminate_with<std::invalid_argument>( "call writeDynamicObject for dynamic::OBJECT"); default: __builtin_unreachable(); } } /** * Create a dynamic array with given \p elems. * It's caller's responsibility to allocate and free the memory for \p ret. The * elements of \p elems are invalidated. */ void createDynamicArray(dynamic* ret, size_t size, dynamic* elems) noexcept { new (ret) dynamic(dynamic::array); ret->resize(size); for (size_t i = 0; i < size; ++i) { ret->at(i) = std::move(elems[i]); elems[i].~dynamic(); } } /** * Create a dynamic array with given \p keys and \p vals. * It's caller's responsibility to allocate and free the memory for \p ret. The * elements of \p vals are invalidated. */ void createDynamicObject( dynamic* ret, size_t size, const char** keys, dynamic* vals) noexcept { new (ret) dynamic(dynamic::object); for (size_t i = 0; i < size; ++i) { ret->insert(keys[i], std::move(vals[i])); vals[i].~dynamic(); } } /** * parse JSON using folly::parseJson() * Returns either * - a pointer to the folly::dynamic representing the parsed JSON. The caller * owns this and is responsible for freeing it. * - nullptr, and *err points to an error message. The caller owns the * memory for the error message, and is responsible for freeing it. */ const folly::dynamic* parseJSON( const char* str, int64_t len, int recursion_limit, char** err) noexcept { json::serialization_opts opts; if (recursion_limit != -1) { opts.recursion_limit = recursion_limit; } try { auto d = parseJson(folly::StringPiece(str, len), opts); return new folly::dynamic(std::move(d)); } catch (const std::exception& e) { *err = strdup(e.what()); return nullptr; } } } // namespace hs } // namespace facebook HS_DEFINE_DESTRUCTIBLE(Dynamic, Dynamic)