forked from TartanLlama/expected
Cmake love (#55)
* Do CMake properly * Remove uneeded file * Add patch to version * Init submodule in appveyor * Use FetchContent * Up CMake version requirement * Use Xenial on Travis instead of Trusty * Tidy traits * Use Xenial repos
This commit is contained in:
@@ -3,6 +3,7 @@ os:
|
|||||||
- Visual Studio 2017
|
- Visual Studio 2017
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
|
- git submodule update --init --recursive
|
||||||
- mkdir build
|
- mkdir build
|
||||||
- cd build
|
- cd build
|
||||||
- cmake ..
|
- cmake ..
|
||||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "cmake/tl-cmake"]
|
||||||
|
path = cmake/tl-cmake
|
||||||
|
url = https://github.com/TartanLlama/tl-cmake.git
|
18
.travis.yml
18
.travis.yml
@@ -1,6 +1,6 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
|
|
||||||
dist: trusty
|
dist: xenial
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
@@ -97,7 +97,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main"
|
- sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main"
|
||||||
key_url: "http://apt.llvm.org/llvm-snapshot.gpg.key"
|
key_url: "http://apt.llvm.org/llvm-snapshot.gpg.key"
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
@@ -108,7 +108,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- llvm-toolchain-trusty-4.0
|
- llvm-toolchain-xenial-4.0
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- clang++-4.0
|
- clang++-4.0
|
||||||
@@ -118,7 +118,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- llvm-toolchain-trusty-5.0
|
- llvm-toolchain-xenial-5.0
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- clang++-5.0
|
- clang++-5.0
|
||||||
@@ -128,7 +128,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- llvm-toolchain-trusty-6.0
|
- llvm-toolchain-xenial-6.0
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- clang++-6.0
|
- clang++-6.0
|
||||||
@@ -211,7 +211,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.9 main"
|
- sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main"
|
||||||
key_url: "http://apt.llvm.org/llvm-snapshot.gpg.key"
|
key_url: "http://apt.llvm.org/llvm-snapshot.gpg.key"
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
@@ -222,7 +222,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- llvm-toolchain-trusty-4.0
|
- llvm-toolchain-xenial-4.0
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- clang++-4.0
|
- clang++-4.0
|
||||||
@@ -232,7 +232,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- llvm-toolchain-trusty-5.0
|
- llvm-toolchain-xenial-5.0
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- clang++-5.0
|
- clang++-5.0
|
||||||
@@ -242,7 +242,7 @@ matrix:
|
|||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- llvm-toolchain-trusty-6.0
|
- llvm-toolchain-xenial-6.0
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- clang++-6.0
|
- clang++-6.0
|
||||||
|
@@ -1,12 +1,23 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.11)
|
||||||
|
|
||||||
project(expected)
|
project(tl-expected VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
option(EXPECTED_ENABLE_TESTS "Enable tests." ON)
|
option(EXPECTED_ENABLE_TESTS "Enable tests." ON)
|
||||||
|
|
||||||
add_library(expected INTERFACE)
|
include(FetchContent)
|
||||||
target_sources(expected INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/tl/expected.hpp)
|
FetchContent_Declare(
|
||||||
target_include_directories(expected INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/tl)
|
tl_cmake
|
||||||
|
GIT_REPOSITORY https://github.com/TartanLlama/tl-cmake.git
|
||||||
|
)
|
||||||
|
FetchContent_GetProperties(tl_cmake)
|
||||||
|
if(NOT tl_cmake_POPULATED)
|
||||||
|
FetchContent_Populate(tl_cmake)
|
||||||
|
set(CMAKE_MODULE_PATH ${tl_cmake_SOURCE_DIR} ${CMAKE_MODULE_PATH})
|
||||||
|
endif()
|
||||||
|
include(add-tl)
|
||||||
|
|
||||||
|
tl_add_library(expected SOURCES
|
||||||
|
include/tl/expected.hpp)
|
||||||
|
|
||||||
# Prepare "Catch" library for other executables
|
# Prepare "Catch" library for other executables
|
||||||
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test)
|
set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test)
|
||||||
|
1
cmake/tl-cmake
Submodule
1
cmake/tl-cmake
Submodule
Submodule cmake/tl-cmake added at 284c6a3f0f
3
cmake/tl-expected-config.cmake.in
Normal file
3
cmake/tl-expected-config.cmake.in
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/tl-expected-targets.cmake")
|
@@ -12,8 +12,8 @@ class ExpectedConan(ConanFile):
|
|||||||
exports_sources = "*"
|
exports_sources = "*"
|
||||||
|
|
||||||
def source(self):
|
def source(self):
|
||||||
tools.replace_in_file('CMakeLists.txt', 'project(expected)',
|
tools.replace_in_file('CMakeLists.txt', 'project(tl-expected)',
|
||||||
'''project(expected)
|
'''project(tl-expected)
|
||||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||||
conan_basic_setup()
|
conan_basic_setup()
|
||||||
''')
|
''')
|
||||||
@@ -31,4 +31,4 @@ conan_basic_setup()
|
|||||||
self.run('%s/bin/tests' % self.build_folder)
|
self.run('%s/bin/tests' % self.build_folder)
|
||||||
|
|
||||||
def package(self):
|
def package(self):
|
||||||
self.copy('*.hpp', dst='include/tl', src='tl')
|
self.copy('*.hpp', dst='include/tl', src='include/tl')
|
@@ -14,8 +14,9 @@
|
|||||||
#ifndef TL_EXPECTED_HPP
|
#ifndef TL_EXPECTED_HPP
|
||||||
#define TL_EXPECTED_HPP
|
#define TL_EXPECTED_HPP
|
||||||
|
|
||||||
#define TL_EXPECTED_VERSION_MAJOR 0
|
#define TL_EXPECTED_VERSION_MAJOR 1
|
||||||
#define TL_EXPECTED_VERSION_MINOR 2
|
#define TL_EXPECTED_VERSION_MINOR 0
|
||||||
|
#define TL_EXPECTED_VERSION_PATCH 0
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -234,24 +235,55 @@ template <class...> struct conjunction : std::true_type {};
|
|||||||
template <class B> struct conjunction<B> : B {};
|
template <class B> struct conjunction<B> : B {};
|
||||||
template <class B, class... Bs>
|
template <class B, class... Bs>
|
||||||
struct conjunction<B, Bs...>
|
struct conjunction<B, Bs...>
|
||||||
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
|
: std::conditional<bool(B::value), conjunction<Bs...>, B>::type {};
|
||||||
|
|
||||||
|
#if defined(_LIBCPP_VERSION) && __cplusplus == 201103L
|
||||||
|
#define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// In C++11 mode, there's an issue in libc++'s std::mem_fn
|
||||||
|
// which results in a hard-error when using it in a noexcept expression
|
||||||
|
// in some cases. This is a check to workaround the common failing case.
|
||||||
|
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
|
||||||
|
template <class T> struct is_pointer_to_non_const_member_func : std::false_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...)> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...)&> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...) &&> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...) volatile> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...) volatile &> : std::true_type {};
|
||||||
|
template <class T, class Ret, class... Args>
|
||||||
|
struct is_pointer_to_non_const_member_func<Ret(T::*) (Args...) volatile &&> : std::true_type {};
|
||||||
|
|
||||||
|
template <class T> struct is_const_or_const_ref : std::false_type {};
|
||||||
|
template <class T> struct is_const_or_const_ref<T const&> : std::true_type {};
|
||||||
|
template <class T> struct is_const_or_const_ref<T const> : std::true_type {};
|
||||||
|
#endif
|
||||||
|
|
||||||
// std::invoke from C++17
|
// std::invoke from C++17
|
||||||
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
|
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
|
||||||
template <typename Fn, typename... Args,
|
template <typename Fn, typename... Args,
|
||||||
typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>{}>,
|
#ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND
|
||||||
int = 0>
|
typename = enable_if_t<!(is_pointer_to_non_const_member_func<Fn>::value
|
||||||
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
&& is_const_or_const_ref<Args...>::value)>,
|
||||||
|
#endif
|
||||||
|
typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>,
|
||||||
|
int = 0>
|
||||||
|
constexpr auto invoke(Fn && f, Args && ... args) noexcept(
|
||||||
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
|
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
|
||||||
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
|
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
|
||||||
return std::mem_fn(f)(std::forward<Args>(args)...);
|
return std::mem_fn(f)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Fn, typename... Args,
|
template <typename Fn, typename... Args,
|
||||||
typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}>>
|
typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>::value>>
|
||||||
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
|
constexpr auto invoke(Fn && f, Args && ... args) noexcept(
|
||||||
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
|
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
|
||||||
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
|
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
|
||||||
return std::forward<Fn>(f)(std::forward<Args>(args)...);
|
return std::forward<Fn>(f)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,8 +292,8 @@ template <class F, class, class... Us> struct invoke_result_impl;
|
|||||||
|
|
||||||
template <class F, class... Us>
|
template <class F, class... Us>
|
||||||
struct invoke_result_impl<
|
struct invoke_result_impl<
|
||||||
F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
|
F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()),
|
||||||
Us...> {
|
Us...> {
|
||||||
using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
|
using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -279,68 +311,68 @@ template <class T, class U = T> struct is_nothrow_swappable : std::true_type {};
|
|||||||
#else
|
#else
|
||||||
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
|
// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
|
||||||
namespace swap_adl_tests {
|
namespace swap_adl_tests {
|
||||||
// if swap ADL finds this then it would call std::swap otherwise (same
|
// if swap ADL finds this then it would call std::swap otherwise (same
|
||||||
// signature)
|
// signature)
|
||||||
struct tag {};
|
struct tag {};
|
||||||
|
|
||||||
template <class T> tag swap(T &, T &);
|
template <class T> tag swap(T&, T&);
|
||||||
template <class T, std::size_t N> tag swap(T (&a)[N], T (&b)[N]);
|
template <class T, std::size_t N> tag swap(T(&a)[N], T(&b)[N]);
|
||||||
|
|
||||||
// helper functions to test if an unqualified swap is possible, and if it
|
// helper functions to test if an unqualified swap is possible, and if it
|
||||||
// becomes std::swap
|
// becomes std::swap
|
||||||
template <class, class> std::false_type can_swap(...) noexcept(false);
|
template <class, class> std::false_type can_swap(...) noexcept(false);
|
||||||
template <class T, class U,
|
template <class T, class U,
|
||||||
class = decltype(swap(std::declval<T &>(), std::declval<U &>()))>
|
class = decltype(swap(std::declval<T&>(), std::declval<U&>()))>
|
||||||
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T &>(),
|
std::true_type can_swap(int) noexcept(noexcept(swap(std::declval<T&>(),
|
||||||
std::declval<U &>())));
|
std::declval<U&>())));
|
||||||
|
|
||||||
template <class, class> std::false_type uses_std(...);
|
template <class, class> std::false_type uses_std(...);
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
std::is_same<decltype(swap(std::declval<T &>(), std::declval<U &>())), tag>
|
std::is_same<decltype(swap(std::declval<T&>(), std::declval<U&>())), tag>
|
||||||
uses_std(int);
|
uses_std(int);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct is_std_swap_noexcept
|
struct is_std_swap_noexcept
|
||||||
: std::integral_constant<bool,
|
: std::integral_constant<bool,
|
||||||
std::is_nothrow_move_constructible<T>::value &&
|
std::is_nothrow_move_constructible<T>::value&&
|
||||||
std::is_nothrow_move_assignable<T>::value> {};
|
std::is_nothrow_move_assignable<T>::value> {};
|
||||||
|
|
||||||
template <class T, std::size_t N>
|
template <class T, std::size_t N>
|
||||||
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
|
struct is_std_swap_noexcept<T[N]> : is_std_swap_noexcept<T> {};
|
||||||
|
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
struct is_adl_swap_noexcept
|
struct is_adl_swap_noexcept
|
||||||
: std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
|
: std::integral_constant<bool, noexcept(can_swap<T, U>(0))> {};
|
||||||
} // namespace swap_adl_tests
|
} // namespace swap_adl_tests
|
||||||
|
|
||||||
template <class T, class U = T>
|
template <class T, class U = T>
|
||||||
struct is_swappable
|
struct is_swappable
|
||||||
: std::integral_constant<
|
: std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
|
decltype(detail::swap_adl_tests::can_swap<T, U>(0))::value &&
|
||||||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
|
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value ||
|
||||||
(std::is_move_assignable<T>::value &&
|
(std::is_move_assignable<T>::value &&
|
||||||
std::is_move_constructible<T>::value))> {};
|
std::is_move_constructible<T>::value))> {};
|
||||||
|
|
||||||
template <class T, std::size_t N>
|
template <class T, std::size_t N>
|
||||||
struct is_swappable<T[N], T[N]>
|
struct is_swappable<T[N], T[N]>
|
||||||
: std::integral_constant<
|
: std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
|
decltype(detail::swap_adl_tests::can_swap<T[N], T[N]>(0))::value &&
|
||||||
(!decltype(
|
(!decltype(
|
||||||
detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
|
detail::swap_adl_tests::uses_std<T[N], T[N]>(0))::value ||
|
||||||
is_swappable<T, T>::value)> {};
|
is_swappable<T, T>::value)> {};
|
||||||
|
|
||||||
template <class T, class U = T>
|
template <class T, class U = T>
|
||||||
struct is_nothrow_swappable
|
struct is_nothrow_swappable
|
||||||
: std::integral_constant<
|
: std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
is_swappable<T, U>::value &&
|
is_swappable<T, U>::value &&
|
||||||
((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
|
((decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value
|
||||||
&&detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
|
&& detail::swap_adl_tests::is_std_swap_noexcept<T>::value) ||
|
||||||
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
|
(!decltype(detail::swap_adl_tests::uses_std<T, U>(0))::value &&
|
||||||
detail::swap_adl_tests::is_adl_swap_noexcept<T,
|
detail::swap_adl_tests::is_adl_swap_noexcept<T,
|
||||||
U>::value))> {
|
U>::value))> {
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@@ -2442,5 +2474,4 @@ void swap(expected<T, E> &lhs,
|
|||||||
}
|
}
|
||||||
} // namespace tl
|
} // namespace tl
|
||||||
|
|
||||||
#define TL_OPTIONAL_EXPECTED_MUTEX
|
|
||||||
#endif
|
#endif
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
TEST_CASE("Simple assignment", "[assignment.simple]") {
|
TEST_CASE("Simple assignment", "[assignment.simple]") {
|
||||||
tl::expected<int, int> e1 = 42;
|
tl::expected<int, int> e1 = 42;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
TEST_CASE("Constexpr", "[constexpr]") {
|
TEST_CASE("Constexpr", "[constexpr]") {
|
||||||
//TODO
|
//TODO
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
#define TOKENPASTE(x, y) x##y
|
#define TOKENPASTE(x, y) x##y
|
||||||
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
|
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
|
||||||
|
256
tests/issues.cpp
256
tests/issues.cpp
@@ -1,129 +1,129 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
tl::expected<int, string> getInt3(int val) { return val; }
|
tl::expected<int, string> getInt3(int val) { return val; }
|
||||||
|
|
||||||
tl::expected<int, string> getInt2(int val) { return val; }
|
tl::expected<int, string> getInt2(int val) { return val; }
|
||||||
|
|
||||||
tl::expected<int, string> getInt1() { return getInt2(5).and_then(getInt3); }
|
tl::expected<int, string> getInt1() { return getInt2(5).and_then(getInt3); }
|
||||||
|
|
||||||
TEST_CASE("Issue 1", "[issues.1]") { getInt1(); }
|
TEST_CASE("Issue 1", "[issues.1]") { getInt1(); }
|
||||||
|
|
||||||
tl::expected<int, int> operation1() { return 42; }
|
tl::expected<int, int> operation1() { return 42; }
|
||||||
|
|
||||||
tl::expected<std::string, int> operation2(int const val) { return "Bananas"; }
|
tl::expected<std::string, int> operation2(int const val) { return "Bananas"; }
|
||||||
|
|
||||||
TEST_CASE("Issue 17", "[issues.17]") {
|
TEST_CASE("Issue 17", "[issues.17]") {
|
||||||
auto const intermediate_result = operation1();
|
auto const intermediate_result = operation1();
|
||||||
|
|
||||||
intermediate_result.and_then(operation2);
|
intermediate_result.and_then(operation2);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct a {};
|
struct a {};
|
||||||
struct b : a {};
|
struct b : a {};
|
||||||
|
|
||||||
auto doit() -> tl::expected<std::unique_ptr<b>, int> {
|
auto doit() -> tl::expected<std::unique_ptr<b>, int> {
|
||||||
return tl::make_unexpected(0);
|
return tl::make_unexpected(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Issue 23", "[issues.23]") {
|
TEST_CASE("Issue 23", "[issues.23]") {
|
||||||
tl::expected<std::unique_ptr<a>, int> msg = doit();
|
tl::expected<std::unique_ptr<a>, int> msg = doit();
|
||||||
REQUIRE(!msg.has_value());
|
REQUIRE(!msg.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Issue 26", "[issues.26]") {
|
TEST_CASE("Issue 26", "[issues.26]") {
|
||||||
tl::expected<a, int> exp = tl::expected<b, int>(tl::unexpect, 0);
|
tl::expected<a, int> exp = tl::expected<b, int>(tl::unexpect, 0);
|
||||||
REQUIRE(!exp.has_value());
|
REQUIRE(!exp.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct foo {
|
struct foo {
|
||||||
foo() = default;
|
foo() = default;
|
||||||
foo(foo &) = delete;
|
foo(foo &) = delete;
|
||||||
foo(foo &&){};
|
foo(foo &&){};
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE("Issue 29", "[issues.29]") {
|
TEST_CASE("Issue 29", "[issues.29]") {
|
||||||
std::vector<foo> v;
|
std::vector<foo> v;
|
||||||
v.emplace_back();
|
v.emplace_back();
|
||||||
tl::expected<std::vector<foo>, int> ov = std::move(v);
|
tl::expected<std::vector<foo>, int> ov = std::move(v);
|
||||||
REQUIRE(ov->size() == 1);
|
REQUIRE(ov->size() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
tl::expected<int, std::string> error() {
|
tl::expected<int, std::string> error() {
|
||||||
return tl::make_unexpected(std::string("error1 "));
|
return tl::make_unexpected(std::string("error1 "));
|
||||||
}
|
}
|
||||||
std::string maperror(std::string s) { return s + "maperror "; }
|
std::string maperror(std::string s) { return s + "maperror "; }
|
||||||
|
|
||||||
TEST_CASE("Issue 30", "[issues.30]") {
|
TEST_CASE("Issue 30", "[issues.30]") {
|
||||||
error().map_error(maperror);
|
error().map_error(maperror);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct i31{
|
struct i31{
|
||||||
int i;
|
int i;
|
||||||
};
|
};
|
||||||
TEST_CASE("Issue 31", "[issues.31]") {
|
TEST_CASE("Issue 31", "[issues.31]") {
|
||||||
const tl::expected<i31, int> a = i31{42};
|
const tl::expected<i31, int> a = i31{42};
|
||||||
a->i;
|
a->i;
|
||||||
|
|
||||||
tl::expected< void, std::string > result;
|
tl::expected< void, std::string > result;
|
||||||
tl::expected< void, std::string > result2 = result;
|
tl::expected< void, std::string > result2 = result;
|
||||||
result2 = result;
|
result2 = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Issue 33", "[issues.33]") {
|
TEST_CASE("Issue 33", "[issues.33]") {
|
||||||
tl::expected<void, int> res {tl::unexpect, 0};
|
tl::expected<void, int> res {tl::unexpect, 0};
|
||||||
REQUIRE(!res);
|
REQUIRE(!res);
|
||||||
res = res.map_error([](int i) { return 42; });
|
res = res.map_error([](int i) { return 42; });
|
||||||
REQUIRE(res.error() == 42);
|
REQUIRE(res.error() == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tl::expected<void, std::string> voidWork() { return {}; }
|
tl::expected<void, std::string> voidWork() { return {}; }
|
||||||
tl::expected<int, std::string> work2() { return 42; }
|
tl::expected<int, std::string> work2() { return 42; }
|
||||||
void errorhandling(std::string){}
|
void errorhandling(std::string){}
|
||||||
|
|
||||||
TEST_CASE("Issue 34", "[issues.34]") {
|
TEST_CASE("Issue 34", "[issues.34]") {
|
||||||
tl::expected <int, std::string> result = voidWork ()
|
tl::expected <int, std::string> result = voidWork ()
|
||||||
.and_then (work2);
|
.and_then (work2);
|
||||||
result.map_error ([&] (std::string result) {errorhandling (result);});
|
result.map_error ([&] (std::string result) {errorhandling (result);});
|
||||||
}
|
}
|
||||||
|
|
||||||
struct non_copyable {
|
struct non_copyable {
|
||||||
non_copyable(non_copyable&&) = default;
|
non_copyable(non_copyable&&) = default;
|
||||||
non_copyable(non_copyable const&) = delete;
|
non_copyable(non_copyable const&) = delete;
|
||||||
non_copyable() = default;
|
non_copyable() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE("Issue 42", "[issues.42]") {
|
TEST_CASE("Issue 42", "[issues.42]") {
|
||||||
tl::expected<non_copyable,int>{}.map([](non_copyable) {});
|
tl::expected<non_copyable,int>{}.map([](non_copyable) {});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Issue 43", "[issues.43]") {
|
TEST_CASE("Issue 43", "[issues.43]") {
|
||||||
auto result = tl::expected<void, std::string>{};
|
auto result = tl::expected<void, std::string>{};
|
||||||
result = tl::make_unexpected(std::string{ "foo" });
|
result = tl::make_unexpected(std::string{ "foo" });
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !(__GNUC__ <= 5)
|
#if !(__GNUC__ <= 5)
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using MaybeDataPtr = tl::expected<int, std::unique_ptr<int>>;
|
using MaybeDataPtr = tl::expected<int, std::unique_ptr<int>>;
|
||||||
|
|
||||||
MaybeDataPtr test(int i) noexcept
|
MaybeDataPtr test(int i) noexcept
|
||||||
{
|
{
|
||||||
return std::move(i);
|
return std::move(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeDataPtr test2(int i) noexcept
|
MaybeDataPtr test2(int i) noexcept
|
||||||
{
|
{
|
||||||
return std::move(i);
|
return std::move(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Issue 49", "[issues.49]") {
|
TEST_CASE("Issue 49", "[issues.49]") {
|
||||||
auto m = test(10)
|
auto m = test(10)
|
||||||
.and_then(test2);
|
.and_then(test2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
TEST_CASE("Noexcept", "[noexcept]") {
|
TEST_CASE("Noexcept", "[noexcept]") {
|
||||||
//TODO
|
//TODO
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
struct move_detector {
|
struct move_detector {
|
||||||
move_detector() = default;
|
move_detector() = default;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
TEST_CASE("Relational operators", "[relops]") {
|
TEST_CASE("Relational operators", "[relops]") {
|
||||||
//TODO
|
//TODO
|
||||||
|
200
tests/swap.cpp
200
tests/swap.cpp
@@ -1,101 +1,101 @@
|
|||||||
#include "catch.hpp"
|
#include "catch.hpp"
|
||||||
#include "expected.hpp"
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
struct no_throw {
|
struct no_throw {
|
||||||
no_throw(std::string i) : i(i) {}
|
no_throw(std::string i) : i(i) {}
|
||||||
std::string i;
|
std::string i;
|
||||||
};
|
};
|
||||||
struct canthrow_move {
|
struct canthrow_move {
|
||||||
canthrow_move(std::string i) : i(i) {}
|
canthrow_move(std::string i) : i(i) {}
|
||||||
canthrow_move(canthrow_move const &) = default;
|
canthrow_move(canthrow_move const &) = default;
|
||||||
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
||||||
canthrow_move &operator=(canthrow_move &&) = default;
|
canthrow_move &operator=(canthrow_move &&) = default;
|
||||||
std::string i;
|
std::string i;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool should_throw = false;
|
bool should_throw = false;
|
||||||
struct willthrow_move {
|
struct willthrow_move {
|
||||||
willthrow_move(std::string i) : i(i) {}
|
willthrow_move(std::string i) : i(i) {}
|
||||||
willthrow_move(willthrow_move const &) = default;
|
willthrow_move(willthrow_move const &) = default;
|
||||||
willthrow_move(willthrow_move &&other) : i(other.i) {
|
willthrow_move(willthrow_move &&other) : i(other.i) {
|
||||||
if (should_throw)
|
if (should_throw)
|
||||||
throw 0;
|
throw 0;
|
||||||
}
|
}
|
||||||
willthrow_move &operator=(willthrow_move &&) = default;
|
willthrow_move &operator=(willthrow_move &&) = default;
|
||||||
std::string i;
|
std::string i;
|
||||||
};
|
};
|
||||||
static_assert(tl::detail::is_swappable<no_throw>::value, "");
|
static_assert(tl::detail::is_swappable<no_throw>::value, "");
|
||||||
|
|
||||||
template <class T1, class T2> void swap_test() {
|
template <class T1, class T2> void swap_test() {
|
||||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcba";
|
std::string s2 = "zyxwvutsrqponmlkjihgfedcba";
|
||||||
|
|
||||||
tl::expected<T1, T2> a{s1};
|
tl::expected<T1, T2> a{s1};
|
||||||
tl::expected<T1, T2> b{s2};
|
tl::expected<T1, T2> b{s2};
|
||||||
swap(a, b);
|
swap(a, b);
|
||||||
REQUIRE(a->i == s2);
|
REQUIRE(a->i == s2);
|
||||||
REQUIRE(b->i == s1);
|
REQUIRE(b->i == s1);
|
||||||
|
|
||||||
a = s1;
|
a = s1;
|
||||||
b = tl::unexpected<T2>(s2);
|
b = tl::unexpected<T2>(s2);
|
||||||
swap(a, b);
|
swap(a, b);
|
||||||
REQUIRE(a.error().i == s2);
|
REQUIRE(a.error().i == s2);
|
||||||
REQUIRE(b->i == s1);
|
REQUIRE(b->i == s1);
|
||||||
|
|
||||||
a = tl::unexpected<T2>(s1);
|
a = tl::unexpected<T2>(s1);
|
||||||
b = s2;
|
b = s2;
|
||||||
swap(a, b);
|
swap(a, b);
|
||||||
REQUIRE(a->i == s2);
|
REQUIRE(a->i == s2);
|
||||||
REQUIRE(b.error().i == s1);
|
REQUIRE(b.error().i == s1);
|
||||||
|
|
||||||
a = tl::unexpected<T2>(s1);
|
a = tl::unexpected<T2>(s1);
|
||||||
b = tl::unexpected<T2>(s2);
|
b = tl::unexpected<T2>(s2);
|
||||||
swap(a, b);
|
swap(a, b);
|
||||||
REQUIRE(a.error().i == s2);
|
REQUIRE(a.error().i == s2);
|
||||||
REQUIRE(b.error().i == s1);
|
REQUIRE(b.error().i == s1);
|
||||||
|
|
||||||
a = s1;
|
a = s1;
|
||||||
b = s2;
|
b = s2;
|
||||||
a.swap(b);
|
a.swap(b);
|
||||||
REQUIRE(a->i == s2);
|
REQUIRE(a->i == s2);
|
||||||
REQUIRE(b->i == s1);
|
REQUIRE(b->i == s1);
|
||||||
|
|
||||||
a = s1;
|
a = s1;
|
||||||
b = tl::unexpected<T2>(s2);
|
b = tl::unexpected<T2>(s2);
|
||||||
a.swap(b);
|
a.swap(b);
|
||||||
REQUIRE(a.error().i == s2);
|
REQUIRE(a.error().i == s2);
|
||||||
REQUIRE(b->i == s1);
|
REQUIRE(b->i == s1);
|
||||||
|
|
||||||
a = tl::unexpected<T2>(s1);
|
a = tl::unexpected<T2>(s1);
|
||||||
b = s2;
|
b = s2;
|
||||||
a.swap(b);
|
a.swap(b);
|
||||||
REQUIRE(a->i == s2);
|
REQUIRE(a->i == s2);
|
||||||
REQUIRE(b.error().i == s1);
|
REQUIRE(b.error().i == s1);
|
||||||
|
|
||||||
a = tl::unexpected<T2>(s1);
|
a = tl::unexpected<T2>(s1);
|
||||||
b = tl::unexpected<T2>(s2);
|
b = tl::unexpected<T2>(s2);
|
||||||
a.swap(b);
|
a.swap(b);
|
||||||
REQUIRE(a.error().i == s2);
|
REQUIRE(a.error().i == s2);
|
||||||
REQUIRE(b.error().i == s1);
|
REQUIRE(b.error().i == s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("swap") {
|
TEST_CASE("swap") {
|
||||||
|
|
||||||
swap_test<no_throw, no_throw>();
|
swap_test<no_throw, no_throw>();
|
||||||
swap_test<no_throw, canthrow_move>();
|
swap_test<no_throw, canthrow_move>();
|
||||||
swap_test<canthrow_move, no_throw>();
|
swap_test<canthrow_move, no_throw>();
|
||||||
|
|
||||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
||||||
tl::expected<no_throw, willthrow_move> a{s1};
|
tl::expected<no_throw, willthrow_move> a{s1};
|
||||||
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
||||||
should_throw = 1;
|
should_throw = 1;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
//this seems to break catch on GCC and Clang
|
//this seems to break catch on GCC and Clang
|
||||||
REQUIRE_THROWS(swap(a, b));
|
REQUIRE_THROWS(swap(a, b));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
REQUIRE(a->i == s1);
|
REQUIRE(a->i == s1);
|
||||||
REQUIRE(b.error().i == s2);
|
REQUIRE(b.error().i == s2);
|
||||||
}
|
}
|
@@ -1,32 +1,32 @@
|
|||||||
struct no_throw {
|
struct no_throw {
|
||||||
no_throw(std::string i) : i(i) {}
|
no_throw(std::string i) : i(i) {}
|
||||||
std::string i;
|
std::string i;
|
||||||
};
|
};
|
||||||
struct canthrow_move {
|
struct canthrow_move {
|
||||||
canthrow_move(std::string i) : i(i) {}
|
canthrow_move(std::string i) : i(i) {}
|
||||||
canthrow_move(canthrow_move const &) = default;
|
canthrow_move(canthrow_move const &) = default;
|
||||||
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
||||||
canthrow_move &operator=(canthrow_move &&) = default;
|
canthrow_move &operator=(canthrow_move &&) = default;
|
||||||
std::string i;
|
std::string i;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool should_throw = false;
|
bool should_throw = false;
|
||||||
struct willthrow_move {
|
struct willthrow_move {
|
||||||
willthrow_move(std::string i) : i(i) {}
|
willthrow_move(std::string i) : i(i) {}
|
||||||
willthrow_move(willthrow_move const &) = default;
|
willthrow_move(willthrow_move const &) = default;
|
||||||
willthrow_move(willthrow_move &&other) : i(other.i) {
|
willthrow_move(willthrow_move &&other) : i(other.i) {
|
||||||
if (should_throw)
|
if (should_throw)
|
||||||
throw 0;
|
throw 0;
|
||||||
}
|
}
|
||||||
willthrow_move &operator=(willthrow_move &&) = default;
|
willthrow_move &operator=(willthrow_move &&) = default;
|
||||||
std::string i;
|
std::string i;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
||||||
tl::expected<no_throw, willthrow_move> a{s1};
|
tl::expected<no_throw, willthrow_move> a{s1};
|
||||||
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
||||||
should_throw = 1;
|
should_throw = 1;
|
||||||
swap(a, b);
|
swap(a, b);
|
||||||
}
|
}
|
Reference in New Issue
Block a user