mirror of
https://github.com/TartanLlama/expected.git
synced 2025-08-02 18:34:29 +02:00
Merge in changes from master
This commit is contained in:
@@ -254,4 +254,4 @@ install:
|
|||||||
- if [ "$CXX" = "clang++" ]; then export CXX="$COMPILER -stdlib=libc++"; fi
|
- if [ "$CXX" = "clang++" ]; then export CXX="$COMPILER -stdlib=libc++"; fi
|
||||||
- if [ "$CXX" = "g++" ]; then export CXX="$COMPILER"; fi
|
- if [ "$CXX" = "g++" ]; then export CXX="$COMPILER"; fi
|
||||||
|
|
||||||
script: mkdir build && cd build && cmake .. && make && ./tests
|
script: mkdir build && cd build && cmake -DCXXSTD=$CXXSTD .. && make && ./tests
|
||||||
|
34
conanfile.py
Normal file
34
conanfile.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from conans import ConanFile, CMake, tools
|
||||||
|
|
||||||
|
class ExpectedConan(ConanFile):
|
||||||
|
name = "expected"
|
||||||
|
version = "master"
|
||||||
|
license = "CC0-1.0"
|
||||||
|
author = "Simon Brand <tartanllama@gmail.com>"
|
||||||
|
url = "https://github.com/TartanLlama/expected"
|
||||||
|
description = "C++11/14/17 std::expected with functional-style extensions"
|
||||||
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
|
generators = "cmake"
|
||||||
|
exports_sources = "*"
|
||||||
|
|
||||||
|
def source(self):
|
||||||
|
tools.replace_in_file('CMakeLists.txt', 'project(expected)',
|
||||||
|
'''project(expected)
|
||||||
|
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||||
|
conan_basic_setup()
|
||||||
|
''')
|
||||||
|
|
||||||
|
def configure_cmake(self):
|
||||||
|
cmake = CMake(self)
|
||||||
|
cmake.configure()
|
||||||
|
return cmake
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
cmake = self.configure_cmake()
|
||||||
|
cmake.build()
|
||||||
|
|
||||||
|
if not tools.cross_building(self.settings):
|
||||||
|
self.run('%s/bin/tests' % self.build_folder)
|
||||||
|
|
||||||
|
def package(self):
|
||||||
|
self.copy('*.hpp', dst='include/tl', src='tl')
|
14
test_package/CMakeLists.txt
Normal file
14
test_package/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
|
project(PackageTest CXX)
|
||||||
|
|
||||||
|
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||||
|
conan_basic_setup()
|
||||||
|
|
||||||
|
add_executable(example example.cpp)
|
||||||
|
target_link_libraries(example ${CONAN_LIBS})
|
||||||
|
|
||||||
|
# CTest is a testing tool that can be used to test your project.
|
||||||
|
# enable_testing()
|
||||||
|
# add_test(NAME example
|
||||||
|
# WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||||
|
# COMMAND example)
|
25
test_package/conanfile.py
Normal file
25
test_package/conanfile.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from conans import ConanFile, CMake, tools
|
||||||
|
|
||||||
|
|
||||||
|
class ExpectedTestConan(ConanFile):
|
||||||
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
|
generators = "cmake"
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
cmake = CMake(self)
|
||||||
|
# Current dir is "test_package/build/<build_id>" and CMakeLists.txt is
|
||||||
|
# in "test_package"
|
||||||
|
cmake.configure()
|
||||||
|
cmake.build()
|
||||||
|
|
||||||
|
def imports(self):
|
||||||
|
self.copy("*.dll", dst="bin", src="bin")
|
||||||
|
self.copy("*.dylib*", dst="bin", src="lib")
|
||||||
|
self.copy('*.so*', dst='bin', src='lib')
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
if not tools.cross_building(self.settings):
|
||||||
|
os.chdir("bin")
|
||||||
|
self.run(".%sexample" % os.sep)
|
16
test_package/example.cpp
Normal file
16
test_package/example.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include <tl/expected.hpp>
|
||||||
|
|
||||||
|
tl::expected<int, const char*> maybe_do_something(int i) {
|
||||||
|
if (i < 5) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return tl::make_unexpected("Uh oh");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
return maybe_do_something(0).value_or(-1);
|
||||||
|
}
|
@@ -106,3 +106,24 @@ 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)
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using MaybeDataPtr = tl::expected<int, std::unique_ptr<int>>;
|
||||||
|
|
||||||
|
MaybeDataPtr test(int i) noexcept
|
||||||
|
{
|
||||||
|
return std::move(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeDataPtr test2(int i) noexcept
|
||||||
|
{
|
||||||
|
return std::move(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Issue 49", "[issues.49]") {
|
||||||
|
auto m = test(10)
|
||||||
|
.and_then(test2);
|
||||||
|
}
|
||||||
|
#endif
|
32
tests/test.cpp
Normal file
32
tests/test.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
struct no_throw {
|
||||||
|
no_throw(std::string i) : i(i) {}
|
||||||
|
std::string i;
|
||||||
|
};
|
||||||
|
struct canthrow_move {
|
||||||
|
canthrow_move(std::string i) : i(i) {}
|
||||||
|
canthrow_move(canthrow_move const &) = default;
|
||||||
|
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i) {}
|
||||||
|
canthrow_move &operator=(canthrow_move &&) = default;
|
||||||
|
std::string i;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool should_throw = false;
|
||||||
|
struct willthrow_move {
|
||||||
|
willthrow_move(std::string i) : i(i) {}
|
||||||
|
willthrow_move(willthrow_move const &) = default;
|
||||||
|
willthrow_move(willthrow_move &&other) : i(other.i) {
|
||||||
|
if (should_throw)
|
||||||
|
throw 0;
|
||||||
|
}
|
||||||
|
willthrow_move &operator=(willthrow_move &&) = default;
|
||||||
|
std::string i;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
||||||
|
tl::expected<no_throw, willthrow_move> a{s1};
|
||||||
|
tl::expected<no_throw, willthrow_move> b{tl::unexpect, s2};
|
||||||
|
should_throw = 1;
|
||||||
|
swap(a, b);
|
||||||
|
}
|
@@ -460,9 +460,9 @@ struct expected_storage_base {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
union {
|
union {
|
||||||
char m_no_init;
|
|
||||||
T m_val;
|
T m_val;
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
char m_no_init;
|
||||||
};
|
};
|
||||||
bool m_has_val;
|
bool m_has_val;
|
||||||
};
|
};
|
||||||
@@ -501,9 +501,9 @@ template <class T, class E> struct expected_storage_base<T, E, true, true> {
|
|||||||
|
|
||||||
~expected_storage_base() = default;
|
~expected_storage_base() = default;
|
||||||
union {
|
union {
|
||||||
char m_no_init;
|
|
||||||
T m_val;
|
T m_val;
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
char m_no_init;
|
||||||
};
|
};
|
||||||
bool m_has_val;
|
bool m_has_val;
|
||||||
};
|
};
|
||||||
@@ -547,9 +547,9 @@ template <class T, class E> struct expected_storage_base<T, E, true, false> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
union {
|
union {
|
||||||
char m_no_init;
|
|
||||||
T m_val;
|
T m_val;
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
char m_no_init;
|
||||||
};
|
};
|
||||||
bool m_has_val;
|
bool m_has_val;
|
||||||
};
|
};
|
||||||
@@ -591,9 +591,9 @@ template <class T, class E> struct expected_storage_base<T, E, false, true> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
union {
|
union {
|
||||||
char m_no_init;
|
|
||||||
T m_val;
|
T m_val;
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
char m_no_init;
|
||||||
};
|
};
|
||||||
bool m_has_val;
|
bool m_has_val;
|
||||||
};
|
};
|
||||||
@@ -622,8 +622,8 @@ template <class E> struct expected_storage_base<void, E, false, true> {
|
|||||||
~expected_storage_base() = default;
|
~expected_storage_base() = default;
|
||||||
struct dummy {};
|
struct dummy {};
|
||||||
union {
|
union {
|
||||||
dummy m_val;
|
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
dummy m_val;
|
||||||
};
|
};
|
||||||
bool m_has_val;
|
bool m_has_val;
|
||||||
};
|
};
|
||||||
@@ -656,8 +656,8 @@ template <class E> struct expected_storage_base<void, E, false, false> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
union {
|
union {
|
||||||
char m_dummy;
|
|
||||||
unexpected<E> m_unexpect;
|
unexpected<E> m_unexpect;
|
||||||
|
char m_dummy;
|
||||||
};
|
};
|
||||||
bool m_has_val;
|
bool m_has_val;
|
||||||
};
|
};
|
||||||
@@ -837,7 +837,7 @@ struct expected_operations_base : expected_storage_base<T, E> {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr void destroy_val() {
|
TL_EXPECTED_11_CONSTEXPR void destroy_val() {
|
||||||
get().~T();
|
get().~T();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -892,7 +892,7 @@ struct expected_operations_base<void, E> : expected_storage_base<void, E> {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
constexpr void destroy_val() {
|
TL_EXPECTED_11_CONSTEXPR void destroy_val() {
|
||||||
//no-op
|
//no-op
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1229,17 +1229,17 @@ class expected : private detail::expected_move_assign_base<T, E>,
|
|||||||
|
|
||||||
template <class U = T,
|
template <class U = T,
|
||||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||||
U &val() {
|
TL_EXPECTED_11_CONSTEXPR U &val() {
|
||||||
return this->m_val;
|
return this->m_val;
|
||||||
}
|
}
|
||||||
unexpected<E> &err() { return this->m_unexpect; }
|
TL_EXPECTED_11_CONSTEXPR unexpected<E> &err() { return this->m_unexpect; }
|
||||||
|
|
||||||
template <class U = T,
|
template <class U = T,
|
||||||
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
detail::enable_if_t<!std::is_void<U>::value> * = nullptr>
|
||||||
const U &val() const {
|
constexpr const U &val() const {
|
||||||
return this->m_val;
|
return this->m_val;
|
||||||
}
|
}
|
||||||
const unexpected<E> &err() const { return this->m_unexpect; }
|
constexpr const unexpected<E> &err() const { return this->m_unexpect; }
|
||||||
|
|
||||||
using impl_base = detail::expected_move_assign_base<T, E>;
|
using impl_base = detail::expected_move_assign_base<T, E>;
|
||||||
using ctor_base = detail::expected_default_ctor_base<T, E>;
|
using ctor_base = detail::expected_default_ctor_base<T, E>;
|
||||||
@@ -1296,7 +1296,7 @@ public:
|
|||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &;
|
||||||
template <class F>
|
template <class F>
|
||||||
TL_EXPECTED_11_CONSTEXPR auto
|
TL_EXPECTED_11_CONSTEXPR auto
|
||||||
and_then(F &&f) & -> decltype(and_then_impl(*this, std::forward<F>(f))) {
|
and_then(F &&f) & -> decltype(and_then_impl(std::declval<expected&>(), std::forward<F>(f))) {
|
||||||
return and_then_impl(*this, std::forward<F>(f));
|
return and_then_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1304,7 +1304,7 @@ public:
|
|||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&;
|
||||||
template <class F>
|
template <class F>
|
||||||
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(
|
TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype(
|
||||||
and_then_impl(std::move(*this), std::forward<F>(f))) {
|
and_then_impl(std::declval<expected&&>(), std::forward<F>(f))) {
|
||||||
return and_then_impl(std::move(*this), std::forward<F>(f));
|
return and_then_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1312,7 +1312,7 @@ public:
|
|||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &;
|
||||||
template <class F>
|
template <class F>
|
||||||
constexpr auto and_then(F &&f) const & -> decltype(
|
constexpr auto and_then(F &&f) const & -> decltype(
|
||||||
and_then_impl(*this, std::forward<F>(f))) {
|
and_then_impl(std::declval<expected const&>(), std::forward<F>(f))) {
|
||||||
return and_then_impl(*this, std::forward<F>(f));
|
return and_then_impl(*this, std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1321,7 +1321,7 @@ public:
|
|||||||
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
/// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&;
|
||||||
template <class F>
|
template <class F>
|
||||||
constexpr auto and_then(F &&f) const && -> decltype(
|
constexpr auto and_then(F &&f) const && -> decltype(
|
||||||
and_then_impl(std::move(*this), std::forward<F>(f))) {
|
and_then_impl(std::declval<expected const&&>(), std::forward<F>(f))) {
|
||||||
return and_then_impl(std::move(*this), std::forward<F>(f));
|
return and_then_impl(std::move(*this), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -2053,7 +2053,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) {
|
|||||||
|
|
||||||
return exp.has_value()
|
return exp.has_value()
|
||||||
? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
|
? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
|
||||||
: Ret(unexpect, exp.error());
|
: Ret(unexpect, std::forward<Exp>(exp).error());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
@@ -2063,7 +2063,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) {
|
|||||||
static_assert(detail::is_expected<Ret>::value, "F must return an expected");
|
static_assert(detail::is_expected<Ret>::value, "F must return an expected");
|
||||||
|
|
||||||
return exp.has_value() ? detail::invoke(std::forward<F>(f))
|
return exp.has_value() ? detail::invoke(std::forward<F>(f))
|
||||||
: Ret(unexpect, exp.error());
|
: Ret(unexpect, std::forward<Exp>(exp).error());
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template <class> struct TC;
|
template <class> struct TC;
|
||||||
@@ -2076,7 +2076,7 @@ auto and_then_impl(Exp &&exp, F &&f) -> Ret {
|
|||||||
|
|
||||||
return exp.has_value()
|
return exp.has_value()
|
||||||
? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
|
? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp))
|
||||||
: Ret(unexpect, exp.error());
|
: Ret(unexpect, std::forward<Exp>(exp).error());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Exp, class F,
|
template <class Exp, class F,
|
||||||
@@ -2086,7 +2086,7 @@ constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret {
|
|||||||
static_assert(detail::is_expected<Ret>::value, "F must return an expected");
|
static_assert(detail::is_expected<Ret>::value, "F must return an expected");
|
||||||
|
|
||||||
return exp.has_value() ? detail::invoke(std::forward<F>(f))
|
return exp.has_value() ? detail::invoke(std::forward<F>(f))
|
||||||
: Ret(unexpect, exp.error());
|
: Ret(unexpect, std::forward<Exp>(exp).error());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user