diff --git a/.circleci/config.yml b/.circleci/config.yml index 9b45b568..f9194ef6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -90,12 +90,12 @@ references: restore_cache: keys: # Find the most recent cache from any branch - - v3_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }} + - v4_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }} upgrade_boost_post: &upgrade_boost_post save_cache: - key: v3_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }} + key: v4_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }} paths: - - /tmp/boost_1_57_0 + - /tmp/boost_1_58_0 upgrade_boost: &upgrade_boost run: name: Upgrade Boost @@ -104,10 +104,10 @@ references: export NUMCORES=`nproc` echo Using $NUMCORES cores # Download and prepare boost (only if not already present from cache) - if [ ! -d "/tmp/boost_1_57_0" ]; then + if [ ! -d "/tmp/boost_1_58_0" ]; then echo "Didn't find boost in cache. Downloading and building." - wget -O /tmp/boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.57.0/boost_1_57_0.tar.bz2/download - if [ $(sha512sum /tmp/boost.tar.bz2 | awk '{print $1;}') == "61881440fd89644c43c6e3bc6292e9fed75a6d3a76f98654b189d0ed4e1087d77b585884e882270c08bf9f7132b173bfc1fde05848e06aa78ba7f1008d10714d" ]; then + wget -O /tmp/boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.58.0/boost_1_58_0.tar.bz2/download + if [ $(sha512sum /tmp/boost.tar.bz2 | awk '{print $1;}') == "7480ec713b0aa13f0ec990603e87e3b5c8d53f4411329b10fae37fc963b90aad12dbd9290a33c3669ae801e9012a68683eadff057591e9ca2ebcd22b1a67b5d1" ]; then echo Correct sha512sum else echo Wrong sha512sum @@ -117,14 +117,14 @@ references: echo Extracting... tar -xf /tmp/boost.tar.bz2 -C /tmp rm -rf boost.tar.bz2 - cd /tmp/boost_1_57_0 + cd /tmp/boost_1_58_0 ./bootstrap.sh --with-toolset=${BUILD_TOOLSET} --with-libraries=filesystem,thread,chrono,program_options cd .. else echo Found boost in cache. Use cache and build. fi # Compile and install boost (if cached, this should be fast) - cd /tmp/boost_1_57_0 + cd /tmp/boost_1_58_0 sudo ./b2 toolset=${BUILD_TOOLSET} link=static cxxflags=-fPIC -d0 -j$NUMCORES install build_pre: &build_pre restore_cache: diff --git a/README.md b/README.md index fc2a26f0..58e6fa40 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Requirements - GCC version >= 5.0 or Clang >= 4.0 - CMake version >= 3.0 - libcurl4 (including development headers) - - Boost libraries version >= 1.57 (including development headers) + - Boost libraries version >= 1.58 (including development headers) - filesystem - system - chrono diff --git a/cmake-utils/utils.cmake b/cmake-utils/utils.cmake index 72cac168..6648871c 100644 --- a/cmake-utils/utils.cmake +++ b/cmake-utils/utils.cmake @@ -108,7 +108,7 @@ endfunction(target_enable_style_warnings) function(target_add_boost TARGET) # Load boost libraries if(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS) - # Many supported systems don't have boost >= 1.57. Better link it statically. + # Many supported systems don't have boost >= 1.58. Better link it statically. message(STATUS "Boost will be statically linked") set(Boost_USE_STATIC_LIBS ON) else(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS) @@ -116,7 +116,7 @@ function(target_add_boost TARGET) set(Boost_USE_STATIC_LIBS OFF) endif(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS) set(BOOST_THREAD_VERSION 4) - find_package(Boost 1.57.0 + find_package(Boost 1.58.0 REQUIRED COMPONENTS ${ARGN}) target_include_directories(${TARGET} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) diff --git a/src/cpp-utils/either.h b/src/cpp-utils/either.h index 98cc13f3..bca422a2 100644 --- a/src/cpp-utils/either.h +++ b/src/cpp-utils/either.h @@ -8,217 +8,224 @@ namespace cpputils { -template -class either final { -public: - template::value && !std::is_constructible::value>* = nullptr> - either(Head&& construct_left_head_arg, Tail&&... construct_left_tail_args) noexcept(noexcept(std::declval>()._construct_left(std::forward(construct_left_head_arg), std::forward(construct_left_tail_args)...))) - : _side(Side::left) { - _construct_left(std::forward(construct_left_head_arg), std::forward(construct_left_tail_args)...); - } + template + class either final { + public: + template::value && !std::is_constructible::value>* = nullptr> + either(Head&& construct_left_head_arg, Tail&&... construct_left_tail_args) noexcept(noexcept(std::declval>()._construct_left(std::forward(construct_left_head_arg), std::forward(construct_left_tail_args)...))) + : _side(Side::left) { + _construct_left(std::forward(construct_left_head_arg), std::forward(construct_left_tail_args)...); + } - template::value && std::is_constructible::value>* = nullptr> - either(Head&& construct_right_head_arg, Tail&&... construct_right_tail_args) noexcept(noexcept(std::declval>()._construct_right(std::forward(construct_right_head_arg), std::forward(construct_right_tail_args)...))) - : _side(Side::right) { - _construct_right(std::forward(construct_right_head_arg), std::forward(construct_right_tail_args)...); - } + template::value && std::is_constructible::value>* = nullptr> + either(Head&& construct_right_head_arg, Tail&&... construct_right_tail_args) noexcept(noexcept(std::declval>()._construct_right(std::forward(construct_right_head_arg), std::forward(construct_right_tail_args)...))) + : _side(Side::right) { + _construct_right(std::forward(construct_right_head_arg), std::forward(construct_right_tail_args)...); + } - //TODO Try allowing copy-construction when Left/Right types are std::is_convertible - either(const either &rhs) noexcept(noexcept(std::declval>()._construct_left(rhs._left)) && noexcept(std::declval>()._construct_right(rhs._right))) - : _side(rhs._side) { - if(_side == Side::left) { - _construct_left(rhs._left); - } else { - _construct_right(rhs._right); + //TODO Try allowing copy-construction when Left/Right types are std::is_convertible + either(const either &rhs) noexcept(noexcept(std::declval>()._construct_left(rhs._left)) && noexcept(std::declval>()._construct_right(rhs._right))) + : _side(rhs._side) { + if(_side == Side::left) { + _construct_left(rhs._left); + } else { + _construct_right(rhs._right); + } + } + + either(either &&rhs) noexcept(noexcept(_construct_left(std::move(rhs._left))) && noexcept(_construct_right(std::move(rhs._right)))) + : _side(rhs._side) { + if(_side == Side::left) { + _construct_left(std::move(rhs._left)); + } else { + _construct_right(std::move(rhs._right)); + } + } + + ~either() { + _destruct(); + } + + //TODO Try allowing copy-assignment when Left/Right types are std::is_convertible + either &operator=(const either &rhs) noexcept(noexcept(_construct_left(rhs._left)) && noexcept(_construct_right(rhs._right))) { + _destruct(); + _side = rhs._side; + if (_side == Side::left) { + _construct_left(rhs._left); + } else { + _construct_right(rhs._right); + } + return *this; + } + + either &operator=(either &&rhs) noexcept(noexcept(_construct_left(std::move(rhs._left))) && noexcept(_construct_right(std::move(rhs._right)))) { + _destruct(); + _side = rhs._side; + if (_side == Side::left) { + _construct_left(std::move(rhs._left)); + } else { + _construct_right(std::move(rhs._right)); + } + return *this; + } + + //TODO fold, map_left, map_right, left_or_else(val), right_or_else(val), left_or_else(func), right_or_else(func) + + bool is_left() const noexcept { + return _side == Side::left; + } + + bool is_right() const noexcept { + return _side == Side::right; + } + + const Left &left() const& { + if (!is_left()) { + throw std::logic_error("Tried to get left side of an either which is right."); + } + return _left; + } + Left &left() & { + return const_cast(const_cast*>(this)->left()); + } + Left &&left() && { + return std::move(left()); + } + + const Right &right() const& { + if (!is_right()) { + throw std::logic_error("Tried to get right side of an either which is left."); + } + return _right; + } + Right &right() & { + return const_cast(const_cast*>(this)->right()); + } + Right &&right() && { + return std::move(right()); + } + + boost::optional left_opt() const& noexcept { + if (_side == Side::left) { + return _left; + } else { + return boost::none; + } + } + boost::optional left_opt() & noexcept { + if (_side == Side::left) { + return _left; + } else { + return boost::none; + } + } + // warning: opposed to the other left_opt variants, this one already moves the content and returns by value. + boost::optional left_opt() && noexcept(noexcept(boost::optional(std::move(_left)))) { + if (_side == Side::left) { + return std::move(_left); + } else { + return boost::none; + } + } + + + boost::optional right_opt() const& noexcept { + if (_side == Side::right) { + return _right; + } else { + return boost::none; + } + } + boost::optional right_opt() & noexcept { + if (_side == Side::right) { + return _right; + } else { + return boost::none; + } + } + // warning: opposed to the other left_opt variants, this one already moves the content and returns by value. + boost::optional right_opt() && noexcept(noexcept(boost::optional(std::move(_right)))) { + if (_side == Side::right) { + return std::move(_right); + } else { + return boost::none; + } + } + + + + private: + union { + Left _left; + Right _right; + }; + enum class Side : uint8_t {left, right} _side; + + explicit either(Side side) noexcept : _side(side) {} + + template + void _construct_left(Args&&... args) noexcept(noexcept(new Left(std::forward(args)...))) { + new(&_left)Left(std::forward(args)...); + } + template + void _construct_right(Args&&... args) noexcept(noexcept(new Right(std::forward(args)...))) { + new(&_right)Right(std::forward(args)...); + } + void _destruct() noexcept { + if (_side == Side::left) { + _left.~Left(); + } else { + _right.~Right(); + } + } + + template + friend either make_left(Args&&... args) /* TODO noexcept(noexcept(std::declval>()._construct_left(std::forward(args)...))) */; + + template + friend either make_right(Args&&... args) /* TODO noexcept(noexcept(std::declval>()._construct_right(std::forward(args)...))) */; + }; + + template + inline bool operator==(const either &lhs, const either &rhs) noexcept(noexcept(std::declval() == std::declval()) && noexcept(std::declval() == std::declval())) { + if (lhs.is_left() != rhs.is_left()) { + return false; + } + if (lhs.is_left()) { + return lhs.left() == rhs.left(); + } else { + return lhs.right() == rhs.right(); + } } - } - either(either &&rhs) noexcept(noexcept(_construct_left(std::move(rhs._left))) && noexcept(_construct_right(std::move(rhs._right)))) - : _side(rhs._side) { - if(_side == Side::left) { - _construct_left(std::move(rhs._left)); - } else { - _construct_right(std::move(rhs._right)); + template + inline bool operator!=(const either &lhs, const either &rhs) noexcept(noexcept(operator==(lhs, rhs))) { + return !operator==(lhs, rhs); } - } - ~either() { - _destruct(); - } - - //TODO Try allowing copy-assignment when Left/Right types are std::is_convertible - either &operator=(const either &rhs) noexcept(noexcept(_construct_left(rhs._left)) && noexcept(_construct_right(rhs._right))) { - _destruct(); - _side = rhs._side; - if (_side == Side::left) { - _construct_left(rhs._left); - } else { - _construct_right(rhs._right); + template + inline std::ostream &operator<<(std::ostream &stream, const either &value) { + if (value.is_left()) { + stream << "Left(" << value.left() << ")"; + } else { + stream << "Right(" << value.right() << ")"; + } + return stream; } - return *this; - } - either &operator=(either &&rhs) noexcept(noexcept(_construct_left(std::move(rhs._left))) && noexcept(_construct_right(std::move(rhs._right)))) { - _destruct(); - _side = rhs._side; - if (_side == Side::left) { - _construct_left(std::move(rhs._left)); - } else { - _construct_right(std::move(rhs._right)); + template + inline either make_left(Args&&... args) /* TODO noexcept(noexcept(std::declval>()._construct_left(std::forward(args)...))) */ { + either result(either::Side::left); + result._construct_left(std::forward(args)...); + return result; } - return *this; - } - //TODO fold, map_left, map_right, left_or_else(val), right_or_else(val), left_or_else(func), right_or_else(func) - - bool is_left() const noexcept { - return _side == Side::left; - } - - bool is_right() const noexcept { - return _side == Side::right; - } - - const Left &left() const& { - ASSERT(is_left(), "Tried to get left side of an either which is right."); - return _left; - } - Left &left() & { - return const_cast(const_cast*>(this)->left()); - } - Left &&left() && { - return std::move(left()); - } - - const Right &right() const& { - ASSERT(is_right(), "Tried to get right side of an either which is left."); - return _right; - } - Right &right() & { - return const_cast(const_cast*>(this)->right()); - } - Right &&right() && { - return std::move(right()); - } - - boost::optional left_opt() const& noexcept { - if (_side == Side::left) { - return _left; - } else { - return boost::none; + template + inline either make_right(Args&&... args) /* TODO noexcept(noexcept(std::declval>()._construct_right(std::forward(args)...))) */ { + either result(either::Side::right); + result._construct_right(std::forward(args)...); + return result; } - } - boost::optional left_opt() & noexcept { - if (_side == Side::left) { - return _left; - } else { - return boost::none; - } - } - // warning: opposed to the other left_opt variants, this one already moves the content and returns by value. - boost::optional left_opt() && noexcept(noexcept(boost::optional(std::move(_left)))) { - if (_side == Side::left) { - return std::move(_left); - } else { - return boost::none; - } - } - - boost::optional right_opt() const& noexcept { - if (_side == Side::right) { - return _right; - } else { - return boost::none; - } - } - boost::optional right_opt() & noexcept { - if (_side == Side::right) { - return _right; - } else { - return boost::none; - } - } - // warning: opposed to the other left_opt variants, this one already moves the content and returns by value. - boost::optional right_opt() && noexcept(noexcept(boost::optional(std::move(_right)))) { - if (_side == Side::right) { - return std::move(_right); - } else { - return boost::none; - } - } - -private: - union { - Left _left; - Right _right; - }; - enum class Side : uint8_t {left, right} _side; - - explicit either(Side side) noexcept : _side(side) {} - - template - void _construct_left(Args&&... args) noexcept(noexcept(new Left(std::forward(args)...))) { - new(&_left)Left(std::forward(args)...); - } - template - void _construct_right(Args&&... args) noexcept(noexcept(new Right(std::forward(args)...))) { - new(&_right)Right(std::forward(args)...); - } - void _destruct() noexcept { - if (_side == Side::left) { - _left.~Left(); - } else { - _right.~Right(); - } - } - - template - friend either make_left(Args&&... args) /* TODO noexcept(noexcept(std::declval>()._construct_left(std::forward(args)...))) */; - - template - friend either make_right(Args&&... args) /* TODO noexcept(noexcept(std::declval>()._construct_right(std::forward(args)...))) */; -}; - -template -inline bool operator==(const either &lhs, const either &rhs) noexcept(noexcept(std::declval() == std::declval()) && noexcept(std::declval() == std::declval())) { - if (lhs.is_left() != rhs.is_left()) { - return false; - } - if (lhs.is_left()) { - return lhs.left() == rhs.left(); - } else { - return lhs.right() == rhs.right(); - } -} - -template -inline bool operator!=(const either &lhs, const either &rhs) noexcept(noexcept(operator==(lhs, rhs))) { - return !operator==(lhs, rhs); -} - -template -inline std::ostream &operator<<(std::ostream &stream, const either &value) { - if (value.is_left()) { - stream << "Left(" << value.left() << ")"; - } else { - stream << "Right(" << value.right() << ")"; - } - return stream; -} - -template -inline either make_left(Args&&... args) /* TODO noexcept(noexcept(std::declval>()._construct_left(std::forward(args)...))) */ { - either result(either::Side::left); - result._construct_left(std::forward(args)...); - return result; -} - -template -inline either make_right(Args&&... args) /* TODO noexcept(noexcept(std::declval>()._construct_right(std::forward(args)...))) */ { - either result(either::Side::right); - result._construct_right(std::forward(args)...); - return result; -} }