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:
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;
}