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/CompactPair.h | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 mfbt/CompactPair.h (limited to 'mfbt/CompactPair.h') diff --git a/mfbt/CompactPair.h b/mfbt/CompactPair.h new file mode 100644 index 0000000000..fa810dc0af --- /dev/null +++ b/mfbt/CompactPair.h @@ -0,0 +1,244 @@ +/* -*- 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 holding a pair of objects that tries to conserve storage space. */ + +#ifndef mozilla_CompactPair_h +#define mozilla_CompactPair_h + +#include +#include +#include + +#include "mozilla/Attributes.h" + +namespace mozilla { + +namespace detail { + +enum StorageType { AsBase, AsMember }; + +// Optimize storage using the Empty Base Optimization -- that empty base classes +// don't take up space -- to optimize size when one or the other class is +// stateless and can be used as a base class. +// +// The extra conditions on storage for B are necessary so that CompactPairHelper +// won't ambiguously inherit from either A or B, such that one or the other base +// class would be inaccessible. +template ? detail::AsBase : detail::AsMember, + detail::StorageType = std::is_empty_v && + !std::is_base_of::value && + !std::is_base_of::value + ? detail::AsBase + : detail::AsMember> +struct CompactPairHelper; + +template +struct CompactPairHelper { + protected: + template + constexpr CompactPairHelper(std::tuple& aATuple, + std::tuple& aBTuple, + std::index_sequence, + std::index_sequence) + : mFirstA(std::forward(std::get(aATuple))...), + mSecondB(std::forward(std::get(aBTuple))...) {} + + public: + template + constexpr CompactPairHelper(AArg&& aA, BArg&& aB) + : mFirstA(std::forward(aA)), mSecondB(std::forward(aB)) {} + + constexpr A& first() { return mFirstA; } + constexpr const A& first() const { return mFirstA; } + constexpr B& second() { return mSecondB; } + constexpr const B& second() const { return mSecondB; } + + void swap(CompactPairHelper& aOther) { + std::swap(mFirstA, aOther.mFirstA); + std::swap(mSecondB, aOther.mSecondB); + } + + private: + A mFirstA; + B mSecondB; +}; + +template +struct CompactPairHelper : private B { + protected: + template + constexpr CompactPairHelper(std::tuple& aATuple, + std::tuple& aBTuple, + std::index_sequence, + std::index_sequence) + : B(std::forward(std::get(aBTuple))...), + mFirstA(std::forward(std::get(aATuple))...) {} + + public: + template + constexpr CompactPairHelper(AArg&& aA, BArg&& aB) + : B(std::forward(aB)), mFirstA(std::forward(aA)) {} + + constexpr A& first() { return mFirstA; } + constexpr const A& first() const { return mFirstA; } + constexpr B& second() { return *this; } + constexpr const B& second() const { return *this; } + + void swap(CompactPairHelper& aOther) { + std::swap(mFirstA, aOther.mFirstA); + std::swap(static_cast(*this), static_cast(aOther)); + } + + private: + A mFirstA; +}; + +template +struct CompactPairHelper : private A { + protected: + template + constexpr CompactPairHelper(std::tuple& aATuple, + std::tuple& aBTuple, + std::index_sequence, + std::index_sequence) + : A(std::forward(std::get(aATuple))...), + mSecondB(std::forward(std::get(aBTuple))...) {} + + public: + template + constexpr CompactPairHelper(AArg&& aA, BArg&& aB) + : A(std::forward(aA)), mSecondB(std::forward(aB)) {} + + constexpr A& first() { return *this; } + constexpr const A& first() const { return *this; } + constexpr B& second() { return mSecondB; } + constexpr const B& second() const { return mSecondB; } + + void swap(CompactPairHelper& aOther) { + std::swap(static_cast(*this), static_cast(aOther)); + std::swap(mSecondB, aOther.mSecondB); + } + + private: + B mSecondB; +}; + +template +struct CompactPairHelper : private A, private B { + protected: + template + constexpr CompactPairHelper(std::tuple& aATuple, + std::tuple& aBTuple, + std::index_sequence, + std::index_sequence) + : A(std::forward(std::get(aATuple))...), + B(std::forward(std::get(aBTuple))...) {} + + public: + template + constexpr CompactPairHelper(AArg&& aA, BArg&& aB) + : A(std::forward(aA)), B(std::forward(aB)) {} + + constexpr A& first() { return static_cast(*this); } + constexpr const A& first() const { return static_cast(*this); } + constexpr B& second() { return static_cast(*this); } + constexpr const B& second() const { return static_cast(*this); } + + void swap(CompactPairHelper& aOther) { + std::swap(static_cast(*this), static_cast(aOther)); + std::swap(static_cast(*this), static_cast(aOther)); + } +}; + +} // namespace detail + +/** + * CompactPair is the logical concatenation of an instance of A with an instance + * B. Space is conserved when possible. Neither A nor B may be a final class. + * + * In general if space conservation is not critical is preferred to use + * std::pair. + * + * It's typically clearer to have individual A and B member fields. Except if + * you want the space-conserving qualities of CompactPair, you're probably + * better off not using this! + * + * No guarantees are provided about the memory layout of A and B, the order of + * initialization or destruction of A and B, and so on. (This is approximately + * required to optimize space usage.) The first/second names are merely + * conceptual! + */ +template +struct CompactPair : private detail::CompactPairHelper { + typedef typename detail::CompactPairHelper Base; + + using Base::Base; + + template + constexpr CompactPair(std::piecewise_construct_t, std::tuple aFirst, + std::tuple aSecond) + : Base(aFirst, aSecond, std::index_sequence_for(), + std::index_sequence_for()) {} + + CompactPair(CompactPair&& aOther) = default; + CompactPair(const CompactPair& aOther) = default; + + CompactPair& operator=(CompactPair&& aOther) = default; + CompactPair& operator=(const CompactPair& aOther) = default; + + /** The A instance. */ + using Base::first; + /** The B instance. */ + using Base::second; + + /** Swap this pair with another pair. */ + void swap(CompactPair& aOther) { Base::swap(aOther); } +}; + +/** + * MakeCompactPair allows you to construct a CompactPair instance using type + * inference. A call like this: + * + * MakeCompactPair(Foo(), Bar()) + * + * will return a CompactPair. + */ +template +CompactPair>, + std::remove_cv_t>> +MakeCompactPair(A&& aA, B&& aB) { + return CompactPair>, + std::remove_cv_t>>( + std::forward(aA), std::forward(aB)); +} + +/** + * CompactPair equality comparison + */ +template +bool operator==(const CompactPair& aLhs, const CompactPair& aRhs) { + return aLhs.first() == aRhs.first() && aLhs.second() == aRhs.second(); +} + +} // namespace mozilla + +namespace std { + +template +void swap(mozilla::CompactPair& aX, mozilla::CompactPair& aY) { + aX.swap(aY); +} + +} // namespace std + +#endif /* mozilla_CompactPair_h */ -- cgit v1.2.3