tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit c7b4d83f88ffd2a3d4831ca49005663a101cdb8f
parent f4961424117a9e42892a3b14d33ed00773c2bde6
Author: Andreas Farre <farre@mozilla.com>
Date:   Wed, 17 Dec 2025 05:35:51 +0000

Bug 2005480 - Implement begin() and end() for Maybe<T>. r=glandium

Differential Revision: https://phabricator.services.mozilla.com/D275956

Diffstat:
Mmfbt/Maybe.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mmfbt/tests/TestMaybe.cpp | 47+++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 96 insertions(+), 0 deletions(-)

diff --git a/mfbt/Maybe.h b/mfbt/Maybe.h @@ -794,6 +794,55 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_GSL_OWNER Maybe return std::invoke(std::forward<Func>(aFunc)); } + /* begin() and end() implementation */ + private: + template <typename U> + struct Iterator { + using iterator_type = Iterator<U>; + using value_type = U; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using pointer = value_type*; + using iterator_category = std::forward_iterator_tag; + + constexpr Iterator() = default; + constexpr explicit Iterator(pointer aValue) : mValue(aValue) {} + + constexpr reference operator*() const { return *mValue; }; + + constexpr pointer operator->() const { return mValue; } + + constexpr iterator_type& operator++() { + mValue = nullptr; + return *this; + } + + constexpr iterator_type operator++(int) { + iterator_type it{mValue}; + mValue = nullptr; + return it; + } + + constexpr auto operator<=>(const Iterator&) const = default; + + private: + pointer mValue; + }; + + public: + using iterator = Iterator<T>; + using const_iterator = Iterator<const T>; + + constexpr iterator begin() { return iterator{ptrOr(nullptr)}; } + constexpr const_iterator begin() const { + return const_iterator{ptrOr(nullptr)}; + } + constexpr const_iterator cbegin() const { return begin(); } + + constexpr iterator end() { return iterator{nullptr}; } + constexpr const_iterator end() const { return const_iterator{nullptr}; } + constexpr const_iterator cend() const { return end(); } + /* If |isSome()|, empties this Maybe and destroys its contents. */ constexpr void reset() { if (isSome()) { diff --git a/mfbt/tests/TestMaybe.cpp b/mfbt/tests/TestMaybe.cpp @@ -1690,6 +1690,52 @@ static bool TestComposedMoves() { return true; } +static bool TestBeginEnd() { + for ([[maybe_unused]] auto v : static_cast<Maybe<int>>(Nothing())) { + MOZ_CRASH("Nothing should not be iterated"); + } + + for (auto v : Some(42)) { + MOZ_RELEASE_ASSERT(v == 42, "Some(42) should be iterated"); + } + + Maybe<int> maybe; + for ([[maybe_unused]] auto v : maybe) { + MOZ_CRASH("Nothing should not be iterated"); + } + + maybe = Some(42); + + for (auto v : maybe) { + MOZ_RELEASE_ASSERT(v == 42, "Some(42) should be iterated"); + } + + maybe = Nothing(); + + for ([[maybe_unused]] auto v : maybe) { + MOZ_CRASH("Nothing should not be iterated"); + } + + int v = 42; + Maybe<int*> maybePtr; + for ([[maybe_unused]] auto* v : maybePtr) { + MOZ_CRASH("Nothing should not be iterated"); + } + + maybePtr = Some(&v); + + for (auto* v : maybePtr) { + MOZ_RELEASE_ASSERT(*v == 42, "Some(address) should be iterated"); + } + + maybePtr = Nothing(); + for ([[maybe_unused]] auto* v : maybePtr) { + MOZ_CRASH("Nothing should not be iterated"); + } + + return true; +} + // These are quasi-implementation details, but we assert them here to prevent // backsliding to earlier times when Maybe<T> for smaller T took up more space // than T's alignment required. @@ -1722,6 +1768,7 @@ int main() { RUN_TEST(TestAndThen); RUN_TEST(TestOrElse); RUN_TEST(TestComposedMoves); + RUN_TEST(TestBeginEnd); return 0; }