From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- mfbt/MaybeOneOf.h | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 mfbt/MaybeOneOf.h (limited to 'mfbt/MaybeOneOf.h') diff --git a/mfbt/MaybeOneOf.h b/mfbt/MaybeOneOf.h new file mode 100644 index 0000000000..769f18d5dd --- /dev/null +++ b/mfbt/MaybeOneOf.h @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * A class storing one of two optional value types that supports in-place lazy + * construction. + */ + +#ifndef mozilla_MaybeOneOf_h +#define mozilla_MaybeOneOf_h + +#include // for size_t + +#include // for placement new +#include + +#include "mozilla/Assertions.h" +#include "mozilla/OperatorNewExtensions.h" +#include "mozilla/TemplateLib.h" + +namespace mozilla { + +/* + * MaybeOneOf is like Maybe, but it supports constructing either T1 + * or T2. When a MaybeOneOf is constructed, it is |empty()|, i.e., + * no value has been constructed and no destructor will be called when the + * MaybeOneOf is destroyed. Upon calling |construct()| or + * |construct()|, a T1 or T2 object will be constructed with the given + * arguments and that object will be destroyed when the owning MaybeOneOf is + * destroyed. + * + * Because MaybeOneOf must be aligned suitable to hold any value stored within + * it, and because |alignas| requirements don't affect platform ABI with respect + * to how parameters are laid out in memory, MaybeOneOf can't be used as the + * type of a function parameter. Pass MaybeOneOf to functions by pointer or + * reference instead. + */ +template +class MOZ_NON_PARAM MaybeOneOf { + static constexpr size_t StorageAlignment = + tl::Max::value; + static constexpr size_t StorageSize = tl::Max::value; + + alignas(StorageAlignment) unsigned char storage[StorageSize]; + + // GCC fails due to -Werror=strict-aliasing if |storage| is directly cast to + // T*. Indirecting through these functions addresses the problem. + void* data() { return storage; } + const void* data() const { return storage; } + + enum State { None, SomeT1, SomeT2 } state; + template + struct Type2State {}; + + template + T& as() { + MOZ_ASSERT(state == Type2State::result); + return *static_cast(data()); + } + + template + const T& as() const { + MOZ_ASSERT(state == Type2State::result); + return *static_cast(data()); + } + + public: + MaybeOneOf() : state(None) {} + ~MaybeOneOf() { destroyIfConstructed(); } + + MaybeOneOf(MaybeOneOf&& rhs) : state(None) { + if (!rhs.empty()) { + if (rhs.constructed()) { + construct(std::move(rhs.as())); + rhs.as().~T1(); + } else { + construct(std::move(rhs.as())); + rhs.as().~T2(); + } + rhs.state = None; + } + } + + MaybeOneOf& operator=(MaybeOneOf&& rhs) { + MOZ_ASSERT(this != &rhs, "Self-move is prohibited"); + this->~MaybeOneOf(); + new (this) MaybeOneOf(std::move(rhs)); + return *this; + } + + bool empty() const { return state == None; } + + template + bool constructed() const { + return state == Type2State::result; + } + + template + void construct(Args&&... aArgs) { + MOZ_ASSERT(state == None); + state = Type2State::result; + ::new (KnownNotNull, data()) T(std::forward(aArgs)...); + } + + template + T& ref() { + return as(); + } + + template + const T& ref() const { + return as(); + } + + void destroy() { + MOZ_ASSERT(state == SomeT1 || state == SomeT2); + if (state == SomeT1) { + as().~T1(); + } else if (state == SomeT2) { + as().~T2(); + } + state = None; + } + + void destroyIfConstructed() { + if (!empty()) { + destroy(); + } + } + + template + constexpr auto mapNonEmpty(Func&& aFunc) const { + MOZ_ASSERT(!empty()); + if (state == SomeT1) { + return std::forward(aFunc)(as()); + } + return std::forward(aFunc)(as()); + } + template + constexpr auto mapNonEmpty(Func&& aFunc) { + MOZ_ASSERT(!empty()); + if (state == SomeT1) { + return std::forward(aFunc)(as()); + } + return std::forward(aFunc)(as()); + } + + private: + MaybeOneOf(const MaybeOneOf& aOther) = delete; + const MaybeOneOf& operator=(const MaybeOneOf& aOther) = delete; +}; + +template +template +struct MaybeOneOf::Type2State { + typedef MaybeOneOf Enclosing; + static const typename Enclosing::State result = Enclosing::SomeT1; +}; + +template +template +struct MaybeOneOf::Type2State { + typedef MaybeOneOf Enclosing; + static const typename Enclosing::State result = Enclosing::SomeT2; +}; + +} // namespace mozilla + +#endif /* mozilla_MaybeOneOf_h */ -- cgit v1.2.3