dlib C++ Library - optional.cpp

// Copyright (C) 2023 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#include <dlib/optional.h>
#include "tester.h"
namespace 
{
 using namespace test;
 using namespace dlib;
 logger dlog("test.optional");
// ---------------------------------------------------------------------------------------------------
 static_assert(std::is_copy_constructible<dlib::optional<int>>::value, "bad");
 static_assert(std::is_copy_assignable<dlib::optional<int>>::value, "bad");
 static_assert(std::is_move_constructible<dlib::optional<int>>::value, "bad");
 static_assert(std::is_move_assignable<dlib::optional<int>>::value, "bad");
 static_assert(std::is_destructible<dlib::optional<int>>::value, "bad");
 static_assert(std::is_trivially_copy_constructible<dlib::optional<int>>::value, "bad");
 static_assert(std::is_trivially_copy_assignable<dlib::optional<int>>::value, "bad");
 static_assert(std::is_trivially_move_constructible<dlib::optional<int>>::value, "bad");
 static_assert(std::is_trivially_move_assignable<dlib::optional<int>>::value, "bad");
 static_assert(std::is_trivially_destructible<dlib::optional<int>>::value, "bad");
 static_assert(std::is_nothrow_copy_constructible<dlib::optional<int>>::value, "bad");
 static_assert(std::is_nothrow_copy_assignable<dlib::optional<int>>::value, "bad");
 static_assert(std::is_nothrow_move_constructible<dlib::optional<int>>::value, "bad");
 static_assert(std::is_nothrow_move_assignable<dlib::optional<int>>::value, "bad");
 static_assert(std::is_nothrow_destructible<dlib::optional<int>>::value, "bad");
 struct trivial_type 
 {
 trivial_type(const trivial_type&) = default;
 trivial_type(trivial_type&&) = default;
 trivial_type& operator=(const trivial_type&) = default;
 trivial_type& operator=(trivial_type&&) = default;
 ~trivial_type() = default;
 };
 static_assert(std::is_copy_constructible<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_copy_assignable<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_move_constructible<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_move_assignable<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_destructible<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_trivially_copy_constructible<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_trivially_copy_assignable<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_trivially_move_constructible<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_trivially_move_assignable<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_trivially_destructible<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_nothrow_copy_constructible<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_nothrow_copy_assignable<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_nothrow_move_constructible<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_nothrow_move_assignable<dlib::optional<trivial_type>>::value, "bad");
 static_assert(std::is_nothrow_destructible<dlib::optional<trivial_type>>::value, "bad");
 struct non_trivial_type
 {
 non_trivial_type(const non_trivial_type&) {}
 non_trivial_type(non_trivial_type&&) {};
 non_trivial_type& operator=(const non_trivial_type&) { return *this; }
 non_trivial_type& operator=(non_trivial_type&&) { return *this; };
 ~non_trivial_type() {}
 };
 static_assert(std::is_copy_constructible<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(std::is_copy_assignable<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(std::is_move_constructible<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(std::is_move_assignable<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(std::is_destructible<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_trivially_copy_constructible<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_trivially_copy_assignable<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_trivially_move_constructible<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_trivially_move_assignable<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_trivially_destructible<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_nothrow_copy_constructible<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_nothrow_copy_assignable<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_nothrow_move_constructible<dlib::optional<non_trivial_type>>::value, "bad");
 static_assert(!std::is_nothrow_move_assignable<dlib::optional<non_trivial_type>>::value, "bad");
 struct nothing_works
 {
 nothing_works(const nothing_works&) = delete;
 nothing_works(nothing_works&&) = delete;
 nothing_works& operator=(const nothing_works&) = delete;
 nothing_works& operator=(nothing_works&&) = delete;
 };
 static_assert(!std::is_copy_constructible<dlib::optional<nothing_works>>::value, "bad");
 static_assert(!std::is_copy_assignable<dlib::optional<nothing_works>>::value, "bad");
 static_assert(!std::is_move_constructible<dlib::optional<nothing_works>>::value, "bad");
 static_assert(!std::is_move_assignable<dlib::optional<nothing_works>>::value, "bad");
 struct copyable_type 
 {
 copyable_type(const copyable_type&) = default;
 copyable_type(copyable_type&&) = delete;
 copyable_type& operator=(const copyable_type&) = default;
 copyable_type& operator=(copyable_type&&) = delete;
 };
 static_assert(std::is_copy_constructible<dlib::optional<copyable_type>>::value, "bad");
 static_assert(std::is_copy_assignable<dlib::optional<copyable_type>>::value, "bad");
 //copyable_type can still be moved, but it will just copy.
 struct moveable_type 
 {
 moveable_type(const moveable_type&) = delete;
 moveable_type(moveable_type&&) = default;
 moveable_type& operator=(const moveable_type&) = delete;
 moveable_type& operator=(moveable_type&&) = default;
 };
 static_assert(!std::is_copy_constructible<dlib::optional<moveable_type>>::value, "bad");
 static_assert(!std::is_copy_assignable<dlib::optional<moveable_type>>::value, "bad");
 static_assert(std::is_move_constructible<dlib::optional<moveable_type>>::value, "bad");
 static_assert(std::is_move_assignable<dlib::optional<moveable_type>>::value, "bad");
// ---------------------------------------------------------------------------------------------------
 void test_optional_int()
 {
 dlib::optional<int> o1;
 DLIB_TEST(!o1);
 DLIB_TEST(!o1.has_value());
 DLIB_TEST(o1.value_or(2) == 2);
 int throw_counter{0};
 try {
 o1.value();
 } catch(const std::exception& e) {
 throw_counter++;
 }
 DLIB_TEST(throw_counter == 1);
 DLIB_TEST(o1 == dlib::nullopt);
 dlib::optional<int> o2 = dlib::nullopt;
 static_assert(noexcept(o2 = dlib::nullopt), "bad");
 DLIB_TEST(!o2);
 DLIB_TEST(!o2.has_value());
 DLIB_TEST(o2.value_or(3) == 3);
 dlib::optional<int> o3 = 42;
 DLIB_TEST(*o3 == 42);
 DLIB_TEST(o3.value() == 42);
 DLIB_TEST(o3.value_or(3) == 42);
 DLIB_TEST(o3 == 42);
 DLIB_TEST(42 == o3);
 dlib::optional<int> o4 = o3;
 static_assert(noexcept(o4 = o3), "bad");
 DLIB_TEST(*o3 == 42);
 DLIB_TEST(*o4 == 42);
 DLIB_TEST(o4 == 42);
 DLIB_TEST(42 == o4);
 DLIB_TEST(o4.value() == 42);
 dlib::optional<int> o5 = o1;
 static_assert(noexcept(o5 = o1), "bad");
 DLIB_TEST(!o1);
 DLIB_TEST(!o5);
 DLIB_TEST(!o5.has_value());
 dlib::optional<int> o6 = std::move(o3);
 static_assert(noexcept(o6 = std::move(o3)), "bad");
 DLIB_TEST(*o6 == 42);
 DLIB_TEST(o6.value() == 42);
 dlib::optional<short> o7 = (short)42;
 static_assert(noexcept(o7 = (short)42), "bad");
 DLIB_TEST(*o7 == 42);
 dlib::optional<int> o8 = o7;
 DLIB_TEST(*o7 == 42);
 DLIB_TEST(*o8 == 42);
 dlib::optional<int> o9 = std::move(o7);
 DLIB_TEST(*o9 == 42);
 dlib::optional<int> o10;
 DLIB_TEST(!o10);
 o10 = o3;
 DLIB_TEST(*o10 == 42);
 o10 = dlib::nullopt;
 DLIB_TEST(!o10);
 dlib::optional<int> o11;
 o11 = std::move(o3);
 DLIB_TEST(*o11 == 42);
 o11 = (short)12;
 DLIB_TEST(*o11 == 12);
 dlib::optional<int> o12;
 swap(o12, o4);
 DLIB_TEST(o12);
 DLIB_TEST(!o4);
 DLIB_TEST(*o12 == 42);
 static_assert(noexcept(swap(o12, o4)), "bad");
 o4.reset();
 DLIB_TEST(!o4);
 }
// ---------------------------------------------------------------------------------------------------
 void test_optional_int_constexpr()
 {
 {
 constexpr dlib::optional<int> o2{};
 constexpr dlib::optional<int> o3 = {};
 constexpr dlib::optional<int> o4 = dlib::nullopt;
 constexpr dlib::optional<int> o5 = {dlib::nullopt};
 constexpr dlib::optional<int> o6(dlib::nullopt);
 static_assert(!o2, "bad");
 static_assert(!o3, "bad");
 static_assert(!o4, "bad");
 static_assert(!o5, "bad");
 static_assert(!o6, "bad");
 static_assert(o2.value_or(1) == 1, "bad");
 static_assert(o3.value_or(1) == 1, "bad");
 static_assert(o4.value_or(1) == 1, "bad");
 static_assert(o5.value_or(1) == 1, "bad");
 static_assert(o6.value_or(1) == 1, "bad");
 static_assert(o2 != 1, "bad");
 static_assert(1 != o2, "bad");
 }
 }
// ---------------------------------------------------------------------------------------------------
 void test_optional_int_monads()
 {
 dlib::optional<int> o1{42};
 {
 auto res = o1.and_then([](int i) { return dlib::optional<long>(i); });
 static_assert(std::is_same<decltype(res), dlib::optional<long>>::value, "bad map");
 DLIB_TEST(*res == 42);
 }
 {
 auto res = o1.transform([](int i) { return (long)i; });
 static_assert(std::is_same<decltype(res), dlib::optional<long>>::value, "bad map");
 DLIB_TEST(*res == 42);
 }
 {
 auto res = o1.and_then([](int i) { return dlib::optional<std::string>(std::to_string(i)); });
 static_assert(std::is_same<decltype(res), dlib::optional<std::string>>::value, "bad map");
 DLIB_TEST(*res == "42");
 }
 {
 auto res = o1.transform([](int i) { return std::to_string(i); });
 static_assert(std::is_same<decltype(res), dlib::optional<std::string>>::value, "bad map");
 DLIB_TEST(*res == "42");
 }
 {
 auto res = o1.transform([](int i) {return i+1;})
 .transform([](int i) {return i*2;})
 .transform([](int i) {return std::to_string(i);})
 .transform([](const std::string& str) {return std::stoi(str);})
 .transform([](int i) {return i - 2;})
 .or_else([] {return dlib::make_optional<int>(0);});
 static_assert(std::is_same<decltype(res), dlib::optional<int>>::value, "bad map");
 DLIB_TEST(*res == 84);
 }
 dlib::optional<int> o2;
 {
 auto res = o2.transform([](int i) {return i+1;})
 .or_else([] {return dlib::make_optional<int>(0);});
 static_assert(std::is_same<decltype(res), dlib::optional<int>>::value, "bad map");
 DLIB_TEST(*res == 0);
 }
 }
// ---------------------------------------------------------------------------------------------------
 void test_optional_int_constexpr_monads()
 {
 constexpr dlib::optional<int> o1{42};
 {
 struct callback
 {
 constexpr auto operator()(int i) {return dlib::optional<long>{i}; };
 };
 constexpr auto res = o1.and_then(callback{});
 static_assert(std::is_same<std::decay_t<decltype(res)>, dlib::optional<long>>::value, "bad map");
 static_assert(*res == 42, "bad");
 DLIB_TEST(*res == 42);
 }
 }
// ---------------------------------------------------------------------------------------------------
 static int constructor_count{0};
 static int copy_constructor_count{0};
 static int move_constructor_count{0};
 static int copy_assign_count{0};
 static int move_assign_count{0};
 static void reset_counters()
 {
 constructor_count = 0;
 copy_constructor_count = 0;
 move_constructor_count = 0;
 copy_assign_count = 0;
 move_assign_count = 0;
 }
 struct optional_dummy
 {
 optional_dummy() {++constructor_count;}
 optional_dummy(const optional_dummy&) {++copy_constructor_count;}
 optional_dummy(optional_dummy&&) {++move_constructor_count;}
 optional_dummy& operator=(const optional_dummy&) {++copy_assign_count; return *this;}
 optional_dummy& operator=(optional_dummy&&) {++move_assign_count; return *this;}
 };
 void test_constructors()
 {
 dlib::optional<optional_dummy> val;
 DLIB_TEST(constructor_count == 0);
 DLIB_TEST(copy_constructor_count == 0);
 DLIB_TEST(move_constructor_count == 0);
 DLIB_TEST(copy_assign_count == 0);
 DLIB_TEST(move_assign_count == 0);
 val = optional_dummy{};
 DLIB_TEST(constructor_count == 1);
 DLIB_TEST(copy_constructor_count == 0);
 DLIB_TEST(move_constructor_count == 1);
 DLIB_TEST(copy_assign_count == 0);
 DLIB_TEST(move_assign_count == 0);
 reset_counters();
 dlib::optional<optional_dummy> val2{val};
 DLIB_TEST(constructor_count == 0);
 DLIB_TEST(copy_constructor_count == 1);
 DLIB_TEST(move_constructor_count == 0);
 DLIB_TEST(copy_assign_count == 0);
 DLIB_TEST(move_assign_count == 0);
 reset_counters();
 dlib::optional<optional_dummy> val3{std::move(val)};
 DLIB_TEST(constructor_count == 0);
 DLIB_TEST(copy_constructor_count == 0);
 DLIB_TEST(move_constructor_count == 1);
 DLIB_TEST(copy_assign_count == 0);
 DLIB_TEST(move_assign_count == 0);
 reset_counters();
 val2 = val;
 DLIB_TEST(constructor_count == 0);
 DLIB_TEST(copy_constructor_count == 0);
 DLIB_TEST(move_constructor_count == 0);
 DLIB_TEST(copy_assign_count == 1);
 DLIB_TEST(move_assign_count == 0);
 reset_counters();
 val3 = std::move(val);
 DLIB_TEST(constructor_count == 0);
 DLIB_TEST(copy_constructor_count == 0);
 DLIB_TEST(move_constructor_count == 0);
 DLIB_TEST(copy_assign_count == 0);
 DLIB_TEST(move_assign_count == 1);
 reset_counters();
 }
// ---------------------------------------------------------------------------------------------------
 void test_emplace()
 {
 struct A
 {
 A() = default;
 explicit A(int i, float f, const std::string& str) : i_{i}, f_{f}, str_{str} {}
 int i_{0};
 float f_{0.0f};
 std::string str_;
 };
 dlib::optional<A> o1(dlib::in_place, 1, 2.5f, "hello there");
 DLIB_TEST(o1);
 DLIB_TEST(o1->i_ == 1);
 DLIB_TEST(o1->f_ == 2.5f);
 DLIB_TEST(o1->str_ == "hello there");
 dlib::optional<A> o2;
 o2.emplace(2, 5.1f, "general kenobi");
 DLIB_TEST(o2);
 DLIB_TEST(o2->i_ == 2);
 DLIB_TEST(o2->f_ == 5.1f);
 DLIB_TEST(o2->str_ == "general kenobi");
 auto o3 = dlib::make_optional<A>(3, 3.141592f, "from a certain point of view");
 DLIB_TEST(o3);
 DLIB_TEST(o3->i_ == 3);
 DLIB_TEST(o3->f_ == 3.141592f);
 DLIB_TEST(o3->str_ == "from a certain point of view");
 dlib::optional<std::string> o4(dlib::in_place, {'a', 'b', 'c'});
 DLIB_TEST(o4);
 DLIB_TEST(*o4 == "abc");
 DLIB_TEST(o4 == "abc");
 dlib::optional<std::string> o5;
 o5.emplace({'a', 'b', 'c'});
 DLIB_TEST(o5);
 DLIB_TEST(*o5 == "abc");
 }
// ---------------------------------------------------------------------------------------------------
 void test_make_optional()
 {
 constexpr auto o1 = dlib::make_optional(1);
 static_assert(std::is_same<std::decay_t<decltype(o1)>, dlib::optional<int>>::value, "bad");
 static_assert(o1 == 1, "bad");
 static_assert(1 == o1, "bad");
 }
 class optional_tester : public tester
 {
 public:
 optional_tester (
 ) :
 tester ("test_optional",
 "Runs tests on the optional object")
 {}
 void perform_test (
 )
 {
 test_optional_int();
 test_optional_int_constexpr();
 test_optional_int_monads();
 test_optional_int_constexpr_monads();
 test_constructors();
 test_emplace();
 test_make_optional();
 }
 } a;
}

AltStyle によって変換されたページ (->オリジナル) /