no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / mfbt / tests / TestMaybe.cpp
blobf9e5ae00dcb24acbac15b0b1662fc405d185611a
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <type_traits>
7 #include <utility>
9 #include "mozilla/Assertions.h"
10 #include "mozilla/Attributes.h"
11 #include "mozilla/Maybe.h"
13 using mozilla::Maybe;
14 using mozilla::Nothing;
15 using mozilla::Some;
16 using mozilla::SomeRef;
17 using mozilla::ToMaybe;
18 using mozilla::ToMaybeRef;
20 #define RUN_TEST(t) \
21 do { \
22 bool cond = (t()); \
23 if (!cond) return 1; \
24 cond = AllDestructorsWereCalled(); \
25 MOZ_ASSERT(cond, "Failed to destroy all objects during test: " #t); \
26 if (!cond) return 1; \
27 } while (false)
29 enum Status {
30 eWasDefaultConstructed,
31 eWasConstructed,
32 eWasCopyConstructed,
33 eWasMoveConstructed,
34 eWasConstMoveConstructed,
35 eWasAssigned,
36 eWasCopyAssigned,
37 eWasMoveAssigned,
38 eWasCopiedFrom,
39 eWasMovedFrom,
40 eWasConstMovedFrom,
43 static size_t sUndestroyedObjects = 0;
45 static bool AllDestructorsWereCalled() { return sUndestroyedObjects == 0; }
47 struct BasicValue {
48 BasicValue() : mStatus(eWasDefaultConstructed), mTag(0) {
49 ++sUndestroyedObjects;
52 explicit BasicValue(int aTag) : mStatus(eWasConstructed), mTag(aTag) {
53 ++sUndestroyedObjects;
56 BasicValue(const BasicValue& aOther)
57 : mStatus(eWasCopyConstructed), mTag(aOther.mTag) {
58 ++sUndestroyedObjects;
61 BasicValue(BasicValue&& aOther)
62 : mStatus(eWasMoveConstructed), mTag(aOther.mTag) {
63 ++sUndestroyedObjects;
64 aOther.mStatus = eWasMovedFrom;
65 aOther.mTag = 0;
68 BasicValue(const BasicValue&& aOther)
69 : mStatus(eWasConstMoveConstructed), mTag(aOther.mTag) {
70 ++sUndestroyedObjects;
71 aOther.mStatus = eWasConstMovedFrom;
74 ~BasicValue() { --sUndestroyedObjects; }
76 BasicValue& operator=(const BasicValue& aOther) {
77 mStatus = eWasCopyAssigned;
78 mTag = aOther.mTag;
79 return *this;
82 BasicValue& operator=(BasicValue&& aOther) {
83 mStatus = eWasMoveAssigned;
84 mTag = aOther.mTag;
85 aOther.mStatus = eWasMovedFrom;
86 aOther.mTag = 0;
87 return *this;
90 bool operator==(const BasicValue& aOther) const {
91 return mTag == aOther.mTag;
94 bool operator<(const BasicValue& aOther) const { return mTag < aOther.mTag; }
96 Status GetStatus() const { return mStatus; }
97 void SetTag(int aValue) { mTag = aValue; }
98 int GetTag() const { return mTag; }
100 private:
101 mutable Status mStatus;
102 int mTag;
105 struct UncopyableValue {
106 UncopyableValue() : mStatus(eWasDefaultConstructed) { ++sUndestroyedObjects; }
108 UncopyableValue(UncopyableValue&& aOther) : mStatus(eWasMoveConstructed) {
109 ++sUndestroyedObjects;
110 aOther.mStatus = eWasMovedFrom;
113 ~UncopyableValue() { --sUndestroyedObjects; }
115 UncopyableValue& operator=(UncopyableValue&& aOther) {
116 mStatus = eWasMoveAssigned;
117 aOther.mStatus = eWasMovedFrom;
118 return *this;
121 Status GetStatus() { return mStatus; }
123 private:
124 UncopyableValue(const UncopyableValue& aOther) = delete;
125 UncopyableValue& operator=(const UncopyableValue& aOther) = delete;
127 Status mStatus;
130 struct UnmovableValue {
131 UnmovableValue() : mStatus(eWasDefaultConstructed) { ++sUndestroyedObjects; }
133 UnmovableValue(const UnmovableValue& aOther) : mStatus(eWasCopyConstructed) {
134 ++sUndestroyedObjects;
137 ~UnmovableValue() { --sUndestroyedObjects; }
139 UnmovableValue& operator=(const UnmovableValue& aOther) {
140 mStatus = eWasCopyAssigned;
141 return *this;
144 Status GetStatus() { return mStatus; }
146 UnmovableValue(UnmovableValue&& aOther) = delete;
147 UnmovableValue& operator=(UnmovableValue&& aOther) = delete;
149 private:
150 Status mStatus;
153 struct UncopyableUnmovableValue {
154 UncopyableUnmovableValue() : mStatus(eWasDefaultConstructed) {
155 ++sUndestroyedObjects;
158 explicit UncopyableUnmovableValue(int) : mStatus(eWasConstructed) {
159 ++sUndestroyedObjects;
162 ~UncopyableUnmovableValue() { --sUndestroyedObjects; }
164 Status GetStatus() const { return mStatus; }
166 private:
167 UncopyableUnmovableValue(const UncopyableUnmovableValue& aOther) = delete;
168 UncopyableUnmovableValue& operator=(const UncopyableUnmovableValue& aOther) =
169 delete;
170 UncopyableUnmovableValue(UncopyableUnmovableValue&& aOther) = delete;
171 UncopyableUnmovableValue& operator=(UncopyableUnmovableValue&& aOther) =
172 delete;
174 Status mStatus;
177 static_assert(std::is_trivially_destructible_v<Maybe<int>>);
178 static_assert(std::is_trivially_copy_constructible_v<Maybe<int>>);
179 static_assert(std::is_trivially_copy_assignable_v<Maybe<int>>);
181 static_assert(42 == Some(42).value());
182 static_assert(42 == Some(42).valueOr(43));
183 static_assert(42 == Maybe<int>{}.valueOr(42));
184 static_assert(42 == Some(42).valueOrFrom([] { return 43; }));
185 static_assert(42 == Maybe<int>{}.valueOrFrom([] { return 42; }));
186 static_assert(Some(43) == [] {
187 auto val = Some(42);
188 val.apply([](int& val) { val += 1; });
189 return val;
190 }());
191 static_assert(Some(43) == Some(42).map([](int val) { return val + 1; }));
192 static_assert(Maybe<int>(std::in_place, 43) ==
193 Maybe<int>(std::in_place, 42).map([](int val) {
194 return val + 1;
195 }));
197 struct TriviallyDestructible {
198 TriviallyDestructible() { // not trivially constructible
202 static_assert(std::is_trivially_destructible_v<Maybe<TriviallyDestructible>>);
204 struct UncopyableValueLiteralType {
205 explicit constexpr UncopyableValueLiteralType(int aValue) : mValue{aValue} {}
207 UncopyableValueLiteralType(UncopyableValueLiteralType&&) = default;
208 UncopyableValueLiteralType& operator=(UncopyableValueLiteralType&&) = default;
210 int mValue;
213 static_assert(
214 std::is_trivially_destructible_v<Maybe<UncopyableValueLiteralType>>);
215 static_assert(!std::is_copy_constructible_v<Maybe<UncopyableValueLiteralType>>);
216 static_assert(!std::is_copy_assignable_v<Maybe<UncopyableValueLiteralType>>);
217 static_assert(std::is_move_constructible_v<Maybe<UncopyableValueLiteralType>>);
218 static_assert(std::is_move_assignable_v<Maybe<UncopyableValueLiteralType>>);
220 constexpr Maybe<UncopyableValueLiteralType> someUncopyable =
221 Some(UncopyableValueLiteralType{42});
222 static_assert(someUncopyable.isSome());
223 static_assert(42 == someUncopyable->mValue);
225 constexpr Maybe<UncopyableValueLiteralType> someUncopyableAssigned = [] {
226 auto res = Maybe<UncopyableValueLiteralType>{};
227 res = Some(UncopyableValueLiteralType{42});
228 return res;
229 }();
230 static_assert(someUncopyableAssigned.isSome());
231 static_assert(42 == someUncopyableAssigned->mValue);
233 static bool TestBasicFeatures() {
234 // Check that a Maybe<T> is initialized to Nothing.
235 Maybe<BasicValue> mayValue;
236 static_assert(std::is_same_v<BasicValue, decltype(mayValue)::ValueType>,
237 "Should have BasicValue ValueType");
238 MOZ_RELEASE_ASSERT(!mayValue);
239 MOZ_RELEASE_ASSERT(!mayValue.isSome());
240 MOZ_RELEASE_ASSERT(mayValue.isNothing());
242 // Check that emplace() default constructs and the accessors work.
243 mayValue.emplace();
244 MOZ_RELEASE_ASSERT(mayValue);
245 MOZ_RELEASE_ASSERT(mayValue.isSome());
246 MOZ_RELEASE_ASSERT(!mayValue.isNothing());
247 MOZ_RELEASE_ASSERT(*mayValue == BasicValue());
248 static_assert(std::is_same_v<BasicValue&, decltype(*mayValue)>,
249 "operator*() should return a BasicValue&");
250 MOZ_RELEASE_ASSERT(mayValue.value() == BasicValue());
251 static_assert(std::is_same_v<BasicValue, decltype(mayValue.value())>,
252 "value() should return a BasicValue");
253 MOZ_RELEASE_ASSERT(mayValue.ref() == BasicValue());
254 static_assert(std::is_same_v<BasicValue&, decltype(mayValue.ref())>,
255 "ref() should return a BasicValue&");
256 MOZ_RELEASE_ASSERT(mayValue.ptr() != nullptr);
257 static_assert(std::is_same_v<BasicValue*, decltype(mayValue.ptr())>,
258 "ptr() should return a BasicValue*");
259 MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasDefaultConstructed);
261 // Check that reset() works.
262 mayValue.reset();
263 MOZ_RELEASE_ASSERT(!mayValue);
264 MOZ_RELEASE_ASSERT(!mayValue.isSome());
265 MOZ_RELEASE_ASSERT(mayValue.isNothing());
267 // Check that emplace(T1) calls the correct constructor.
268 mayValue.emplace(1);
269 MOZ_RELEASE_ASSERT(mayValue);
270 MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasConstructed);
271 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
272 mayValue.reset();
273 MOZ_RELEASE_ASSERT(!mayValue);
276 // Check that Maybe(std::in_place, T1) calls the correct constructor.
277 const auto mayValueConstructed = Maybe<BasicValue>(std::in_place, 1);
278 MOZ_RELEASE_ASSERT(mayValueConstructed);
279 MOZ_RELEASE_ASSERT(mayValueConstructed->GetStatus() == eWasConstructed);
280 MOZ_RELEASE_ASSERT(mayValueConstructed->GetTag() == 1);
283 // Check that Some() and Nothing() work.
284 mayValue = Some(BasicValue(2));
285 MOZ_RELEASE_ASSERT(mayValue);
286 MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasMoveConstructed);
287 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
288 mayValue = Nothing();
289 MOZ_RELEASE_ASSERT(!mayValue);
291 // Check that the accessors work through a const ref.
292 mayValue.emplace();
293 const Maybe<BasicValue>& mayValueCRef = mayValue;
294 MOZ_RELEASE_ASSERT(mayValueCRef);
295 MOZ_RELEASE_ASSERT(mayValueCRef.isSome());
296 MOZ_RELEASE_ASSERT(!mayValueCRef.isNothing());
297 MOZ_RELEASE_ASSERT(*mayValueCRef == BasicValue());
298 static_assert(std::is_same_v<const BasicValue&, decltype(*mayValueCRef)>,
299 "operator*() should return a BasicValue");
300 MOZ_RELEASE_ASSERT(mayValueCRef.value() == BasicValue());
301 static_assert(std::is_same_v<BasicValue, decltype(mayValueCRef.value())>,
302 "value() should return a BasicValue");
303 MOZ_RELEASE_ASSERT(mayValueCRef.ref() == BasicValue());
304 static_assert(std::is_same_v<const BasicValue&, decltype(mayValueCRef.ref())>,
305 "ref() should return a const BasicValue&");
306 MOZ_RELEASE_ASSERT(mayValueCRef.ptr() != nullptr);
307 static_assert(std::is_same_v<const BasicValue*, decltype(mayValueCRef.ptr())>,
308 "ptr() should return a const BasicValue*");
309 MOZ_RELEASE_ASSERT(mayValueCRef->GetStatus() == eWasDefaultConstructed);
310 mayValue.reset();
312 // Check that we can create and reference Maybe<const Type>.
313 Maybe<const BasicValue> mayCValue1 = Some(BasicValue(5));
314 MOZ_RELEASE_ASSERT(mayCValue1);
315 MOZ_RELEASE_ASSERT(mayCValue1.isSome());
316 MOZ_RELEASE_ASSERT(*mayCValue1 == BasicValue(5));
317 const Maybe<const BasicValue>& mayCValue1Ref = mayCValue1;
318 MOZ_RELEASE_ASSERT(mayCValue1Ref == mayCValue1);
319 MOZ_RELEASE_ASSERT(*mayCValue1Ref == BasicValue(5));
320 Maybe<const BasicValue> mayCValue2;
321 mayCValue2.emplace(6);
322 MOZ_RELEASE_ASSERT(mayCValue2);
323 MOZ_RELEASE_ASSERT(mayCValue2.isSome());
324 MOZ_RELEASE_ASSERT(*mayCValue2 == BasicValue(6));
326 // Check that accessors work through rvalue-references.
327 MOZ_RELEASE_ASSERT(Some(BasicValue()));
328 MOZ_RELEASE_ASSERT(Some(BasicValue()).isSome());
329 MOZ_RELEASE_ASSERT(!Some(BasicValue()).isNothing());
330 MOZ_RELEASE_ASSERT(*Some(BasicValue()) == BasicValue());
331 static_assert(std::is_same_v<BasicValue&&, decltype(*Some(BasicValue()))>,
332 "operator*() should return a BasicValue&&");
333 MOZ_RELEASE_ASSERT(Some(BasicValue()).value() == BasicValue());
334 static_assert(
335 std::is_same_v<BasicValue, decltype(Some(BasicValue()).value())>,
336 "value() should return a BasicValue");
337 MOZ_RELEASE_ASSERT(Some(BasicValue()).ref() == BasicValue());
338 static_assert(
339 std::is_same_v<BasicValue&&, decltype(Some(BasicValue()).ref())>,
340 "ref() should return a BasicValue&&");
341 MOZ_RELEASE_ASSERT(Some(BasicValue()).ptr() != nullptr);
342 static_assert(std::is_same_v<BasicValue*, decltype(Some(BasicValue()).ptr())>,
343 "ptr() should return a BasicValue*");
344 MOZ_RELEASE_ASSERT(Some(BasicValue())->GetStatus() == eWasMoveConstructed);
346 // Check that accessors work through const-rvalue-references.
347 auto MakeConstMaybe = []() -> const Maybe<BasicValue> {
348 return Some(BasicValue());
350 MOZ_RELEASE_ASSERT(MakeConstMaybe());
351 MOZ_RELEASE_ASSERT(MakeConstMaybe().isSome());
352 MOZ_RELEASE_ASSERT(!MakeConstMaybe().isNothing());
353 MOZ_RELEASE_ASSERT(*MakeConstMaybe() == BasicValue());
354 static_assert(std::is_same_v<const BasicValue&&, decltype(*MakeConstMaybe())>,
355 "operator*() should return a const BasicValue&&");
356 MOZ_RELEASE_ASSERT(MakeConstMaybe().value() == BasicValue());
357 static_assert(std::is_same_v<BasicValue, decltype(MakeConstMaybe().value())>,
358 "value() should return a BasicValue");
359 MOZ_RELEASE_ASSERT(MakeConstMaybe().ref() == BasicValue());
360 static_assert(
361 std::is_same_v<const BasicValue&&, decltype(MakeConstMaybe().ref())>,
362 "ref() should return a const BasicValue&&");
363 MOZ_RELEASE_ASSERT(MakeConstMaybe().ptr() != nullptr);
364 static_assert(
365 std::is_same_v<const BasicValue*, decltype(MakeConstMaybe().ptr())>,
366 "ptr() should return a const BasicValue*");
367 MOZ_RELEASE_ASSERT(MakeConstMaybe()->GetStatus() == eWasMoveConstructed);
368 MOZ_RELEASE_ASSERT(BasicValue(*MakeConstMaybe()).GetStatus() ==
369 eWasConstMoveConstructed);
371 // Check that take works
372 mayValue = Some(BasicValue(6));
373 Maybe taken = mayValue.take();
374 MOZ_RELEASE_ASSERT(taken->GetStatus() == eWasMoveConstructed);
375 MOZ_RELEASE_ASSERT(taken == Some(BasicValue(6)));
376 MOZ_RELEASE_ASSERT(!mayValue.isSome());
377 MOZ_RELEASE_ASSERT(mayValue.take() == Nothing());
379 // Check that extract works
380 mayValue = Some(BasicValue(7));
381 BasicValue extracted = mayValue.extract();
382 MOZ_RELEASE_ASSERT(extracted.GetStatus() == eWasMoveConstructed);
383 MOZ_RELEASE_ASSERT(extracted == BasicValue(7));
384 MOZ_RELEASE_ASSERT(!mayValue.isSome());
386 return true;
389 template <typename T>
390 static void TestCopyMaybe() {
392 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
394 Maybe<T> src = Some(T());
395 Maybe<T> dstCopyConstructed = src;
397 MOZ_RELEASE_ASSERT(2 == sUndestroyedObjects);
398 MOZ_RELEASE_ASSERT(dstCopyConstructed->GetStatus() == eWasCopyConstructed);
402 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
404 Maybe<T> src = Some(T());
405 Maybe<T> dstCopyAssigned;
406 dstCopyAssigned = src;
408 MOZ_RELEASE_ASSERT(2 == sUndestroyedObjects);
409 MOZ_RELEASE_ASSERT(dstCopyAssigned->GetStatus() == eWasCopyConstructed);
413 template <typename T>
414 static void TestMoveMaybe() {
416 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
418 Maybe<T> src = Some(T());
419 Maybe<T> dstMoveConstructed = std::move(src);
421 MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
422 MOZ_RELEASE_ASSERT(dstMoveConstructed->GetStatus() == eWasMoveConstructed);
426 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
428 Maybe<T> src = Some(T());
429 Maybe<T> dstMoveAssigned;
430 dstMoveAssigned = std::move(src);
432 MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
433 MOZ_RELEASE_ASSERT(dstMoveAssigned->GetStatus() == eWasMoveConstructed);
437 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
439 Maybe<T> src = Some(T());
440 Maybe<T> dstMoveConstructed = src.take();
442 MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
443 MOZ_RELEASE_ASSERT(dstMoveConstructed->GetStatus() == eWasMoveConstructed);
447 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
449 Maybe<T> src = Some(T());
450 T dstMoveConstructed = src.extract();
452 MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
453 MOZ_RELEASE_ASSERT(dstMoveConstructed.GetStatus() == eWasMoveConstructed);
457 static bool TestCopyAndMove() {
458 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
461 // Check that we get moves when possible for types that can support both
462 // moves and copies.
464 Maybe<BasicValue> mayBasicValue = Some(BasicValue(1));
465 MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
466 MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveConstructed);
467 MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 1);
468 mayBasicValue = Some(BasicValue(2));
469 MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
470 MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveAssigned);
471 MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 2);
472 mayBasicValue.reset();
473 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
474 mayBasicValue.emplace(BasicValue(3));
475 MOZ_RELEASE_ASSERT(1 == sUndestroyedObjects);
476 MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMoveConstructed);
477 MOZ_RELEASE_ASSERT(mayBasicValue->GetTag() == 3);
479 // Check that we get copies when moves aren't possible.
480 Maybe<BasicValue> mayBasicValue2 = Some(*mayBasicValue);
481 MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyConstructed);
482 MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 3);
483 mayBasicValue->SetTag(4);
484 mayBasicValue2 = mayBasicValue;
485 // This test should work again when we fix bug 1052940.
486 // MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyAssigned);
487 MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 4);
488 mayBasicValue->SetTag(5);
489 mayBasicValue2.reset();
490 mayBasicValue2.emplace(*mayBasicValue);
491 MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasCopyConstructed);
492 MOZ_RELEASE_ASSERT(mayBasicValue2->GetTag() == 5);
494 // Check that std::move() works. (Another sanity check for move support.)
495 Maybe<BasicValue> mayBasicValue3 = Some(std::move(*mayBasicValue));
496 MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMoveConstructed);
497 MOZ_RELEASE_ASSERT(mayBasicValue3->GetTag() == 5);
498 MOZ_RELEASE_ASSERT(mayBasicValue->GetStatus() == eWasMovedFrom);
499 mayBasicValue2->SetTag(6);
500 mayBasicValue3 = Some(std::move(*mayBasicValue2));
501 MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMoveAssigned);
502 MOZ_RELEASE_ASSERT(mayBasicValue3->GetTag() == 6);
503 MOZ_RELEASE_ASSERT(mayBasicValue2->GetStatus() == eWasMovedFrom);
504 Maybe<BasicValue> mayBasicValue4;
505 mayBasicValue4.emplace(std::move(*mayBasicValue3));
506 MOZ_RELEASE_ASSERT(mayBasicValue4->GetStatus() == eWasMoveConstructed);
507 MOZ_RELEASE_ASSERT(mayBasicValue4->GetTag() == 6);
508 MOZ_RELEASE_ASSERT(mayBasicValue3->GetStatus() == eWasMovedFrom);
511 TestCopyMaybe<BasicValue>();
512 TestMoveMaybe<BasicValue>();
515 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
518 // Check that we always get copies for types that don't support moves.
520 Maybe<UnmovableValue> mayUnmovableValue = Some(UnmovableValue());
521 MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
522 mayUnmovableValue.reset();
523 mayUnmovableValue.emplace(UnmovableValue());
524 MOZ_RELEASE_ASSERT(mayUnmovableValue->GetStatus() == eWasCopyConstructed);
527 TestCopyMaybe<UnmovableValue>();
529 static_assert(std::is_copy_constructible_v<Maybe<UnmovableValue>>);
530 static_assert(std::is_copy_assignable_v<Maybe<UnmovableValue>>);
531 static_assert(!std::is_move_constructible_v<Maybe<UnmovableValue>>);
532 static_assert(!std::is_move_assignable_v<Maybe<UnmovableValue>>);
535 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
538 // Check that types that only support moves, but not copies, work.
540 Maybe<UncopyableValue> mayUncopyableValue = Some(UncopyableValue());
541 MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() ==
542 eWasMoveConstructed);
543 mayUncopyableValue = Some(UncopyableValue());
544 MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() == eWasMoveAssigned);
545 mayUncopyableValue.reset();
546 mayUncopyableValue.emplace(UncopyableValue());
547 MOZ_RELEASE_ASSERT(mayUncopyableValue->GetStatus() ==
548 eWasMoveConstructed);
549 mayUncopyableValue = Nothing();
552 TestMoveMaybe<BasicValue>();
554 static_assert(!std::is_copy_constructible_v<Maybe<UncopyableValue>>);
555 static_assert(!std::is_copy_assignable_v<Maybe<UncopyableValue>>);
556 static_assert(std::is_move_constructible_v<Maybe<UncopyableValue>>);
557 static_assert(std::is_move_assignable_v<Maybe<UncopyableValue>>);
560 MOZ_RELEASE_ASSERT(0 == sUndestroyedObjects);
562 { // Check that types that support neither moves or copies work.
564 const auto mayUncopyableUnmovableValueConstructed =
565 Maybe<UncopyableUnmovableValue>{std::in_place};
566 MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValueConstructed->GetStatus() ==
567 eWasDefaultConstructed);
570 Maybe<UncopyableUnmovableValue> mayUncopyableUnmovableValue;
571 mayUncopyableUnmovableValue.emplace();
572 MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() ==
573 eWasDefaultConstructed);
574 mayUncopyableUnmovableValue.reset();
575 mayUncopyableUnmovableValue.emplace(0);
576 MOZ_RELEASE_ASSERT(mayUncopyableUnmovableValue->GetStatus() ==
577 eWasConstructed);
578 mayUncopyableUnmovableValue = Nothing();
580 static_assert(
581 !std::is_copy_constructible_v<Maybe<UncopyableUnmovableValue>>);
582 static_assert(!std::is_copy_assignable_v<Maybe<UncopyableUnmovableValue>>);
583 static_assert(
584 !std::is_move_constructible_v<Maybe<UncopyableUnmovableValue>>);
585 static_assert(!std::is_move_assignable_v<Maybe<UncopyableUnmovableValue>>);
589 // Test copy and move with a trivially copyable and trivially destructible
590 // type.
592 constexpr Maybe<int> src = Some(42);
593 constexpr Maybe<int> dstCopyConstructed = src;
595 static_assert(src.isSome());
596 static_assert(dstCopyConstructed.isSome());
597 static_assert(42 == *src);
598 static_assert(42 == *dstCopyConstructed);
599 static_assert(42 == dstCopyConstructed.value());
603 const Maybe<int> src = Some(42);
604 Maybe<int> dstCopyAssigned;
605 dstCopyAssigned = src;
607 MOZ_RELEASE_ASSERT(src.isSome());
608 MOZ_RELEASE_ASSERT(dstCopyAssigned.isSome());
609 MOZ_RELEASE_ASSERT(42 == *src);
610 MOZ_RELEASE_ASSERT(42 == *dstCopyAssigned);
614 Maybe<int> src = Some(42);
615 const Maybe<int> dstMoveConstructed = std::move(src);
617 MOZ_RELEASE_ASSERT(!src.isSome());
618 MOZ_RELEASE_ASSERT(dstMoveConstructed.isSome());
619 MOZ_RELEASE_ASSERT(42 == *dstMoveConstructed);
623 Maybe<int> src = Some(42);
624 Maybe<int> dstMoveAssigned;
625 dstMoveAssigned = std::move(src);
627 MOZ_RELEASE_ASSERT(!src.isSome());
628 MOZ_RELEASE_ASSERT(dstMoveAssigned.isSome());
629 MOZ_RELEASE_ASSERT(42 == *dstMoveAssigned);
633 return true;
636 static BasicValue* sStaticBasicValue = nullptr;
638 static BasicValue MakeBasicValue() { return BasicValue(9); }
640 static BasicValue& MakeBasicValueRef() { return *sStaticBasicValue; }
642 static BasicValue* MakeBasicValuePtr() { return sStaticBasicValue; }
644 static bool TestFunctionalAccessors() {
645 BasicValue value(9);
646 sStaticBasicValue = new BasicValue(9);
648 // Check that the 'some' case of functional accessors works.
649 Maybe<BasicValue> someValue = Some(BasicValue(3));
650 MOZ_RELEASE_ASSERT(someValue.valueOr(value) == BasicValue(3));
651 static_assert(std::is_same_v<BasicValue, decltype(someValue.valueOr(value))>,
652 "valueOr should return a BasicValue");
653 MOZ_RELEASE_ASSERT(someValue.valueOrFrom(&MakeBasicValue) == BasicValue(3));
654 static_assert(
655 std::is_same_v<BasicValue,
656 decltype(someValue.valueOrFrom(&MakeBasicValue))>,
657 "valueOrFrom should return a BasicValue");
658 MOZ_RELEASE_ASSERT(someValue.ptrOr(&value) != &value);
659 static_assert(std::is_same_v<BasicValue*, decltype(someValue.ptrOr(&value))>,
660 "ptrOr should return a BasicValue*");
661 MOZ_RELEASE_ASSERT(*someValue.ptrOrFrom(&MakeBasicValuePtr) == BasicValue(3));
662 static_assert(
663 std::is_same_v<BasicValue*,
664 decltype(someValue.ptrOrFrom(&MakeBasicValuePtr))>,
665 "ptrOrFrom should return a BasicValue*");
666 MOZ_RELEASE_ASSERT(someValue.refOr(value) == BasicValue(3));
667 static_assert(std::is_same_v<BasicValue&, decltype(someValue.refOr(value))>,
668 "refOr should return a BasicValue&");
669 MOZ_RELEASE_ASSERT(someValue.refOrFrom(&MakeBasicValueRef) == BasicValue(3));
670 static_assert(
671 std::is_same_v<BasicValue&,
672 decltype(someValue.refOrFrom(&MakeBasicValueRef))>,
673 "refOrFrom should return a BasicValue&");
675 // Check that the 'some' case works through a const reference.
676 const Maybe<BasicValue>& someValueCRef = someValue;
677 MOZ_RELEASE_ASSERT(someValueCRef.valueOr(value) == BasicValue(3));
678 static_assert(
679 std::is_same_v<BasicValue, decltype(someValueCRef.valueOr(value))>,
680 "valueOr should return a BasicValue");
681 MOZ_RELEASE_ASSERT(someValueCRef.valueOrFrom(&MakeBasicValue) ==
682 BasicValue(3));
683 static_assert(
684 std::is_same_v<BasicValue,
685 decltype(someValueCRef.valueOrFrom(&MakeBasicValue))>,
686 "valueOrFrom should return a BasicValue");
687 MOZ_RELEASE_ASSERT(someValueCRef.ptrOr(&value) != &value);
688 static_assert(
689 std::is_same_v<const BasicValue*, decltype(someValueCRef.ptrOr(&value))>,
690 "ptrOr should return a const BasicValue*");
691 MOZ_RELEASE_ASSERT(*someValueCRef.ptrOrFrom(&MakeBasicValuePtr) ==
692 BasicValue(3));
693 static_assert(
694 std::is_same_v<const BasicValue*,
695 decltype(someValueCRef.ptrOrFrom(&MakeBasicValuePtr))>,
696 "ptrOrFrom should return a const BasicValue*");
697 MOZ_RELEASE_ASSERT(someValueCRef.refOr(value) == BasicValue(3));
698 static_assert(
699 std::is_same_v<const BasicValue&, decltype(someValueCRef.refOr(value))>,
700 "refOr should return a const BasicValue&");
701 MOZ_RELEASE_ASSERT(someValueCRef.refOrFrom(&MakeBasicValueRef) ==
702 BasicValue(3));
703 static_assert(
704 std::is_same_v<const BasicValue&,
705 decltype(someValueCRef.refOrFrom(&MakeBasicValueRef))>,
706 "refOrFrom should return a const BasicValue&");
708 // Check that the 'none' case of functional accessors works.
709 Maybe<BasicValue> noneValue;
710 MOZ_RELEASE_ASSERT(noneValue.valueOr(value) == BasicValue(9));
711 static_assert(std::is_same_v<BasicValue, decltype(noneValue.valueOr(value))>,
712 "valueOr should return a BasicValue");
713 MOZ_RELEASE_ASSERT(noneValue.valueOrFrom(&MakeBasicValue) == BasicValue(9));
714 static_assert(
715 std::is_same_v<BasicValue,
716 decltype(noneValue.valueOrFrom(&MakeBasicValue))>,
717 "valueOrFrom should return a BasicValue");
718 MOZ_RELEASE_ASSERT(noneValue.ptrOr(&value) == &value);
719 static_assert(std::is_same_v<BasicValue*, decltype(noneValue.ptrOr(&value))>,
720 "ptrOr should return a BasicValue*");
721 MOZ_RELEASE_ASSERT(*noneValue.ptrOrFrom(&MakeBasicValuePtr) == BasicValue(9));
722 static_assert(
723 std::is_same_v<BasicValue*,
724 decltype(noneValue.ptrOrFrom(&MakeBasicValuePtr))>,
725 "ptrOrFrom should return a BasicValue*");
726 MOZ_RELEASE_ASSERT(noneValue.refOr(value) == BasicValue(9));
727 static_assert(std::is_same_v<BasicValue&, decltype(noneValue.refOr(value))>,
728 "refOr should return a BasicValue&");
729 MOZ_RELEASE_ASSERT(noneValue.refOrFrom(&MakeBasicValueRef) == BasicValue(9));
730 static_assert(
731 std::is_same_v<BasicValue&,
732 decltype(noneValue.refOrFrom(&MakeBasicValueRef))>,
733 "refOrFrom should return a BasicValue&");
735 // Check that the 'none' case works through a const reference.
736 const Maybe<BasicValue>& noneValueCRef = noneValue;
737 MOZ_RELEASE_ASSERT(noneValueCRef.valueOr(value) == BasicValue(9));
738 static_assert(
739 std::is_same_v<BasicValue, decltype(noneValueCRef.valueOr(value))>,
740 "valueOr should return a BasicValue");
741 MOZ_RELEASE_ASSERT(noneValueCRef.valueOrFrom(&MakeBasicValue) ==
742 BasicValue(9));
743 static_assert(
744 std::is_same_v<BasicValue,
745 decltype(noneValueCRef.valueOrFrom(&MakeBasicValue))>,
746 "valueOrFrom should return a BasicValue");
747 MOZ_RELEASE_ASSERT(noneValueCRef.ptrOr(&value) == &value);
748 static_assert(
749 std::is_same_v<const BasicValue*, decltype(noneValueCRef.ptrOr(&value))>,
750 "ptrOr should return a const BasicValue*");
751 MOZ_RELEASE_ASSERT(*noneValueCRef.ptrOrFrom(&MakeBasicValuePtr) ==
752 BasicValue(9));
753 static_assert(
754 std::is_same_v<const BasicValue*,
755 decltype(noneValueCRef.ptrOrFrom(&MakeBasicValuePtr))>,
756 "ptrOrFrom should return a const BasicValue*");
757 MOZ_RELEASE_ASSERT(noneValueCRef.refOr(value) == BasicValue(9));
758 static_assert(
759 std::is_same_v<const BasicValue&, decltype(noneValueCRef.refOr(value))>,
760 "refOr should return a const BasicValue&");
761 MOZ_RELEASE_ASSERT(noneValueCRef.refOrFrom(&MakeBasicValueRef) ==
762 BasicValue(9));
763 static_assert(
764 std::is_same_v<const BasicValue&,
765 decltype(noneValueCRef.refOrFrom(&MakeBasicValueRef))>,
766 "refOrFrom should return a const BasicValue&");
768 // Clean up so the undestroyed objects count stays accurate.
769 delete sStaticBasicValue;
770 sStaticBasicValue = nullptr;
772 return true;
775 static bool gFunctionWasApplied = false;
777 static void IncrementTag(BasicValue& aValue) {
778 gFunctionWasApplied = true;
779 aValue.SetTag(aValue.GetTag() + 1);
782 static void AccessValue(const BasicValue&) { gFunctionWasApplied = true; }
784 struct IncrementTagFunctor {
785 IncrementTagFunctor() : mBy(1) {}
787 void operator()(BasicValue& aValue) {
788 aValue.SetTag(aValue.GetTag() + mBy.GetTag());
791 BasicValue mBy;
794 static bool TestApply() {
795 // Check that apply handles the 'Nothing' case.
796 gFunctionWasApplied = false;
797 Maybe<BasicValue> mayValue;
798 mayValue.apply(&IncrementTag);
799 mayValue.apply(&AccessValue);
800 MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
802 // Check that apply handles the 'Some' case.
803 mayValue = Some(BasicValue(1));
804 mayValue.apply(&IncrementTag);
805 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
806 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
807 gFunctionWasApplied = false;
808 mayValue.apply(&AccessValue);
809 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
811 // Check that apply works with a const reference.
812 const Maybe<BasicValue>& mayValueCRef = mayValue;
813 gFunctionWasApplied = false;
814 mayValueCRef.apply(&AccessValue);
815 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
817 // Check that apply works with functors.
818 IncrementTagFunctor tagIncrementer;
819 MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
820 mayValue = Some(BasicValue(1));
821 mayValue.apply(tagIncrementer);
822 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
823 MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
825 // Check that apply works with lambda expressions.
826 int32_t two = 2;
827 gFunctionWasApplied = false;
828 mayValue = Some(BasicValue(2));
829 mayValue.apply([&](BasicValue& aVal) { aVal.SetTag(aVal.GetTag() * two); });
830 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 4);
831 mayValue.apply([=](BasicValue& aVal) { aVal.SetTag(aVal.GetTag() * two); });
832 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 8);
833 mayValueCRef.apply(
834 [&](const BasicValue& aVal) { gFunctionWasApplied = true; });
835 MOZ_RELEASE_ASSERT(gFunctionWasApplied == true);
837 // Check that apply can move the contained value.
838 mayValue = Some(BasicValue(1));
839 Maybe<BasicValue> otherValue;
840 std::move(mayValue).apply(
841 [&](BasicValue&& aVal) { otherValue = Some(std::move(aVal)); });
842 MOZ_RELEASE_ASSERT(mayValue.isNothing());
843 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
844 MOZ_RELEASE_ASSERT(otherValue->GetStatus() == eWasMoveConstructed);
846 return true;
849 static int TimesTwo(const BasicValue& aValue) { return aValue.GetTag() * 2; }
851 static int TimesTwoAndResetOriginal(BasicValue& aValue) {
852 int tag = aValue.GetTag();
853 aValue.SetTag(1);
854 return tag * 2;
857 struct MultiplyTagFunctor {
858 MultiplyTagFunctor() : mBy(2) {}
860 int operator()(BasicValue& aValue) { return aValue.GetTag() * mBy.GetTag(); }
862 BasicValue mBy;
865 static bool TestMap() {
866 // Check that map handles the 'Nothing' case.
867 Maybe<BasicValue> mayValue;
868 MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwo) == Nothing());
869 static_assert(std::is_same_v<Maybe<int>, decltype(mayValue.map(&TimesTwo))>,
870 "map(TimesTwo) should return a Maybe<int>");
871 MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwoAndResetOriginal) == Nothing());
873 // Check that map handles the 'Some' case.
874 mayValue = Some(BasicValue(2));
875 MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwo) == Some(4));
876 MOZ_RELEASE_ASSERT(mayValue.map(&TimesTwoAndResetOriginal) == Some(4));
877 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
878 mayValue = Some(BasicValue(2));
880 // Check that map works with a const reference.
881 mayValue->SetTag(2);
882 const Maybe<BasicValue>& mayValueCRef = mayValue;
883 MOZ_RELEASE_ASSERT(mayValueCRef.map(&TimesTwo) == Some(4));
884 static_assert(
885 std::is_same_v<Maybe<int>, decltype(mayValueCRef.map(&TimesTwo))>,
886 "map(TimesTwo) should return a Maybe<int>");
888 // Check that map works with functors.
889 MultiplyTagFunctor tagMultiplier;
890 MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
891 MOZ_RELEASE_ASSERT(mayValue.map(tagMultiplier) == Some(4));
892 MOZ_RELEASE_ASSERT(tagMultiplier.mBy.GetStatus() == eWasConstructed);
894 // Check that map works with lambda expressions.
895 int two = 2;
896 mayValue = Some(BasicValue(2));
897 Maybe<int> mappedValue =
898 mayValue.map([&](const BasicValue& aVal) { return aVal.GetTag() * two; });
899 MOZ_RELEASE_ASSERT(mappedValue == Some(4));
900 mappedValue =
901 mayValue.map([=](const BasicValue& aVal) { return aVal.GetTag() * two; });
902 MOZ_RELEASE_ASSERT(mappedValue == Some(4));
903 mappedValue = mayValueCRef.map(
904 [&](const BasicValue& aVal) { return aVal.GetTag() * two; });
905 MOZ_RELEASE_ASSERT(mappedValue == Some(4));
907 // Check that map can move the contained value.
908 mayValue = Some(BasicValue(1));
909 Maybe<BasicValue> otherValue = std::move(mayValue).map(
910 [](BasicValue&& aValue) { return std::move(aValue); });
911 MOZ_RELEASE_ASSERT(mayValue.isNothing());
912 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
913 MOZ_RELEASE_ASSERT(otherValue->GetStatus() == eWasMoveConstructed);
915 // Check that function object qualifiers are preserved when invoked.
916 struct F {
917 std::integral_constant<int, 1> operator()(int) & { return {}; }
918 std::integral_constant<int, 2> operator()(int) const& { return {}; }
919 std::integral_constant<int, 3> operator()(int) && { return {}; }
920 std::integral_constant<int, 4> operator()(int) const&& { return {}; }
922 Maybe<int> mi = Some(0);
923 const Maybe<int> cmi = Some(0);
924 F f;
925 static_assert(std::is_same<decltype(mi.map(f)),
926 Maybe<std::integral_constant<int, 1>>>::value,
927 "Maybe.map(&)");
928 MOZ_RELEASE_ASSERT(mi.map(f).value()() == 1);
929 static_assert(std::is_same<decltype(cmi.map(f)),
930 Maybe<std::integral_constant<int, 1>>>::value,
931 "const Maybe.map(&)");
932 MOZ_RELEASE_ASSERT(cmi.map(f).value()() == 1);
933 const F cf;
934 static_assert(std::is_same<decltype(mi.map(cf)),
935 Maybe<std::integral_constant<int, 2>>>::value,
936 "Maybe.map(const &)");
937 MOZ_RELEASE_ASSERT(mi.map(cf).value() == 2);
938 static_assert(std::is_same<decltype(cmi.map(cf)),
939 Maybe<std::integral_constant<int, 2>>>::value,
940 "const Maybe.map(const &)");
941 MOZ_RELEASE_ASSERT(cmi.map(cf).value() == 2);
942 static_assert(std::is_same<decltype(mi.map(F{})),
943 Maybe<std::integral_constant<int, 3>>>::value,
944 "Maybe.map(&&)");
945 MOZ_RELEASE_ASSERT(mi.map(F{}).value() == 3);
946 static_assert(std::is_same<decltype(cmi.map(F{})),
947 Maybe<std::integral_constant<int, 3>>>::value,
948 "const Maybe.map(&&)");
949 MOZ_RELEASE_ASSERT(cmi.map(F{}).value() == 3);
950 using CF = const F;
951 static_assert(std::is_same<decltype(mi.map(CF{})),
952 Maybe<std::integral_constant<int, 4>>>::value,
953 "Maybe.map(const &&)");
954 MOZ_RELEASE_ASSERT(mi.map(CF{}).value() == 4);
955 static_assert(std::is_same<decltype(cmi.map(CF{})),
956 Maybe<std::integral_constant<int, 4>>>::value,
957 "const Maybe.map(const &&)");
958 MOZ_RELEASE_ASSERT(cmi.map(CF{}).value() == 4);
960 return true;
963 static bool TestToMaybe() {
964 BasicValue value(1);
965 BasicValue* nullPointer = nullptr;
967 // Check that a non-null pointer translates into a Some value.
968 Maybe<BasicValue> mayValue = ToMaybe(&value);
969 static_assert(std::is_same_v<Maybe<BasicValue>, decltype(ToMaybe(&value))>,
970 "ToMaybe should return a Maybe<BasicValue>");
971 MOZ_RELEASE_ASSERT(mayValue.isSome());
972 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
973 MOZ_RELEASE_ASSERT(mayValue->GetStatus() == eWasCopyConstructed);
974 MOZ_RELEASE_ASSERT(value.GetStatus() != eWasMovedFrom);
976 // Check that a null pointer translates into a Nothing value.
977 mayValue = ToMaybe(nullPointer);
978 static_assert(
979 std::is_same_v<Maybe<BasicValue>, decltype(ToMaybe(nullPointer))>,
980 "ToMaybe should return a Maybe<BasicValue>");
981 MOZ_RELEASE_ASSERT(mayValue.isNothing());
983 return true;
986 static bool TestComparisonOperators() {
987 Maybe<BasicValue> nothingValue = Nothing();
988 Maybe<BasicValue> anotherNothingValue = Nothing();
989 Maybe<BasicValue> oneValue = Some(BasicValue(1));
990 Maybe<BasicValue> anotherOneValue = Some(BasicValue(1));
991 Maybe<BasicValue> twoValue = Some(BasicValue(2));
993 // Check equality.
994 MOZ_RELEASE_ASSERT(nothingValue == anotherNothingValue);
995 MOZ_RELEASE_ASSERT(oneValue == anotherOneValue);
997 // Check inequality.
998 MOZ_RELEASE_ASSERT(nothingValue != oneValue);
999 MOZ_RELEASE_ASSERT(oneValue != nothingValue);
1000 MOZ_RELEASE_ASSERT(oneValue != twoValue);
1002 // Check '<'.
1003 MOZ_RELEASE_ASSERT(nothingValue < oneValue);
1004 MOZ_RELEASE_ASSERT(oneValue < twoValue);
1006 // Check '<='.
1007 MOZ_RELEASE_ASSERT(nothingValue <= anotherNothingValue);
1008 MOZ_RELEASE_ASSERT(nothingValue <= oneValue);
1009 MOZ_RELEASE_ASSERT(oneValue <= oneValue);
1010 MOZ_RELEASE_ASSERT(oneValue <= twoValue);
1012 // Check '>'.
1013 MOZ_RELEASE_ASSERT(oneValue > nothingValue);
1014 MOZ_RELEASE_ASSERT(twoValue > oneValue);
1016 // Check '>='.
1017 MOZ_RELEASE_ASSERT(nothingValue >= anotherNothingValue);
1018 MOZ_RELEASE_ASSERT(oneValue >= nothingValue);
1019 MOZ_RELEASE_ASSERT(oneValue >= oneValue);
1020 MOZ_RELEASE_ASSERT(twoValue >= oneValue);
1022 return true;
1025 // Check that Maybe<> can wrap a superclass that happens to also be a concrete
1026 // class (i.e. that the compiler doesn't warn when we invoke the superclass's
1027 // destructor explicitly in |reset()|.
1028 class MySuperClass {
1029 virtual void VirtualMethod() { /* do nothing */
1033 class MyDerivedClass : public MySuperClass {
1034 void VirtualMethod() override { /* do nothing */
1038 static bool TestVirtualFunction() {
1039 Maybe<MySuperClass> super;
1040 super.emplace();
1041 super.reset();
1043 Maybe<MyDerivedClass> derived;
1044 derived.emplace();
1045 derived.reset();
1047 // If this compiles successfully, we've passed.
1048 return true;
1051 static Maybe<int*> ReturnSomeNullptr() { return Some(nullptr); }
1053 struct D {
1054 explicit D(const Maybe<int*>&) {}
1057 static bool TestSomeNullptrConversion() {
1058 Maybe<int*> m1 = Some(nullptr);
1059 MOZ_RELEASE_ASSERT(m1.isSome());
1060 MOZ_RELEASE_ASSERT(m1);
1061 MOZ_RELEASE_ASSERT(!*m1);
1063 auto m2 = ReturnSomeNullptr();
1064 MOZ_RELEASE_ASSERT(m2.isSome());
1065 MOZ_RELEASE_ASSERT(m2);
1066 MOZ_RELEASE_ASSERT(!*m2);
1068 Maybe<decltype(nullptr)> m3 = Some(nullptr);
1069 MOZ_RELEASE_ASSERT(m3.isSome());
1070 MOZ_RELEASE_ASSERT(m3);
1071 MOZ_RELEASE_ASSERT(*m3 == nullptr);
1073 D d(Some(nullptr));
1075 return true;
1078 struct Base {};
1079 struct Derived : Base {};
1081 static Maybe<Base*> ReturnDerivedPointer() {
1082 Derived* d = nullptr;
1083 return Some(d);
1086 struct ExplicitConstructorBasePointer {
1087 explicit ExplicitConstructorBasePointer(const Maybe<Base*>&) {}
1090 static bool TestSomePointerConversion() {
1091 Base base;
1092 Derived derived;
1094 Maybe<Base*> m1 = Some(&derived);
1095 MOZ_RELEASE_ASSERT(m1.isSome());
1096 MOZ_RELEASE_ASSERT(m1);
1097 MOZ_RELEASE_ASSERT(*m1 == &derived);
1099 auto m2 = ReturnDerivedPointer();
1100 MOZ_RELEASE_ASSERT(m2.isSome());
1101 MOZ_RELEASE_ASSERT(m2);
1102 MOZ_RELEASE_ASSERT(*m2 == nullptr);
1104 Maybe<Base*> m3 = Some(&base);
1105 MOZ_RELEASE_ASSERT(m3.isSome());
1106 MOZ_RELEASE_ASSERT(m3);
1107 MOZ_RELEASE_ASSERT(*m3 == &base);
1109 auto s1 = Some(&derived);
1110 Maybe<Base*> c1(s1);
1111 MOZ_RELEASE_ASSERT(c1.isSome());
1112 MOZ_RELEASE_ASSERT(c1);
1113 MOZ_RELEASE_ASSERT(*c1 == &derived);
1115 ExplicitConstructorBasePointer ecbp(Some(&derived));
1117 return true;
1120 struct SourceType1 {
1121 int mTag;
1123 operator int() const { return mTag; }
1125 struct DestType {
1126 int mTag;
1127 Status mStatus;
1129 DestType() : mTag(0), mStatus(eWasDefaultConstructed) {}
1131 MOZ_IMPLICIT DestType(int aTag) : mTag(aTag), mStatus(eWasConstructed) {}
1133 MOZ_IMPLICIT DestType(SourceType1&& aSrc)
1134 : mTag(aSrc.mTag), mStatus(eWasMoveConstructed) {}
1136 MOZ_IMPLICIT DestType(const SourceType1& aSrc)
1137 : mTag(aSrc.mTag), mStatus(eWasCopyConstructed) {}
1139 DestType& operator=(int aTag) {
1140 mTag = aTag;
1141 mStatus = eWasAssigned;
1142 return *this;
1145 DestType& operator=(SourceType1&& aSrc) {
1146 mTag = aSrc.mTag;
1147 mStatus = eWasMoveAssigned;
1148 return *this;
1151 DestType& operator=(const SourceType1& aSrc) {
1152 mTag = aSrc.mTag;
1153 mStatus = eWasCopyAssigned;
1154 return *this;
1157 struct SourceType2 {
1158 int mTag;
1160 operator DestType() const& {
1161 DestType result;
1162 result.mTag = mTag;
1163 result.mStatus = eWasCopiedFrom;
1164 return result;
1167 operator DestType() && {
1168 DestType result;
1169 result.mTag = mTag;
1170 result.mStatus = eWasMovedFrom;
1171 return result;
1175 static bool TestTypeConversion() {
1177 Maybe<SourceType1> src = Some(SourceType1{1});
1178 Maybe<DestType> dest = src;
1179 MOZ_RELEASE_ASSERT(src.isSome() && src->mTag == 1);
1180 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 1);
1181 MOZ_RELEASE_ASSERT(dest->mStatus == eWasCopyConstructed);
1183 src = Some(SourceType1{2});
1184 dest = src;
1185 MOZ_RELEASE_ASSERT(src.isSome() && src->mTag == 2);
1186 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 2);
1187 MOZ_RELEASE_ASSERT(dest->mStatus == eWasCopyAssigned);
1191 Maybe<SourceType1> src = Some(SourceType1{1});
1192 Maybe<DestType> dest = std::move(src);
1193 MOZ_RELEASE_ASSERT(src.isNothing());
1194 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 1);
1195 MOZ_RELEASE_ASSERT(dest->mStatus == eWasMoveConstructed);
1197 src = Some(SourceType1{2});
1198 dest = std::move(src);
1199 MOZ_RELEASE_ASSERT(src.isNothing());
1200 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 2);
1201 MOZ_RELEASE_ASSERT(dest->mStatus == eWasMoveAssigned);
1205 Maybe<SourceType2> src = Some(SourceType2{1});
1206 Maybe<DestType> dest = src;
1207 MOZ_RELEASE_ASSERT(src.isSome() && src->mTag == 1);
1208 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 1);
1209 MOZ_RELEASE_ASSERT(dest->mStatus == eWasCopiedFrom);
1211 src = Some(SourceType2{2});
1212 dest = src;
1213 MOZ_RELEASE_ASSERT(src.isSome() && src->mTag == 2);
1214 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 2);
1215 MOZ_RELEASE_ASSERT(dest->mStatus == eWasCopiedFrom);
1219 Maybe<SourceType2> src = Some(SourceType2{1});
1220 Maybe<DestType> dest = std::move(src);
1221 MOZ_RELEASE_ASSERT(src.isNothing());
1222 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 1);
1223 MOZ_RELEASE_ASSERT(dest->mStatus == eWasMovedFrom);
1225 src = Some(SourceType2{2});
1226 dest = std::move(src);
1227 MOZ_RELEASE_ASSERT(src.isNothing());
1228 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 2);
1229 MOZ_RELEASE_ASSERT(dest->mStatus == eWasMovedFrom);
1233 Maybe<int> src = Some(1);
1234 Maybe<DestType> dest = src;
1235 MOZ_RELEASE_ASSERT(src.isSome() && *src == 1);
1236 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 1);
1237 MOZ_RELEASE_ASSERT(dest->mStatus == eWasConstructed);
1239 src = Some(2);
1240 dest = src;
1241 MOZ_RELEASE_ASSERT(src.isSome() && *src == 2);
1242 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 2);
1243 MOZ_RELEASE_ASSERT(dest->mStatus == eWasAssigned);
1247 Maybe<int> src = Some(1);
1248 Maybe<DestType> dest = std::move(src);
1249 MOZ_RELEASE_ASSERT(src.isNothing());
1250 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 1);
1251 MOZ_RELEASE_ASSERT(dest->mStatus == eWasConstructed);
1253 src = Some(2);
1254 dest = std::move(src);
1255 MOZ_RELEASE_ASSERT(src.isNothing());
1256 MOZ_RELEASE_ASSERT(dest.isSome() && dest->mTag == 2);
1257 MOZ_RELEASE_ASSERT(dest->mStatus == eWasAssigned);
1261 Maybe<SourceType1> src = Some(SourceType1{1});
1262 Maybe<int> dest = src;
1263 MOZ_RELEASE_ASSERT(src.isSome() && src->mTag == 1);
1264 MOZ_RELEASE_ASSERT(dest.isSome() && *dest == 1);
1266 src = Some(SourceType1{2});
1267 dest = src;
1268 MOZ_RELEASE_ASSERT(src.isSome() && src->mTag == 2);
1269 MOZ_RELEASE_ASSERT(dest.isSome() && *dest == 2);
1273 Maybe<SourceType1> src = Some(SourceType1{1});
1274 Maybe<int> dest = std::move(src);
1275 MOZ_RELEASE_ASSERT(src.isNothing());
1276 MOZ_RELEASE_ASSERT(dest.isSome() && *dest == 1);
1278 src = Some(SourceType1{2});
1279 dest = std::move(src);
1280 MOZ_RELEASE_ASSERT(src.isNothing());
1281 MOZ_RELEASE_ASSERT(dest.isSome() && *dest == 2);
1285 Maybe<size_t> src = Some(1);
1286 Maybe<char16_t> dest = src;
1287 MOZ_RELEASE_ASSERT(src.isSome() && *src == 1);
1288 MOZ_RELEASE_ASSERT(dest.isSome() && *dest == 1);
1290 src = Some(2);
1291 dest = src;
1292 MOZ_RELEASE_ASSERT(src.isSome() && *src == 2);
1293 MOZ_RELEASE_ASSERT(dest.isSome() && *dest == 2);
1297 Maybe<size_t> src = Some(1);
1298 Maybe<char16_t> dest = std::move(src);
1299 MOZ_RELEASE_ASSERT(src.isNothing());
1300 MOZ_RELEASE_ASSERT(dest.isSome() && *dest == 1);
1302 src = Some(2);
1303 dest = std::move(src);
1304 MOZ_RELEASE_ASSERT(src.isNothing());
1305 MOZ_RELEASE_ASSERT(dest.isSome() && *dest == 2);
1308 return true;
1311 static bool TestReference() {
1312 static_assert(std::is_trivially_destructible_v<Maybe<int&>>);
1313 static_assert(std::is_trivially_copy_constructible_v<Maybe<int&>>);
1314 static_assert(std::is_trivially_copy_assignable_v<Maybe<int&>>);
1316 static_assert(Maybe<int&>{}.isNothing());
1317 static_assert(Maybe<int&>{Nothing{}}.isNothing());
1320 Maybe<int&> defaultConstructed;
1322 MOZ_RELEASE_ASSERT(defaultConstructed.isNothing());
1323 MOZ_RELEASE_ASSERT(!defaultConstructed.isSome());
1324 MOZ_RELEASE_ASSERT(!defaultConstructed);
1328 Maybe<int&> nothing = Nothing();
1330 MOZ_RELEASE_ASSERT(nothing.isNothing());
1331 MOZ_RELEASE_ASSERT(!nothing.isSome());
1332 MOZ_RELEASE_ASSERT(!nothing);
1336 int foo = 42, bar = 42;
1337 Maybe<int&> some = SomeRef(foo);
1339 MOZ_RELEASE_ASSERT(!some.isNothing());
1340 MOZ_RELEASE_ASSERT(some.isSome());
1341 MOZ_RELEASE_ASSERT(some);
1342 MOZ_RELEASE_ASSERT(&some.ref() == &foo);
1344 MOZ_RELEASE_ASSERT(some.refEquals(foo));
1345 MOZ_RELEASE_ASSERT(some.refEquals(SomeRef(foo)));
1346 MOZ_RELEASE_ASSERT(!some.refEquals(Nothing()));
1347 MOZ_RELEASE_ASSERT(!some.refEquals(bar));
1348 MOZ_RELEASE_ASSERT(!some.refEquals(SomeRef(bar)));
1350 some.ref()++;
1351 MOZ_RELEASE_ASSERT(43 == foo);
1353 (*some)++;
1354 MOZ_RELEASE_ASSERT(44 == foo);
1358 int foo = 42, bar = 42;
1359 Maybe<int&> some;
1360 some.emplace(foo);
1362 MOZ_RELEASE_ASSERT(!some.isNothing());
1363 MOZ_RELEASE_ASSERT(some.isSome());
1364 MOZ_RELEASE_ASSERT(some);
1365 MOZ_RELEASE_ASSERT(&some.ref() == &foo);
1367 MOZ_RELEASE_ASSERT(some.refEquals(foo));
1368 MOZ_RELEASE_ASSERT(some.refEquals(SomeRef(foo)));
1369 MOZ_RELEASE_ASSERT(!some.refEquals(Nothing()));
1370 MOZ_RELEASE_ASSERT(!some.refEquals(bar));
1371 MOZ_RELEASE_ASSERT(!some.refEquals(SomeRef(bar)));
1373 some.ref()++;
1374 MOZ_RELEASE_ASSERT(43 == foo);
1378 Maybe<int&> defaultConstructed;
1379 defaultConstructed.reset();
1381 MOZ_RELEASE_ASSERT(defaultConstructed.isNothing());
1382 MOZ_RELEASE_ASSERT(!defaultConstructed.isSome());
1383 MOZ_RELEASE_ASSERT(!defaultConstructed);
1387 int foo = 42;
1388 Maybe<int&> some = SomeRef(foo);
1389 some.reset();
1391 MOZ_RELEASE_ASSERT(some.isNothing());
1392 MOZ_RELEASE_ASSERT(!some.isSome());
1393 MOZ_RELEASE_ASSERT(!some);
1397 int foo = 42;
1398 Maybe<int&> some = SomeRef(foo);
1400 auto& applied = some.apply([](int& ref) { ref++; });
1402 MOZ_RELEASE_ASSERT(&some == &applied);
1403 MOZ_RELEASE_ASSERT(43 == foo);
1407 Maybe<int&> nothing;
1409 auto& applied = nothing.apply([](int& ref) { ref++; });
1411 MOZ_RELEASE_ASSERT(&nothing == &applied);
1415 int foo = 42;
1416 Maybe<int&> some = SomeRef(foo);
1418 auto mapped = some.map([](int& ref) { return &ref; });
1419 static_assert(std::is_same_v<decltype(mapped), Maybe<int*>>);
1421 MOZ_RELEASE_ASSERT(&foo == *mapped);
1425 Maybe<int&> nothing;
1427 auto mapped = nothing.map([](int& ref) { return &ref; });
1429 MOZ_RELEASE_ASSERT(mapped.isNothing());
1430 MOZ_RELEASE_ASSERT(!mapped.isSome());
1431 MOZ_RELEASE_ASSERT(!mapped);
1435 int foo = 42;
1436 auto someRef = ToMaybeRef(&foo);
1438 static_assert(std::is_same_v<decltype(someRef), Maybe<int&>>);
1440 MOZ_RELEASE_ASSERT(someRef.isSome());
1441 MOZ_RELEASE_ASSERT(&foo == &someRef.ref());
1445 int* fooPtr = nullptr;
1446 auto someRef = ToMaybeRef(fooPtr);
1448 static_assert(std::is_same_v<decltype(someRef), Maybe<int&>>);
1450 MOZ_RELEASE_ASSERT(someRef.isNothing());
1453 return true;
1456 static Maybe<int> IncrementAndReturnTag(BasicValue& aValue) {
1457 gFunctionWasApplied = true;
1458 aValue.SetTag(aValue.GetTag() + 1);
1459 return Some(aValue.GetTag());
1462 static Maybe<int> AccessValueAndReturnNothing(const BasicValue&) {
1463 gFunctionWasApplied = true;
1464 return Nothing();
1467 static Maybe<int> AccessValueAndReturnOther(const BasicValue&) {
1468 gFunctionWasApplied = true;
1469 return Some(42);
1472 struct IncrementAndReturnTagFunctor {
1473 IncrementAndReturnTagFunctor() : mBy(1) {}
1475 Maybe<int> operator()(BasicValue& aValue) {
1476 aValue.SetTag(aValue.GetTag() + mBy.GetTag());
1477 return Some(aValue.GetTag());
1480 BasicValue mBy;
1483 struct AccessValueAndReturnOtherFunctor {
1484 explicit AccessValueAndReturnOtherFunctor(int aVal) : mBy(aVal) {}
1486 Maybe<BasicValue> operator()() {
1487 gFunctionWasApplied = true;
1488 return Some(mBy);
1491 BasicValue mBy;
1494 static bool TestAndThen() {
1495 // Check that andThen handles the 'Nothing' case.
1496 gFunctionWasApplied = false;
1497 Maybe<BasicValue> mayValue;
1498 Maybe<int> otherValue = mayValue.andThen(&AccessValueAndReturnOther);
1499 MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
1500 MOZ_RELEASE_ASSERT(otherValue.isNothing());
1502 // Check that andThen handles the 'Some' case.
1503 mayValue = Some(BasicValue(1));
1504 otherValue = mayValue.andThen(&AccessValueAndReturnNothing);
1505 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
1506 MOZ_RELEASE_ASSERT(otherValue.isNothing());
1507 gFunctionWasApplied = false;
1508 otherValue = mayValue.andThen(&IncrementAndReturnTag);
1509 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
1510 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
1511 MOZ_RELEASE_ASSERT(*otherValue == 2);
1512 gFunctionWasApplied = false;
1513 otherValue = mayValue.andThen(&AccessValueAndReturnOther);
1514 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
1515 MOZ_RELEASE_ASSERT(*otherValue == 42);
1517 // Check that andThen works with a const reference.
1518 const Maybe<BasicValue>& mayValueCRef = mayValue;
1519 gFunctionWasApplied = false;
1520 otherValue = mayValueCRef.andThen(&AccessValueAndReturnOther);
1521 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
1522 MOZ_RELEASE_ASSERT(*otherValue == 42);
1524 // Check that andThen works with functors.
1525 IncrementAndReturnTagFunctor tagIncrementer;
1526 MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
1527 mayValue = Some(BasicValue(1));
1528 otherValue = mayValue.andThen(tagIncrementer);
1529 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 2);
1530 MOZ_RELEASE_ASSERT(*otherValue == 2);
1531 MOZ_RELEASE_ASSERT(tagIncrementer.mBy.GetStatus() == eWasConstructed);
1533 // Check that andThen works with lambda expressions.
1534 gFunctionWasApplied = false;
1535 mayValue = Some(BasicValue(2));
1536 otherValue = mayValue.andThen(
1537 [](BasicValue& aVal) { return Some(aVal.GetTag() * 2); });
1538 MOZ_RELEASE_ASSERT(*otherValue == 4);
1539 otherValue = otherValue.andThen([](int aVal) { return Some(aVal * 2); });
1540 MOZ_RELEASE_ASSERT(*otherValue == 8);
1541 otherValue = mayValueCRef.andThen([&](const BasicValue& aVal) {
1542 gFunctionWasApplied = true;
1543 return Some(42);
1545 MOZ_RELEASE_ASSERT(gFunctionWasApplied == true);
1546 MOZ_RELEASE_ASSERT(*otherValue == 42);
1548 // Check that andThen can move the contained value.
1549 mayValue = Some(BasicValue(1));
1550 otherValue = std::move(mayValue).andThen([&](BasicValue&& aVal) {
1551 BasicValue tmp = std::move(aVal);
1552 return Some(tmp.GetTag());
1554 MOZ_RELEASE_ASSERT(mayValue.isNothing());
1555 MOZ_RELEASE_ASSERT(*otherValue == 1);
1557 return true;
1560 static bool TestOrElse() {
1561 const auto createValue = [&](int aTag) {
1562 return [&, aTag]() -> Maybe<BasicValue> {
1563 gFunctionWasApplied = true;
1564 return Some(BasicValue(aTag));
1567 // Check that orElse handles the 'Some' case.
1568 gFunctionWasApplied = false;
1569 Maybe<BasicValue> mayValue = Some(BasicValue(1));
1570 Maybe<BasicValue> otherValue = mayValue.orElse(createValue(2));
1571 MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
1572 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
1574 // Check that orElse handles the 'Nothing' case.
1575 mayValue = Nothing();
1576 otherValue = mayValue.orElse(createValue(1));
1577 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
1578 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
1579 gFunctionWasApplied = false;
1580 otherValue = otherValue.orElse(createValue(2));
1581 MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
1582 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
1584 // Check that orElse works with a const reference.
1585 mayValue = Nothing();
1586 const Maybe<BasicValue>& mayValueCRef = mayValue;
1587 gFunctionWasApplied = false;
1588 otherValue = mayValueCRef.orElse(createValue(1));
1589 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
1590 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
1592 // Check that orElse works with functors.
1593 gFunctionWasApplied = false;
1594 AccessValueAndReturnOtherFunctor accesser(42);
1595 mayValue = Some(BasicValue(1));
1596 otherValue = mayValue.orElse(accesser);
1597 MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
1598 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
1599 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
1600 mayValue = Nothing();
1601 otherValue = mayValue.orElse(accesser);
1602 MOZ_RELEASE_ASSERT(gFunctionWasApplied);
1603 MOZ_RELEASE_ASSERT(mayValue.isNothing());
1604 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 42);
1606 // Check that orElse works with lambda expressions.
1607 gFunctionWasApplied = false;
1608 mayValue = Nothing();
1609 otherValue = mayValue.orElse([] { return Some(BasicValue(1)); });
1610 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
1611 mayValue = otherValue.orElse([] { return Some(BasicValue(2)); });
1612 MOZ_RELEASE_ASSERT(mayValue->GetTag() == 1);
1613 otherValue = mayValueCRef.orElse([&] {
1614 gFunctionWasApplied = true;
1615 return Some(BasicValue(42));
1617 MOZ_RELEASE_ASSERT(!gFunctionWasApplied);
1618 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
1620 // Check that orElse can move the contained value.
1621 mayValue = Some(BasicValue(1));
1622 otherValue = std::move(mayValue).orElse([] { return Some(BasicValue(2)); });
1623 MOZ_RELEASE_ASSERT(mayValue.isNothing());
1624 MOZ_RELEASE_ASSERT(otherValue->GetTag() == 1);
1626 return true;
1629 static bool TestComposedMoves() {
1630 const auto moveAlong = [](UncopyableValue&& aValue) {
1631 return Some(std::move(aValue));
1633 const auto justNothing = []() -> Maybe<UncopyableValue> { return Nothing(); };
1634 const auto createValue = [] { return Some(UncopyableValue()); };
1636 // Check that andThen and orElse can propagate a non-copyable value created
1637 // mid-chain.
1638 Maybe<UncopyableValue> mayValue;
1639 Maybe<UncopyableValue> movedValue = std::move(mayValue)
1640 .andThen(moveAlong)
1641 .orElse(createValue)
1642 .andThen(moveAlong);
1643 MOZ_RELEASE_ASSERT(mayValue.isNothing());
1644 MOZ_RELEASE_ASSERT(movedValue->GetStatus() == eWasMoveConstructed);
1646 // Check that andThen and orElse can propagate a non-copyable value created
1647 // pre-chain.
1648 mayValue = Some(UncopyableValue{});
1649 movedValue = std::move(mayValue)
1650 .andThen(moveAlong)
1651 .orElse(justNothing)
1652 .andThen(moveAlong);
1653 MOZ_RELEASE_ASSERT(mayValue.isNothing());
1654 MOZ_RELEASE_ASSERT(movedValue->GetStatus() == eWasMoveAssigned);
1656 // Check that andThen and orElse can propagate a reference.
1658 UncopyableValue val{};
1659 UncopyableValue otherVal{};
1660 const auto passAlong = [](UncopyableValue& aValue) {
1661 return SomeRef(aValue);
1663 const auto fallbackToOther = [&]() { return SomeRef(otherVal); };
1665 Maybe<UncopyableValue&> mayRef = SomeRef(val);
1666 Maybe<UncopyableValue&> chainedRef =
1667 mayRef.andThen(passAlong).orElse(fallbackToOther).andThen(passAlong);
1668 MOZ_RELEASE_ASSERT(&val != &otherVal,
1669 "Distinct values should not compare equal");
1670 MOZ_RELEASE_ASSERT(&*mayRef == &*chainedRef,
1671 "Chain should pass along the same reference");
1674 // Check that andThen and orElse can propagate a const reference.
1676 const UncopyableValue val{};
1677 const UncopyableValue otherVal{};
1678 const auto passAlong = [](const UncopyableValue& aValue) {
1679 return SomeRef(aValue);
1681 const auto fallbackToOther = [&]() { return SomeRef(otherVal); };
1683 Maybe<const UncopyableValue&> mayRef = SomeRef(val);
1684 Maybe<const UncopyableValue&> chainedRef =
1685 mayRef.andThen(passAlong).orElse(fallbackToOther).andThen(passAlong);
1686 MOZ_RELEASE_ASSERT(&val != &otherVal,
1687 "Distinct values should not compare equal");
1688 MOZ_RELEASE_ASSERT(&*mayRef == &*chainedRef,
1689 "Chain should pass along the same reference");
1692 return true;
1695 // These are quasi-implementation details, but we assert them here to prevent
1696 // backsliding to earlier times when Maybe<T> for smaller T took up more space
1697 // than T's alignment required.
1699 static_assert(sizeof(Maybe<char>) == 2 * sizeof(char),
1700 "Maybe<char> shouldn't bloat at all ");
1701 static_assert(sizeof(Maybe<bool>) <= 2 * sizeof(bool),
1702 "Maybe<bool> shouldn't bloat");
1703 static_assert(sizeof(Maybe<int>) <= 2 * sizeof(int),
1704 "Maybe<int> shouldn't bloat");
1705 static_assert(sizeof(Maybe<long>) <= 2 * sizeof(long),
1706 "Maybe<long> shouldn't bloat");
1707 static_assert(sizeof(Maybe<double>) <= 2 * sizeof(double),
1708 "Maybe<double> shouldn't bloat");
1709 static_assert(sizeof(Maybe<int&>) == sizeof(int*));
1711 int main() {
1712 RUN_TEST(TestBasicFeatures);
1713 RUN_TEST(TestCopyAndMove);
1714 RUN_TEST(TestFunctionalAccessors);
1715 RUN_TEST(TestApply);
1716 RUN_TEST(TestMap);
1717 RUN_TEST(TestToMaybe);
1718 RUN_TEST(TestComparisonOperators);
1719 RUN_TEST(TestVirtualFunction);
1720 RUN_TEST(TestSomeNullptrConversion);
1721 RUN_TEST(TestSomePointerConversion);
1722 RUN_TEST(TestTypeConversion);
1723 RUN_TEST(TestReference);
1724 RUN_TEST(TestAndThen);
1725 RUN_TEST(TestOrElse);
1726 RUN_TEST(TestComposedMoves);
1728 return 0;