From 91ce8b18174dcff3eeba770bd280eb5af0df98ca Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Tue, 23 Nov 2021 04:27:32 -0500 Subject: Issue %3005 - Move memory/mfbt/mozglue to system/ as memory, framework, and utils respectively --- system/framework/MaybeOneOf.h | 142 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 system/framework/MaybeOneOf.h (limited to 'system/framework/MaybeOneOf.h') diff --git a/system/framework/MaybeOneOf.h b/system/framework/MaybeOneOf.h new file mode 100644 index 000000000..ea8124772 --- /dev/null +++ b/system/framework/MaybeOneOf.h @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#ifndef mozilla_MaybeOneOf_h +#define mozilla_MaybeOneOf_h + +#include "mozilla/Alignment.h" +#include "mozilla/Assertions.h" +#include "mozilla/Move.h" +#include "mozilla/TemplateLib.h" + +#include // For placement new + +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. + */ +template +class MaybeOneOf +{ + AlignedStorage::value> storage; + + enum State { None, SomeT1, SomeT2 } state; + template struct Type2State {}; + + template + T& as() + { + MOZ_ASSERT(state == Type2State::result); + return *(T*)storage.addr(); + } + + template + const T& as() const + { + MOZ_ASSERT(state == Type2State::result); + return *(T*)storage.addr(); + } + +public: + MaybeOneOf() : state(None) {} + ~MaybeOneOf() { destroyIfConstructed(); } + + MaybeOneOf(MaybeOneOf&& rhs) + : state(None) + { + if (!rhs.empty()) { + if (rhs.constructed()) { + construct(Move(rhs.as())); + rhs.as().~T1(); + } else { + construct(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(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 (storage.addr()) T(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(); + } + } + +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