/* * serialize.h * * This source file is part of the FoundationDB open source project * * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors * * 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. */ #pragma once #include "flow/Error.h" #include "flow/Arena.h" #include "flow/flat_buffers.h" template struct LoadContext { Ar& ar; std::vector> doAfter; LoadContext(Ar& ar) : ar(ar) {} Arena& arena() { return ar.arena(); } const uint8_t* tryReadZeroCopy(const uint8_t* ptr, unsigned len) { if constexpr (Ar::ownsUnderlyingMemory) { return ptr; } else { if (len == 0) return nullptr; uint8_t* dat = new (arena()) uint8_t[len]; std::copy(ptr, ptr + len, dat); return dat; } } void done() const { for (auto& f : doAfter) { f(); } } void addArena(Arena& arena) { arena = ar.arena(); } }; template class _ObjectReader { public: template void deserialize(FileIdentifier file_identifier, Items&... items) { const uint8_t* data = static_cast(this)->data(); LoadContext context(*static_cast(this)); ASSERT(read_file_identifier(data) == file_identifier); load_members(data, context, items...); context.done(); } template void deserialize(Item& item) { deserialize(FileIdentifierFor::value, item); } }; class ObjectReader : public _ObjectReader { public: static constexpr bool ownsUnderlyingMemory = false; ObjectReader(const uint8_t* data) : _data(data) {} const uint8_t* data() { return _data; } Arena& arena() { return _arena; } private: const uint8_t* _data; Arena _arena; }; class ArenaObjectReader : public _ObjectReader { public: static constexpr bool ownsUnderlyingMemory = true; ArenaObjectReader(Arena const& arena, const StringRef& input) : _data(input.begin()), _arena(arena) {} const uint8_t* data() { return _data; } Arena& arena() { return _arena; } private: const uint8_t* _data; Arena _arena; }; class ObjectWriter { public: template void serialize(FileIdentifier file_identifier, Items const&... items) { ASSERT(data == nullptr); // object serializer can only serialize one object int allocations = 0; auto allocator = [this, &allocations](size_t size_) { ++allocations; size = size_; data = new (arena) uint8_t[size]; return data; }; save_members(allocator, file_identifier, items...); ASSERT(allocations == 1); } template void serialize(Item const& item) { serialize(FileIdentifierFor::value, item); } StringRef toStringRef() const { return StringRef(data, size); } Standalone toString() const { return Standalone(toStringRef(), arena); } template static Standalone toValue(Item const& item) { ObjectWriter writer; writer.serialize(item); return writer.toString(); } private: Arena arena; uint8_t* data = nullptr; int size = 0; }; // this special case is needed - the code expects // Standalone and T to be equivalent for serialization namespace detail { template struct LoadSaveHelper> { template void load(Standalone& member, const uint8_t* current, Context& context) { helper.load(member.contents(), current, context); context.addArena(member.arena()); } template RelativeOffset save(const Standalone& member, Writer& writer, const VTableSet* vtables) { return helper.save(member.contents(), writer, vtables); } private: LoadSaveHelper helper; }; } // namespace detail