From f5214b7686ef64880d4823ed8e6c64ebacea8241 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Thu, 10 Jun 2021 23:43:45 +0200 Subject: [PATCH] Add an in place std::optional bitsery extension To avoid unnecessarily recreating the object during deserialization. This has also been upstreamed to https://github.com/fraillt/bitsery/pull/78. --- src/common/bitsery/ext/in-place-optional.h | 91 ++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/common/bitsery/ext/in-place-optional.h diff --git a/src/common/bitsery/ext/in-place-optional.h b/src/common/bitsery/ext/in-place-optional.h new file mode 100644 index 00000000..9c7c7ffd --- /dev/null +++ b/src/common/bitsery/ext/in-place-optional.h @@ -0,0 +1,91 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020-2021 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +namespace bitsery { +namespace ext { + +/** + * A temporary replacement for `bitsery::ext::InPlaceOptional` to avoid + * reinitializing the object we're deserializing into if it already holds a + * value. This follows the same idea as our `InPLaceVariant`. + * + * This is copied almost verbatim from `bitsery::ext::InPlaceOptional` (we can't + * access the private member, so we couldn't override just the deserialization + * method). + */ +class InPlaceOptional { + public: + /** + * Works with std::optional types + * @param alignBeforeData only makes sense when bit-packing enabled, by + * default aligns after writing/reading bool state of optional + */ + explicit InPlaceOptional(bool alignBeforeData = true) + : _alignBeforeData{alignBeforeData} {} + + template + void serialize(Ser& ser, const std::optional& obj, Fnc&& fnc) const { + ser.boolValue(static_cast(obj)); + if (_alignBeforeData) + ser.adapter().align(); + if (obj) + fnc(ser, const_cast(*obj)); + } + + template + void deserialize(Des& des, std::optional& obj, Fnc&& fnc) const { + bool exists{}; + des.boolValue(exists); + if (_alignBeforeData) + des.adapter().align(); + if (exists) { + // Reinitializing nontrivial types may be expensive + // especially when they reference heap data, so if `obj` + // already holds a value then we'll deserialize into the + // existing object + if constexpr (!std::is_trivial_v) { + if (obj) { + fnc(des, *obj); + return; + } + } + + obj = ::bitsery::Access::create(); + fnc(des, *obj); + } else { + obj = std::nullopt; + } + } + + private: + bool _alignBeforeData; +}; +} // namespace ext + +namespace traits { +template +struct ExtensionTraits> { + using TValue = T; + static constexpr bool SupportValueOverload = true; + static constexpr bool SupportObjectOverload = true; + static constexpr bool SupportLambdaOverload = true; +}; +} // namespace traits +} // namespace bitsery