├── .gitattributes ├── tests ├── nullopt.cpp ├── test_util.hpp ├── emplace.cpp ├── in_place.cpp ├── observers.cpp ├── test_workarounds.h ├── specialized_alg.cpp ├── constexpr_op.cpp ├── constructors.cpp ├── assignment.hpp ├── hash.cpp ├── noexcept_trait.cpp ├── relops.cpp ├── sfm_traits.cpp ├── archetypes.ipp ├── swap.cpp ├── test_macros.h └── archetypes.h ├── CMakeLists.txt ├── LICENSE ├── README.md └── include └── swl └── optional.hpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /tests/nullopt.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | 3 | int main() { 4 | swl::optional o1 = swl::nullopt; 5 | swl::optional o2{swl::nullopt}; 6 | swl::optional o3(swl::nullopt); 7 | swl::optional o4 = {swl::nullopt}; 8 | 9 | assert(!o1); 10 | assert(!o2); 11 | assert(!o3); 12 | assert(!o4); 13 | } 14 | -------------------------------------------------------------------------------- /tests/test_util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct takes_init_and_variadic { 8 | std::vector v; 9 | std::tuple t; 10 | template 11 | takes_init_and_variadic(std::initializer_list l, Args &&... args) 12 | : v(l), t(std::forward(args)...) {} 13 | }; -------------------------------------------------------------------------------- /tests/emplace.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | int main(){ 7 | swl::optional, std::pair>> i; 8 | i.emplace(std::piecewise_construct, std::make_tuple(0,2), std::make_tuple(3,4)); 9 | assert(i->first.first == 0); 10 | assert(i->first.second == 2); 11 | assert(i->second.first == 3); 12 | assert(i->second.second == 4); 13 | } 14 | -------------------------------------------------------------------------------- /tests/in_place.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "test_util.hpp" 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | swl::optional o1{swl::in_place}; 10 | swl::optional o2(swl::in_place); 11 | assert(o1); 12 | assert(o1 == 0); 13 | assert(o2); 14 | assert(o2 == 0); 15 | 16 | swl::optional o3(swl::in_place, 42); 17 | assert(o3 == 42); 18 | 19 | swl::optional> o4(swl::in_place, 0, 1); 20 | assert(o4); 21 | assert(std::get<0>(*o4) == 0); 22 | assert(std::get<1>(*o4) == 1); 23 | 24 | swl::optional> o5(swl::in_place, {0, 1}); 25 | assert(o5); 26 | assert((*o5)[0] == 0); 27 | assert((*o5)[1] == 1); 28 | 29 | swl::optional o6(swl::in_place, {0, 1}, 2, 3); 30 | assert(o6->v[0] == 0); 31 | assert(o6->v[1] == 1); 32 | assert(std::get<0>(o6->t) == 2); 33 | assert(std::get<1>(o6->t) == 3); 34 | } 35 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | project(swl.optional 4 | VERSION 1.0.0 5 | LANGUAGES CXX 6 | HOMEPAGE_URL https://github.com/groundswellaudio/swl-optional) 7 | 8 | add_library(swl-optional INTERFACE) 9 | 10 | target_include_directories(swl-optional INTERFACE 11 | $ 12 | $) 13 | 14 | target_compile_features(swl-optional INTERFACE cxx_std_20) 15 | 16 | 17 | 18 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) 19 | 20 | include(CTest) 21 | 22 | file(GLOB test-sources CONFIGURE_DEPENDS tests/*.cpp) 23 | 24 | foreach (source IN LISTS test-sources) 25 | get_filename_component(name "${source}" NAME_WE) 26 | set(test "${PROJECT_NAME}-test-${name}") 27 | add_executable(${test} "${source}") 28 | target_link_libraries(${test} swl-optional) 29 | add_test(NAME ${PROJECT_NAME}::test::${name} COMMAND ${test}) 30 | endforeach() 31 | 32 | endif() 33 | 34 | -------------------------------------------------------------------------------- /tests/observers.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | 3 | struct move_detector { 4 | move_detector() = default; 5 | move_detector(move_detector &&rhs) { rhs.been_moved = true; } 6 | bool been_moved = false; 7 | }; 8 | 9 | int main() { 10 | swl::optional o1 = 42; 11 | swl::optional o2; 12 | const swl::optional o3 = 42; 13 | 14 | assert(*o1 == 42); 15 | assert(*o1 == o1.value()); 16 | assert(o2.value_or(42) == 42); 17 | assert(o3.value() == 42); 18 | auto success = std::is_same::value; 19 | assert(success); 20 | success = std::is_same::value; 21 | assert(success); 22 | success = std::is_same::value; 23 | assert(success); 24 | 25 | success = std::is_same::value; 26 | assert(success); 27 | 28 | swl::optional o4{swl::in_place}; 29 | move_detector o5 = std::move(o4).value(); 30 | assert(o4->been_moved); 31 | assert(!o5.been_moved); 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 groundswellaudio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_workarounds.h: -------------------------------------------------------------------------------- 1 | // -*- C++ -*- 2 | //===----------------------------------------------------------------------===// 3 | // 4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 | // See https://llvm.org/LICENSE.txt for license information. 6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 | // 8 | //===----------------------------------------------------------------------===// 9 | 10 | #ifndef SUPPORT_TEST_WORKAROUNDS_H 11 | #define SUPPORT_TEST_WORKAROUNDS_H 12 | 13 | #include "test_macros.h" 14 | 15 | #if defined(TEST_COMPILER_EDG) 16 | # define TEST_WORKAROUND_EDG_EXPLICIT_CONSTEXPR // VSO-424280 17 | #endif 18 | 19 | #if defined(TEST_COMPILER_C1XX) 20 | # if _MSC_VER < 1927 21 | # define TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE // VSO-117743 22 | # endif 23 | # ifndef _MSC_EXTENSIONS 24 | # define TEST_WORKAROUND_C1XX_BROKEN_ZA_CTOR_CHECK // VSO-119998 25 | # endif 26 | #endif 27 | 28 | #if defined(TEST_COMPILER_GCC) 29 | # if __GNUC__ < 9 30 | # define TEST_WORKAROUND_CONSTEXPR_IMPLIES_NOEXCEPT // GCC-87603 31 | # endif 32 | #endif 33 | 34 | #endif // SUPPORT_TEST_WORKAROUNDS_H 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swl::optional 2 | A standard conforming C++20 implementation of `std::optional`. 3 | 4 | C++20 came with new features that makes the implementation of `std::optional` 5 | (and other types based on unions) a lot simpler to write, faster to compile, and more debugger-friendly 6 | (ever crawled through all the `std::optional` base classes in your IDE debugger?). \ 7 | So if you're using `optional`a lot in C++20, switching to this implementation is free cookies. 8 | 9 | ## Testing 10 | The tests were adapted from [TartanLlama's optional](https://github.com/TartanLlama/optional) 11 | with some bits from the LLVM repo. Kudos to them. \ 12 | To run the tests : \ 13 | `mkdir ./test_out` \ 14 | `cd test_out` \ 15 | `cmake ../` \ 16 | `ctest --build-and-test ../ ./ --build-generator "Unix Makefiles"` (replace "Unix Makefiles" as needed) \ 17 | `make test` 18 | 19 | ## Tested compilers 20 | - GCC 11+ 21 | - GCC 10+ (the early 10.X versions have a bug in `std::construct_at`, which prevent to use it in a constexpr context, hence the tests might not compile) 22 | - Clang will not fully work as its implementation of C++20 is still incomplete (Clang 12+ will work for trivially destructible type) 23 | -------------------------------------------------------------------------------- /tests/specialized_alg.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | auto o1 = swl::make_optional(42); 8 | auto o2 = swl::optional(42); 9 | 10 | constexpr bool is_same = std::is_same>::value; 11 | assert(is_same); 12 | assert(o1 == o2); 13 | 14 | auto o3 = swl::make_optional>(0, 1, 2, 3); 15 | assert(std::get<0>(*o3) == 0); 16 | assert(std::get<1>(*o3) == 1); 17 | assert(std::get<2>(*o3) == 2); 18 | assert(std::get<3>(*o3) == 3); 19 | 20 | auto o4 = swl::make_optional>({0, 1, 2, 3}); 21 | assert(o4.value()[0] == 0); 22 | assert(o4.value()[1] == 1); 23 | assert(o4.value()[2] == 2); 24 | assert(o4.value()[3] == 3); 25 | 26 | auto o5 = swl::make_optional({0, 1}, 2, 3); 27 | assert(o5->v[0] == 0); 28 | assert(o5->v[1] == 1); 29 | assert(std::get<0>(o5->t) == 2); 30 | assert(std::get<1>(o5->t) == 3); 31 | 32 | /* 33 | auto i = 42; 34 | auto o6 = swl::make_optional(i); 35 | assert((std::is_same>::value)); 36 | assert(o6); 37 | assert(*o6 == 42); */ 38 | } 39 | -------------------------------------------------------------------------------- /tests/constexpr_op.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | 3 | int main(){ 4 | { 5 | constexpr swl::optional o2{}; 6 | constexpr swl::optional o3 = {}; 7 | constexpr swl::optional o4 = swl::nullopt; 8 | constexpr swl::optional o5 = {swl::nullopt}; 9 | constexpr swl::optional o6(swl::nullopt); 10 | 11 | static_assert(!o2); 12 | static_assert(!o3); 13 | static_assert(!o4); 14 | static_assert(!o5); 15 | static_assert(!o6); 16 | } 17 | 18 | { 19 | constexpr swl::optional o1 = 42; 20 | constexpr swl::optional o2{42}; 21 | constexpr swl::optional o3(42); 22 | constexpr swl::optional o4 = {42}; 23 | constexpr int i = 42; 24 | constexpr swl::optional o5 = std::move(i); 25 | constexpr swl::optional o6{std::move(i)}; 26 | constexpr swl::optional o7(std::move(i)); 27 | constexpr swl::optional o8 = {std::move(i)}; 28 | 29 | static_assert(*o1 == 42); 30 | static_assert(*o2 == 42); 31 | static_assert(*o3 == 42); 32 | static_assert(*o4 == 42); 33 | static_assert(*o5 == 42); 34 | static_assert(*o6 == 42); 35 | static_assert(*o7 == 42); 36 | static_assert(*o8 == 42); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/constructors.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | #include 3 | 4 | struct foo { 5 | foo() = default; 6 | foo(foo&) = delete; 7 | foo(foo&&) {}; 8 | }; 9 | 10 | int main(){ 11 | swl::optional o1; 12 | assert(!o1); 13 | 14 | swl::optional o2 = swl::nullopt; 15 | assert(!o2); 16 | 17 | swl::optional o3 = 42; 18 | assert(*o3 == 42); 19 | 20 | swl::optional o4 = o3; 21 | assert(*o4 == 42); 22 | 23 | swl::optional o5 = o1; 24 | assert(!o5); 25 | 26 | swl::optional o6 = std::move(o3); 27 | assert(*o6 == 42); 28 | 29 | swl::optional o7 = 42; 30 | assert(*o7 == 42); 31 | 32 | swl::optional o8 = o7; 33 | assert(*o8 == 42); 34 | 35 | swl::optional o9 = std::move(o7); 36 | assert(*o9 == 42); 37 | 38 | /* 39 | { 40 | swl::optional o; 41 | assert(!o); 42 | 43 | swl::optional oo = o; 44 | assert(!oo); 45 | } 46 | { 47 | auto i = 42; 48 | swl::optional o = i; 49 | assert(o); 50 | assert(*o == 42); 51 | 52 | swl::optional oo = o; 53 | assert(oo); 54 | assert(*oo == 42); 55 | } 56 | */ 57 | 58 | std::vector v; 59 | v.emplace_back(); 60 | swl::optional> ov = std::move(v); 61 | assert(ov->size() == 1); 62 | } 63 | -------------------------------------------------------------------------------- /tests/assignment.hpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | #include 3 | 4 | inline void assignement() { 5 | swl::optional o1 = 42; 6 | swl::optional o2 = 12; 7 | swl::optional o3; 8 | 9 | o1 = o1; 10 | assert(*o1 == 42); 11 | 12 | o1 = o2; 13 | assert(*o1 == 12); 14 | 15 | o1 = o3; 16 | assert(!o1); 17 | 18 | o1 = 42; 19 | assert(*o1 == 42); 20 | 21 | o1 = swl::nullopt; 22 | assert(!o1); 23 | 24 | o1 = std::move(o2); 25 | assert(*o1 == 12); 26 | 27 | swl::optional o4 = 42; 28 | 29 | o1 = o4; 30 | assert(*o1 == 42); 31 | 32 | o1 = std::move(o4); 33 | assert(*o1 == 42); 34 | } 35 | 36 | /* 37 | TEST_CASE("Assignment reference", "[assignment.ref]") { 38 | auto i = 42; 39 | auto j = 12; 40 | 41 | swl::optional o1 = i; 42 | swl::optional o2 = j; 43 | swl::optional o3; 44 | 45 | o1 = o1; 46 | assert(*o1 == 42); 47 | assert(&*o1 == &i); 48 | 49 | o1 = o2; 50 | assert(*o1 == 12); 51 | 52 | o1 = o3; 53 | assert(!o1); 54 | 55 | auto k = 42; 56 | o1 = k; 57 | assert(*o1 == 42); 58 | assert(*o1 == i); 59 | assert(*o1 == k); 60 | assert(&*o1 != &i); 61 | assert(&*o1 == &k); 62 | 63 | k = 12; 64 | assert(*o1 == 12); 65 | 66 | o1 = swl::nullopt; 67 | assert(!o1); 68 | 69 | o1 = std::move(o2); 70 | assert(*o1 == 12); 71 | } */ 72 | -------------------------------------------------------------------------------- /tests/hash.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace hash_test_impl{ 8 | struct A {}; 9 | struct B {}; 10 | } 11 | 12 | namespace std { 13 | template <> 14 | struct hash { 15 | size_t operator()(hash_test_impl::B const&) { return 0; } 16 | }; 17 | } 18 | 19 | template 20 | inline void test_hash_enabled_for_type(){ 21 | static_assert( requires{ std::hash{}; } ); 22 | } 23 | 24 | template 25 | inline void test_hash_disabled_for_type(){ 26 | static_assert( not requires{ std::hash{}; } ); 27 | } 28 | 29 | int main() 30 | { 31 | using namespace hash_test_impl; 32 | using swl::optional; 33 | 34 | const std::size_t nullopt_hash = 35 | std::hash>{}(optional{}); 36 | 37 | /* 38 | { 39 | optional opt; 40 | ASSERT_NOT_NOEXCEPT(std::hash>()(opt)); 41 | ASSERT_NOT_NOEXCEPT(std::hash>()(opt)); 42 | } */ 43 | 44 | { 45 | typedef int T; 46 | optional opt; 47 | assert(std::hash>{}(opt) == nullopt_hash); 48 | opt = 2; 49 | assert(std::hash>{}(opt) == std::hash{}(*opt)); 50 | } 51 | { 52 | typedef std::string T; 53 | optional opt; 54 | assert(std::hash>{}(opt) == nullopt_hash); 55 | opt = std::string("123"); 56 | assert(std::hash>{}(opt) == std::hash{}(*opt)); 57 | } 58 | { 59 | typedef std::unique_ptr T; 60 | optional opt; 61 | assert(std::hash>{}(opt) == nullopt_hash); 62 | opt = std::unique_ptr(new int(3)); 63 | assert(std::hash>{}(opt) == std::hash{}(*opt)); 64 | } 65 | { 66 | test_hash_enabled_for_type >(); 67 | test_hash_enabled_for_type >(); 68 | test_hash_enabled_for_type >(); 69 | test_hash_enabled_for_type >(); 70 | 71 | test_hash_disabled_for_type>(); 72 | test_hash_disabled_for_type>(); 73 | 74 | test_hash_enabled_for_type>(); 75 | test_hash_enabled_for_type>(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/noexcept_trait.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | 3 | int main() { 4 | swl::optional o1{4}; 5 | swl::optional o2{42}; 6 | 7 | { 8 | assert(noexcept(o1 == swl::nullopt)); 9 | assert(noexcept(swl::nullopt == o1)); 10 | assert(noexcept(o1 != swl::nullopt)); 11 | assert(noexcept(swl::nullopt != o1)); 12 | assert(noexcept(o1 < swl::nullopt)); 13 | assert(noexcept(swl::nullopt < o1)); 14 | assert(noexcept(o1 <= swl::nullopt)); 15 | assert(noexcept(swl::nullopt <= o1)); 16 | assert(noexcept(o1 > swl::nullopt)); 17 | assert(noexcept(swl::nullopt > o1)); 18 | assert(noexcept(o1 >= swl::nullopt)); 19 | assert(noexcept(swl::nullopt >= o1)); 20 | } 21 | 22 | 23 | { 24 | struct nothrow_swappable { 25 | nothrow_swappable &swap(const nothrow_swappable &) noexcept { 26 | return *this; 27 | } 28 | }; 29 | 30 | struct throw_swappable { 31 | throw_swappable() = default; 32 | throw_swappable(const throw_swappable &) {} 33 | throw_swappable(throw_swappable &&) {} 34 | throw_swappable &swap(const throw_swappable &) { return *this; } 35 | }; 36 | 37 | swl::optional ont; 38 | swl::optional ot; 39 | 40 | assert(noexcept(ont.swap(ont))); 41 | assert(!noexcept(ot.swap(ot))); 42 | } 43 | 44 | { 45 | assert(noexcept(swl::optional{})); 46 | assert(noexcept(swl::optional{swl::nullopt})); 47 | 48 | struct nothrow_move { 49 | nothrow_move(nothrow_move &&) noexcept = default; 50 | }; 51 | 52 | struct throw_move { 53 | throw_move(throw_move &&){}; 54 | }; 55 | 56 | using nothrow_opt = swl::optional; 57 | using throw_opt = swl::optional; 58 | 59 | assert(std::is_nothrow_move_constructible::value); 60 | assert(!std::is_nothrow_move_constructible::value); 61 | } 62 | 63 | { 64 | assert(noexcept(o1 = swl::nullopt)); 65 | 66 | struct nothrow_move_assign { 67 | nothrow_move_assign() = default; 68 | nothrow_move_assign(nothrow_move_assign &&) noexcept = default; 69 | nothrow_move_assign &operator=(const nothrow_move_assign &) = default; 70 | }; 71 | 72 | struct throw_move_assign { 73 | throw_move_assign() = default; 74 | throw_move_assign(throw_move_assign &&){}; 75 | throw_move_assign &operator=(const throw_move_assign &) { return *this; } 76 | }; 77 | 78 | using nothrow_opt = swl::optional; 79 | using throw_opt = swl::optional; 80 | 81 | assert(noexcept(std::declval() = std::declval())); 82 | assert(!noexcept(std::declval() = std::declval())); 83 | } 84 | 85 | { 86 | assert(noexcept(static_cast(o1))); 87 | assert(noexcept(o1.has_value())); 88 | } 89 | 90 | { 91 | assert(noexcept(o1.reset())); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/relops.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | 3 | int main() { 4 | swl::optional o1{4}; 5 | swl::optional o2{42}; 6 | swl::optional o3{}; 7 | 8 | { 9 | assert(!(o1 == o2)); 10 | assert(o1 == o1); 11 | assert(o1 != o2); 12 | assert(!(o1 != o1)); 13 | assert(o1 < o2); 14 | assert(!(o1 < o1)); 15 | assert(!(o1 > o2)); 16 | assert(!(o1 > o1)); 17 | assert(o1 <= o2); 18 | assert(o1 <= o1); 19 | assert(!(o1 >= o2)); 20 | assert(o1 >= o1); 21 | } 22 | 23 | { 24 | assert(!(o1 == swl::nullopt)); 25 | assert(!(swl::nullopt == o1)); 26 | assert(o1 != swl::nullopt); 27 | assert(swl::nullopt != o1); 28 | assert(!(o1 < swl::nullopt)); 29 | assert(swl::nullopt < o1); 30 | assert(o1 > swl::nullopt); 31 | assert(!(swl::nullopt > o1)); 32 | assert(!(o1 <= swl::nullopt)); 33 | assert(swl::nullopt <= o1); 34 | assert(o1 >= swl::nullopt); 35 | assert(!(swl::nullopt >= o1)); 36 | 37 | assert(o3 == swl::nullopt); 38 | assert(swl::nullopt == o3); 39 | assert(!(o3 != swl::nullopt)); 40 | assert(!(swl::nullopt != o3)); 41 | assert(!(o3 < swl::nullopt)); 42 | assert(!(swl::nullopt < o3)); 43 | assert(!(o3 > swl::nullopt)); 44 | assert(!(swl::nullopt > o3)); 45 | assert(o3 <= swl::nullopt); 46 | assert(swl::nullopt <= o3); 47 | assert(o3 >= swl::nullopt); 48 | assert(swl::nullopt >= o3); 49 | } 50 | 51 | { 52 | assert(!(o1 == 1)); 53 | assert(!(1 == o1)); 54 | assert(o1 != 1); 55 | assert(1 != o1); 56 | assert(!(o1 < 1)); 57 | assert(1 < o1); 58 | assert(o1 > 1); 59 | assert(!(1 > o1)); 60 | assert(!(o1 <= 1)); 61 | assert(1 <= o1); 62 | assert(o1 >= 1); 63 | assert(!(1 >= o1)); 64 | 65 | assert(o1 == 4); 66 | assert(4 == o1); 67 | assert(!(o1 != 4)); 68 | assert(!(4 != o1)); 69 | assert(!(o1 < 4)); 70 | assert(!(4 < o1)); 71 | assert(!(o1 > 4)); 72 | assert(!(4 > o1)); 73 | assert(o1 <= 4); 74 | assert(4 <= o1); 75 | assert(o1 >= 4); 76 | assert(4 >= o1); 77 | } 78 | 79 | swl::optional o4{"hello"}; 80 | swl::optional o5{"xyz"}; 81 | 82 | { 83 | assert(!(o4 == o5)); 84 | assert(o4 == o4); 85 | assert(o4 != o5); 86 | assert(!(o4 != o4)); 87 | assert(o4 < o5); 88 | assert(!(o4 < o4)); 89 | assert(!(o4 > o5)); 90 | assert(!(o4 > o4)); 91 | assert(o4 <= o5); 92 | assert(o4 <= o4); 93 | assert(!(o4 >= o5)); 94 | assert(o4 >= o4); 95 | } 96 | 97 | { 98 | assert(!(o4 == swl::nullopt)); 99 | assert(!(swl::nullopt == o4)); 100 | assert(o4 != swl::nullopt); 101 | assert(swl::nullopt != o4); 102 | assert(!(o4 < swl::nullopt)); 103 | assert(swl::nullopt < o4); 104 | assert(o4 > swl::nullopt); 105 | assert(!(swl::nullopt > o4)); 106 | assert(!(o4 <= swl::nullopt)); 107 | assert(swl::nullopt <= o4); 108 | assert(o4 >= swl::nullopt); 109 | assert(!(swl::nullopt >= o4)); 110 | 111 | assert(o3 == swl::nullopt); 112 | assert(swl::nullopt == o3); 113 | assert(!(o3 != swl::nullopt)); 114 | assert(!(swl::nullopt != o3)); 115 | assert(!(o3 < swl::nullopt)); 116 | assert(!(swl::nullopt < o3)); 117 | assert(!(o3 > swl::nullopt)); 118 | assert(!(swl::nullopt > o3)); 119 | assert(o3 <= swl::nullopt); 120 | assert(swl::nullopt <= o3); 121 | assert(o3 >= swl::nullopt); 122 | assert(swl::nullopt >= o3); 123 | } 124 | 125 | { 126 | assert(!(o4 == "a")); 127 | assert(!("a" == o4)); 128 | assert(o4 != "a"); 129 | assert("a" != o4); 130 | assert(!(o4 < "a")); 131 | assert("a" < o4); 132 | assert(o4 > "a"); 133 | assert(!("a" > o4)); 134 | assert(!(o4 <= "a")); 135 | assert("a" <= o4); 136 | assert(o4 >= "a"); 137 | assert(!("a" >= o4)); 138 | 139 | assert(o4 == "hello"); 140 | assert("hello" == o4); 141 | assert(!(o4 != "hello")); 142 | assert(!("hello" != o4)); 143 | assert(!(o4 < "hello")); 144 | assert(!("hello" < o4)); 145 | assert(!(o4 > "hello")); 146 | assert(!("hello" > o4)); 147 | assert(o4 <= "hello"); 148 | assert("hello" <= o4); 149 | assert(o4 >= "hello"); 150 | assert("hello" >= o4); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /tests/sfm_traits.cpp: -------------------------------------------------------------------------------- 1 | #include "test_util.hpp" 2 | #include 3 | 4 | int main() { 5 | static_assert(std::is_trivially_copy_constructible>::value); 6 | static_assert(std::is_trivially_copy_assignable>::value); 7 | static_assert(std::is_trivially_move_constructible>::value); 8 | static_assert(std::is_trivially_move_assignable>::value); 9 | static_assert(std::is_trivially_destructible>::value); 10 | 11 | { 12 | struct T { 13 | T(const T&) = default; 14 | T(T&&) = default; 15 | T& operator=(const T&) = default; 16 | T& operator=(T&&) = default; 17 | ~T() = default; 18 | }; 19 | static_assert(std::is_trivially_copy_constructible>::value); 20 | static_assert(std::is_trivially_copy_assignable>::value); 21 | static_assert(std::is_trivially_move_constructible>::value); 22 | static_assert(std::is_trivially_move_assignable>::value); 23 | static_assert(std::is_trivially_destructible>::value); 24 | } 25 | 26 | { 27 | struct T { 28 | T(const T&){} 29 | T(T&&) {}; 30 | T& operator=(const T&) { return *this; } 31 | T& operator=(T&&) { return *this; }; 32 | ~T(){} 33 | }; 34 | static_assert(!std::is_trivially_copy_constructible>::value); 35 | static_assert(!std::is_trivially_copy_assignable>::value); 36 | static_assert(!std::is_trivially_move_constructible>::value); 37 | static_assert(!std::is_trivially_move_assignable>::value); 38 | static_assert(!std::is_trivially_destructible>::value); 39 | } 40 | 41 | 42 | // ==================== 43 | 44 | static_assert(std::is_copy_constructible>::value); 45 | static_assert(std::is_copy_assignable>::value); 46 | static_assert(std::is_move_constructible>::value); 47 | static_assert(std::is_move_assignable>::value); 48 | static_assert(std::is_destructible>::value); 49 | 50 | { 51 | struct T { 52 | T(const T&) = default; 53 | T(T&&) = default; 54 | T& operator=(const T&) = default; 55 | T& operator=(T&&) = default; 56 | ~T() = default; 57 | }; 58 | static_assert(std::is_copy_constructible>::value); 59 | static_assert(std::is_copy_assignable>::value); 60 | static_assert(std::is_move_constructible>::value); 61 | static_assert(std::is_move_assignable>::value); 62 | static_assert(std::is_destructible>::value); 63 | } 64 | 65 | { 66 | struct T { 67 | T(const T&)=delete; 68 | T(T&&)=delete; 69 | T& operator=(const T&)=delete; 70 | T& operator=(T&&)=delete; 71 | }; 72 | static_assert(!std::is_copy_constructible>::value); 73 | static_assert(!std::is_copy_assignable>::value); 74 | static_assert(!std::is_move_constructible>::value); 75 | static_assert(!std::is_move_assignable>::value); 76 | } 77 | 78 | { 79 | struct T { 80 | T(const T&)=delete; 81 | T(T&&)=default; 82 | T& operator=(const T&)=delete; 83 | T& operator=(T&&)=default; 84 | }; 85 | static_assert(!std::is_copy_constructible>::value); 86 | static_assert(!std::is_copy_assignable>::value); 87 | static_assert(std::is_move_constructible>::value); 88 | static_assert(std::is_move_assignable>::value); 89 | } 90 | 91 | { 92 | struct T { 93 | T(const T&)=default; 94 | T(T&&)=delete; 95 | T& operator=(const T&)=default; 96 | T& operator=(T&&)=delete; 97 | }; 98 | static_assert(std::is_copy_constructible>::value); 99 | static_assert(std::is_copy_assignable>::value); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /tests/archetypes.ipp: -------------------------------------------------------------------------------- 1 | //===----------------------------------------------------------------------===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | 9 | #ifndef DEFINE_BASE 10 | #define DEFINE_BASE(Name) ::ArchetypeBases::NullBase 11 | #endif 12 | #ifndef DEFINE_EXPLICIT 13 | #define DEFINE_EXPLICIT 14 | #endif 15 | #ifndef DEFINE_NOEXCEPT 16 | #define DEFINE_NOEXCEPT 17 | #endif 18 | #ifndef DEFINE_CONSTEXPR 19 | #ifdef TEST_WORKAROUND_EDG_EXPLICIT_CONSTEXPR 20 | #define DEFINE_CONSTEXPR 21 | #else // TEST_WORKAROUND_EDG_EXPLICIT_CONSTEXPR 22 | #define DEFINE_CONSTEXPR constexpr 23 | #endif // TEST_WORKAROUND_EDG_EXPLICIT_CONSTEXPR 24 | #endif 25 | #ifndef DEFINE_ASSIGN_CONSTEXPR 26 | #if TEST_STD_VER >= 14 27 | #define DEFINE_ASSIGN_CONSTEXPR DEFINE_CONSTEXPR 28 | #else 29 | #define DEFINE_ASSIGN_CONSTEXPR 30 | #endif 31 | #endif 32 | #ifndef DEFINE_CTOR 33 | #define DEFINE_CTOR = default 34 | #endif 35 | #ifndef DEFINE_DEFAULT_CTOR 36 | #define DEFINE_DEFAULT_CTOR DEFINE_CTOR 37 | #endif 38 | #ifndef DEFINE_ASSIGN 39 | #define DEFINE_ASSIGN = default 40 | #endif 41 | #ifndef DEFINE_DTOR 42 | #define DEFINE_DTOR(Name) 43 | #endif 44 | 45 | struct AllCtors : DEFINE_BASE(AllCtors) { 46 | using Base = DEFINE_BASE(AllCtors); 47 | using Base::Base; 48 | using Base::operator=; 49 | DEFINE_EXPLICIT DEFINE_CONSTEXPR AllCtors() DEFINE_NOEXCEPT DEFINE_DEFAULT_CTOR; 50 | DEFINE_EXPLICIT DEFINE_CONSTEXPR AllCtors(AllCtors const&) DEFINE_NOEXCEPT DEFINE_CTOR; 51 | DEFINE_EXPLICIT DEFINE_CONSTEXPR AllCtors(AllCtors &&) DEFINE_NOEXCEPT DEFINE_CTOR; 52 | DEFINE_ASSIGN_CONSTEXPR AllCtors& operator=(AllCtors const&) DEFINE_NOEXCEPT DEFINE_ASSIGN; 53 | DEFINE_ASSIGN_CONSTEXPR AllCtors& operator=(AllCtors &&) DEFINE_NOEXCEPT DEFINE_ASSIGN; 54 | DEFINE_DTOR(AllCtors) 55 | }; 56 | 57 | struct NoCtors : DEFINE_BASE(NoCtors) { 58 | using Base = DEFINE_BASE(NoCtors); 59 | DEFINE_EXPLICIT NoCtors() DEFINE_NOEXCEPT = delete; 60 | DEFINE_EXPLICIT NoCtors(NoCtors const&) DEFINE_NOEXCEPT = delete; 61 | NoCtors& operator=(NoCtors const&) DEFINE_NOEXCEPT = delete; 62 | DEFINE_DTOR(NoCtors) 63 | }; 64 | 65 | struct NoDefault : DEFINE_BASE(NoDefault) { 66 | using Base = DEFINE_BASE(NoDefault); 67 | using Base::Base; 68 | DEFINE_EXPLICIT DEFINE_CONSTEXPR NoDefault() DEFINE_NOEXCEPT = delete; 69 | DEFINE_DTOR(NoDefault) 70 | }; 71 | 72 | struct DefaultOnly : DEFINE_BASE(DefaultOnly) { 73 | using Base = DEFINE_BASE(DefaultOnly); 74 | using Base::Base; 75 | DEFINE_EXPLICIT DEFINE_CONSTEXPR DefaultOnly() DEFINE_NOEXCEPT DEFINE_DEFAULT_CTOR; 76 | DefaultOnly(DefaultOnly const&) DEFINE_NOEXCEPT = delete; 77 | DefaultOnly& operator=(DefaultOnly const&) DEFINE_NOEXCEPT = delete; 78 | DEFINE_DTOR(DefaultOnly) 79 | }; 80 | 81 | struct Copyable : DEFINE_BASE(Copyable) { 82 | using Base = DEFINE_BASE(Copyable); 83 | using Base::Base; 84 | DEFINE_EXPLICIT DEFINE_CONSTEXPR Copyable() DEFINE_NOEXCEPT DEFINE_DEFAULT_CTOR; 85 | DEFINE_EXPLICIT DEFINE_CONSTEXPR Copyable(Copyable const &) DEFINE_NOEXCEPT DEFINE_CTOR; 86 | Copyable &operator=(Copyable const &) DEFINE_NOEXCEPT DEFINE_ASSIGN; 87 | DEFINE_DTOR(Copyable) 88 | }; 89 | 90 | struct CopyOnly : DEFINE_BASE(CopyOnly) { 91 | using Base = DEFINE_BASE(CopyOnly); 92 | using Base::Base; 93 | DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyOnly() DEFINE_NOEXCEPT DEFINE_DEFAULT_CTOR; 94 | DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyOnly(CopyOnly const &) DEFINE_NOEXCEPT DEFINE_CTOR; 95 | DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyOnly(CopyOnly &&) DEFINE_NOEXCEPT = delete; 96 | CopyOnly &operator=(CopyOnly const &) DEFINE_NOEXCEPT DEFINE_ASSIGN; 97 | CopyOnly &operator=(CopyOnly &&) DEFINE_NOEXCEPT = delete; 98 | DEFINE_DTOR(CopyOnly) 99 | }; 100 | 101 | struct NonCopyable : DEFINE_BASE(NonCopyable) { 102 | using Base = DEFINE_BASE(NonCopyable); 103 | using Base::Base; 104 | DEFINE_EXPLICIT DEFINE_CONSTEXPR NonCopyable() DEFINE_NOEXCEPT DEFINE_DEFAULT_CTOR; 105 | DEFINE_EXPLICIT DEFINE_CONSTEXPR NonCopyable(NonCopyable const &) DEFINE_NOEXCEPT = delete; 106 | NonCopyable &operator=(NonCopyable const &) DEFINE_NOEXCEPT = delete; 107 | DEFINE_DTOR(NonCopyable) 108 | }; 109 | 110 | struct MoveOnly : DEFINE_BASE(MoveOnly) { 111 | using Base = DEFINE_BASE(MoveOnly); 112 | using Base::Base; 113 | DEFINE_EXPLICIT DEFINE_CONSTEXPR MoveOnly() DEFINE_NOEXCEPT DEFINE_DEFAULT_CTOR; 114 | DEFINE_EXPLICIT DEFINE_CONSTEXPR MoveOnly(MoveOnly &&) DEFINE_NOEXCEPT DEFINE_CTOR; 115 | MoveOnly &operator=(MoveOnly &&) DEFINE_NOEXCEPT DEFINE_ASSIGN; 116 | DEFINE_DTOR(MoveOnly) 117 | }; 118 | 119 | struct CopyAssignable : DEFINE_BASE(CopyAssignable) { 120 | using Base = DEFINE_BASE(CopyAssignable); 121 | using Base::Base; 122 | DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyAssignable() DEFINE_NOEXCEPT = delete; 123 | CopyAssignable& operator=(CopyAssignable const&) DEFINE_NOEXCEPT DEFINE_ASSIGN; 124 | DEFINE_DTOR(CopyAssignable) 125 | }; 126 | 127 | struct CopyAssignOnly : DEFINE_BASE(CopyAssignOnly) { 128 | using Base = DEFINE_BASE(CopyAssignOnly); 129 | using Base::Base; 130 | DEFINE_EXPLICIT DEFINE_CONSTEXPR CopyAssignOnly() DEFINE_NOEXCEPT = delete; 131 | CopyAssignOnly& operator=(CopyAssignOnly const&) DEFINE_NOEXCEPT DEFINE_ASSIGN; 132 | CopyAssignOnly& operator=(CopyAssignOnly &&) DEFINE_NOEXCEPT = delete; 133 | DEFINE_DTOR(CopyAssignOnly) 134 | }; 135 | 136 | struct MoveAssignOnly : DEFINE_BASE(MoveAssignOnly) { 137 | using Base = DEFINE_BASE(MoveAssignOnly); 138 | using Base::Base; 139 | DEFINE_EXPLICIT DEFINE_CONSTEXPR MoveAssignOnly() DEFINE_NOEXCEPT = delete; 140 | MoveAssignOnly& operator=(MoveAssignOnly const&) DEFINE_NOEXCEPT = delete; 141 | MoveAssignOnly& operator=(MoveAssignOnly &&) DEFINE_NOEXCEPT DEFINE_ASSIGN; 142 | DEFINE_DTOR(MoveAssignOnly) 143 | }; 144 | 145 | struct ConvertingType : DEFINE_BASE(ConvertingType) { 146 | using Base = DEFINE_BASE(ConvertingType); 147 | using Base::Base; 148 | DEFINE_EXPLICIT DEFINE_CONSTEXPR ConvertingType() DEFINE_NOEXCEPT DEFINE_DEFAULT_CTOR; 149 | DEFINE_EXPLICIT DEFINE_CONSTEXPR ConvertingType(ConvertingType const&) DEFINE_NOEXCEPT DEFINE_CTOR; 150 | DEFINE_EXPLICIT DEFINE_CONSTEXPR ConvertingType(ConvertingType &&) DEFINE_NOEXCEPT DEFINE_CTOR; 151 | ConvertingType& operator=(ConvertingType const&) DEFINE_NOEXCEPT DEFINE_ASSIGN; 152 | ConvertingType& operator=(ConvertingType &&) DEFINE_NOEXCEPT DEFINE_ASSIGN; 153 | template 154 | DEFINE_EXPLICIT DEFINE_CONSTEXPR ConvertingType(Args&&...) DEFINE_NOEXCEPT {} 155 | template 156 | ConvertingType& operator=(Arg&&) DEFINE_NOEXCEPT { return *this; } 157 | DEFINE_DTOR(ConvertingType) 158 | }; 159 | 160 | template