Do CMake properly

This commit is contained in:
Simon Brand
2019-05-01 12:15:40 +01:00
parent 2c9780949d
commit 90ed23a4e4
19 changed files with 285 additions and 276 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "cmake/tl-cmake"]
path = cmake/tl-cmake
url = https://github.com/TartanLlama/tl-cmake.git

View File

@ -1,12 +1,14 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.8)
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) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/tl-cmake" ${CMAKE_MODULE_PATH})
target_sources(expected INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/tl/expected.hpp) include(add-tl)
target_include_directories(expected INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/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

Submodule cmake/tl-cmake added at 284c6a3f0f

View File

@ -0,0 +1,3 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/tl-expected-targets.cmake")

View File

@ -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')

BIN
include/tl/expected.hpp.gch Normal file

Binary file not shown.

View File

@ -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;

View File

@ -1,5 +1,5 @@
#include "catch.hpp" #include "catch.hpp"
#include "expected.hpp" #include <tl/expected.hpp>
#include <string> #include <string>

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
} }

View File

@ -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);
} }