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/. */
9 #include "mozilla/Assertions.h"
10 #include "mozilla/Attributes.h"
11 #include "mozilla/Maybe.h"
14 using mozilla::Nothing
;
16 using mozilla::SomeRef
;
17 using mozilla::ToMaybe
;
18 using mozilla::ToMaybeRef
;
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; \
30 eWasDefaultConstructed
,
34 eWasConstMoveConstructed
,
43 static size_t sUndestroyedObjects
= 0;
45 static bool AllDestructorsWereCalled() { return sUndestroyedObjects
== 0; }
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
;
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
;
82 BasicValue
& operator=(BasicValue
&& aOther
) {
83 mStatus
= eWasMoveAssigned
;
85 aOther
.mStatus
= eWasMovedFrom
;
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
; }
101 mutable Status mStatus
;
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
;
121 Status
GetStatus() { return mStatus
; }
124 UncopyableValue(const UncopyableValue
& aOther
) = delete;
125 UncopyableValue
& operator=(const UncopyableValue
& aOther
) = delete;
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
;
144 Status
GetStatus() { return mStatus
; }
146 UnmovableValue(UnmovableValue
&& aOther
) = delete;
147 UnmovableValue
& operator=(UnmovableValue
&& aOther
) = delete;
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
; }
167 UncopyableUnmovableValue(const UncopyableUnmovableValue
& aOther
) = delete;
168 UncopyableUnmovableValue
& operator=(const UncopyableUnmovableValue
& aOther
) =
170 UncopyableUnmovableValue(UncopyableUnmovableValue
&& aOther
) = delete;
171 UncopyableUnmovableValue
& operator=(UncopyableUnmovableValue
&& aOther
) =
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) == [] {
188 val
.apply([](int& val
) { val
+= 1; });
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
) {
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;
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});
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.
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.
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.
269 MOZ_RELEASE_ASSERT(mayValue
);
270 MOZ_RELEASE_ASSERT(mayValue
->GetStatus() == eWasConstructed
);
271 MOZ_RELEASE_ASSERT(mayValue
->GetTag() == 1);
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.
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
);
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());
335 std::is_same_v
<BasicValue
, decltype(Some(BasicValue()).value())>,
336 "value() should return a BasicValue");
337 MOZ_RELEASE_ASSERT(Some(BasicValue()).ref() == BasicValue());
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());
361 std::is_same_v
<const BasicValue
&&, decltype(MakeConstMaybe().ref())>,
362 "ref() should return a const BasicValue&&");
363 MOZ_RELEASE_ASSERT(MakeConstMaybe().ptr() != nullptr);
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());
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
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() ==
578 mayUncopyableUnmovableValue
= Nothing();
581 !std::is_copy_constructible_v
<Maybe
<UncopyableUnmovableValue
>>);
582 static_assert(!std::is_copy_assignable_v
<Maybe
<UncopyableUnmovableValue
>>);
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
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
);
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() {
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));
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));
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));
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));
679 std::is_same_v
<BasicValue
, decltype(someValueCRef
.valueOr(value
))>,
680 "valueOr should return a BasicValue");
681 MOZ_RELEASE_ASSERT(someValueCRef
.valueOrFrom(&MakeBasicValue
) ==
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
);
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
) ==
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));
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
) ==
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));
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));
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));
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));
739 std::is_same_v
<BasicValue
, decltype(noneValueCRef
.valueOr(value
))>,
740 "valueOr should return a BasicValue");
741 MOZ_RELEASE_ASSERT(noneValueCRef
.valueOrFrom(&MakeBasicValue
) ==
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
);
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
) ==
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));
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
) ==
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;
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());
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.
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);
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
);
849 static int TimesTwo(const BasicValue
& aValue
) { return aValue
.GetTag() * 2; }
851 static int TimesTwoAndResetOriginal(BasicValue
& aValue
) {
852 int tag
= aValue
.GetTag();
857 struct MultiplyTagFunctor
{
858 MultiplyTagFunctor() : mBy(2) {}
860 int operator()(BasicValue
& aValue
) { return aValue
.GetTag() * mBy
.GetTag(); }
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.
882 const Maybe
<BasicValue
>& mayValueCRef
= mayValue
;
883 MOZ_RELEASE_ASSERT(mayValueCRef
.map(&TimesTwo
) == Some(4));
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.
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));
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.
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);
925 static_assert(std::is_same
<decltype(mi
.map(f
)),
926 Maybe
<std::integral_constant
<int, 1>>>::value
,
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);
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
,
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);
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);
963 static bool TestToMaybe() {
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
);
979 std::is_same_v
<Maybe
<BasicValue
>, decltype(ToMaybe(nullPointer
))>,
980 "ToMaybe should return a Maybe<BasicValue>");
981 MOZ_RELEASE_ASSERT(mayValue
.isNothing());
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));
994 MOZ_RELEASE_ASSERT(nothingValue
== anotherNothingValue
);
995 MOZ_RELEASE_ASSERT(oneValue
== anotherOneValue
);
998 MOZ_RELEASE_ASSERT(nothingValue
!= oneValue
);
999 MOZ_RELEASE_ASSERT(oneValue
!= nothingValue
);
1000 MOZ_RELEASE_ASSERT(oneValue
!= twoValue
);
1003 MOZ_RELEASE_ASSERT(nothingValue
< oneValue
);
1004 MOZ_RELEASE_ASSERT(oneValue
< twoValue
);
1007 MOZ_RELEASE_ASSERT(nothingValue
<= anotherNothingValue
);
1008 MOZ_RELEASE_ASSERT(nothingValue
<= oneValue
);
1009 MOZ_RELEASE_ASSERT(oneValue
<= oneValue
);
1010 MOZ_RELEASE_ASSERT(oneValue
<= twoValue
);
1013 MOZ_RELEASE_ASSERT(oneValue
> nothingValue
);
1014 MOZ_RELEASE_ASSERT(twoValue
> oneValue
);
1017 MOZ_RELEASE_ASSERT(nothingValue
>= anotherNothingValue
);
1018 MOZ_RELEASE_ASSERT(oneValue
>= nothingValue
);
1019 MOZ_RELEASE_ASSERT(oneValue
>= oneValue
);
1020 MOZ_RELEASE_ASSERT(twoValue
>= oneValue
);
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
;
1043 Maybe
<MyDerivedClass
> derived
;
1047 // If this compiles successfully, we've passed.
1051 static Maybe
<int*> ReturnSomeNullptr() { return Some(nullptr); }
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);
1079 struct Derived
: Base
{};
1081 static Maybe
<Base
*> ReturnDerivedPointer() {
1082 Derived
* d
= nullptr;
1086 struct ExplicitConstructorBasePointer
{
1087 explicit ExplicitConstructorBasePointer(const Maybe
<Base
*>&) {}
1090 static bool TestSomePointerConversion() {
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
));
1120 struct SourceType1
{
1123 operator int() const { return mTag
; }
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
) {
1141 mStatus
= eWasAssigned
;
1145 DestType
& operator=(SourceType1
&& aSrc
) {
1147 mStatus
= eWasMoveAssigned
;
1151 DestType
& operator=(const SourceType1
& aSrc
) {
1153 mStatus
= eWasCopyAssigned
;
1157 struct SourceType2
{
1160 operator DestType() const& {
1163 result
.mStatus
= eWasCopiedFrom
;
1167 operator DestType() && {
1170 result
.mStatus
= eWasMovedFrom
;
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});
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});
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
);
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
);
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});
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);
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);
1303 dest
= std::move(src
);
1304 MOZ_RELEASE_ASSERT(src
.isNothing());
1305 MOZ_RELEASE_ASSERT(dest
.isSome() && *dest
== 2);
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
)));
1351 MOZ_RELEASE_ASSERT(43 == foo
);
1354 MOZ_RELEASE_ASSERT(44 == foo
);
1358 int foo
= 42, bar
= 42;
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
)));
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
);
1388 Maybe
<int&> some
= SomeRef(foo
);
1391 MOZ_RELEASE_ASSERT(some
.isNothing());
1392 MOZ_RELEASE_ASSERT(!some
.isSome());
1393 MOZ_RELEASE_ASSERT(!some
);
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(¬hing
== &applied
);
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
);
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());
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;
1467 static Maybe
<int> AccessValueAndReturnOther(const BasicValue
&) {
1468 gFunctionWasApplied
= true;
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());
1483 struct AccessValueAndReturnOtherFunctor
{
1484 explicit AccessValueAndReturnOtherFunctor(int aVal
) : mBy(aVal
) {}
1486 Maybe
<BasicValue
> operator()() {
1487 gFunctionWasApplied
= true;
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;
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);
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);
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
1638 Maybe
<UncopyableValue
> mayValue
;
1639 Maybe
<UncopyableValue
> movedValue
= std::move(mayValue
)
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
1648 mayValue
= Some(UncopyableValue
{});
1649 movedValue
= std::move(mayValue
)
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");
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*));
1712 RUN_TEST(TestBasicFeatures
);
1713 RUN_TEST(TestCopyAndMove
);
1714 RUN_TEST(TestFunctionalAccessors
);
1715 RUN_TEST(TestApply
);
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
);