// yabridge: a Wine plugin bridge
// Copyright (C) 2020-2024 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::StdVariant` to avoid
* reinitializing the object we're deserializing into if the requested variant
* is currently active. For storing audio buffers we use variants containing
* float and double vectors to have a type safe way to disambiguate between
* single and double precision audio, but as it turns out bitsery's
* `std::variant` extension would always reinitialize those objects, undoing our
* efforts to prevent allocations.
*/
template
class InPlaceVariant : public StdVariant {
public:
template
void deserialize(Des& des, std::variant& obj, Fnc&&) const {
size_t index{};
details::readSize(
des.adapter(), index, sizeof...(Ts),
std::integral_constant{});
// Most of this is copied directly from the original implementation.
// We just added the check here to reuse the existing object if
// possible.
this->execIndex(index, obj, [this, &des](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
using TElem =
typename std::variant_alternative>::type;
// Reinitializing nontrivial types may be expensive especially when
// they reference heap data, so if `data` is already holding the
// requested variant then we'll deserialize into the existing object
if constexpr (!std::is_trivial_v) {
if (auto item = std::get_if(&data)) {
this->serializeType(des, *item);
return;
}
}
TElem item = ::bitsery::Access::create();
this->serializeType(des, item);
data = std::variant(std::in_place_index_t{},
std::move(item));
});
}
};
template
InPlaceVariant(Overloads...) -> InPlaceVariant;
} // namespace ext
namespace traits {
template
struct ExtensionTraits, Variant> {
static_assert(
bitsery::details::IsSpecializationOf::value,
"InPlaceVariant only works with std::variant");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
} // namespace traits
} // namespace bitsery