Skip to content

Commit

Permalink
Containers: STL compatibility for Optional.
Browse files Browse the repository at this point in the history
  • Loading branch information
mosra committed Jan 26, 2019
1 parent 9eb8e3c commit 69e6593
Show file tree
Hide file tree
Showing 10 changed files with 373 additions and 3 deletions.
2 changes: 2 additions & 0 deletions doc/corrade-changelog.dox
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ namespace Corrade {
initialization
- Added r-value overloads to @ref Containers::Optional::operator*() allowing
you to easily take the value out of a r-value optional
- Opt-in STL compatibility for @ref Containers::Optional, allowing for
*explicit* conversion from and to @cpp std::optional @ce in C++17.
- New @ref Containers::arrayCast(StridedArrayView<T>) overload for casting
strided array views

Expand Down
14 changes: 14 additions & 0 deletions doc/snippets/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ add_library(snippets STATIC
target_link_libraries(snippets PRIVATE CorradeUtility)
set_target_properties(snippets PROPERTIES FOLDER "Corrade/doc/snippets")

# Copied verbatim from src/Corrade/Test/CMakeLists.txt, please keep in sync
# (especially for AppleClang)
if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "7.0") OR
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0") OR
#(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "10.0") OR
(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.10"))
add_library(snippets-cpp17 STATIC
Containers-stl17.cpp)
target_link_libraries(snippets-cpp17 PRIVATE CorradeUtility)
set_target_properties(snippets-cpp17 PROPERTIES
CORRADE_CXX_STANDARD 17
FOLDER "Corrade/doc/snippets")
endif()

if(WITH_INTERCONNECT)
add_library(snippets-Interconnect STATIC Interconnect.cpp)
target_link_libraries(snippets-Interconnect PRIVATE CorradeInterconnect)
Expand Down
39 changes: 39 additions & 0 deletions doc/snippets/Containers-stl17.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
This file is part of Corrade.
Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
2017, 2018, 2019 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#include "Corrade/Containers/OptionalStl.h"

using namespace Corrade;

int main() {
{
/* [Optional] */
std::optional<int> a{5};
Containers::Optional<int> b(a);

std::optional<std::string> c(Containers::optional<std::string>("hello"));
/* [Optional] */
}
}
1 change: 1 addition & 0 deletions src/Corrade/Containers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ set(CorradeContainers_HEADERS
EnumSet.hpp
LinkedList.h
Optional.h
OptionalStl.h
Pointer.h
PointerStl.h
Reference.h
Expand Down
33 changes: 33 additions & 0 deletions src/Corrade/Containers/Optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

/** @file
* @brief Class @ref Corrade::Containers::Optional, tag type @ref Corrade::Containers::NullOptT, tag @ref Corrade::Containers::NullOpt, function @ref Corrade::Containers::optional()
* @see @ref Corrade/Containers/OptionalStl.h
*/

#include <new>
Expand All @@ -41,6 +42,10 @@

namespace Corrade { namespace Containers {

namespace Implementation {
template<class> struct OptionalConverter;
}

/**
@brief Null optional initialization tag type
Expand Down Expand Up @@ -80,6 +85,18 @@ Unlike `std::optional`, this class does not provide a @cpp constexpr @ce
implementation or ordering operators, which makes it fairly simple and
lightweight. If you need the extra features, use the standard `std::optional`.
@section Containers-Optional-stl STL compatibility
Instances of @ref Optional are *explicitly* copy- and move-convertible to and
from @cpp std::optional @ce if you include @ref Corrade/Containers/OptionalStl.h
and build your code with C++17 enabled. The conversion is provided in a
separate header to avoid unconditional @cpp #include <optional> @ce, which
significantly affects compile times. Example:
@snippet Containers-stl17.cpp Optional
<b></b>
@m_class{m-block m-success}
@par Single-header version
Expand Down Expand Up @@ -132,6 +149,12 @@ template<class T> class Optional {
new(&_value.v) T{std::forward<Args>(args)...};
}

/** @brief Copy-construct an optional from external representation */
template<class U, class = decltype(Implementation::OptionalConverter<U>::from(std::declval<const U&>()))> explicit Optional(const U& other) noexcept(std::is_nothrow_copy_constructible<T>::value): Optional{Implementation::OptionalConverter<U>::from(other)} {}

/** @brief Move-construct an optional from external representation */
template<class U, class = decltype(Implementation::OptionalConverter<U>::from(std::declval<U&&>()))> explicit Optional(U&& other) noexcept(std::is_nothrow_move_constructible<T>::value): Optional{Implementation::OptionalConverter<U>::from(std::move(other))} {}

/** @brief Copy constructor */
Optional(const Optional<T>& other) noexcept(std::is_nothrow_copy_constructible<T>::value);

Expand All @@ -156,6 +179,16 @@ template<class T> class Optional {
*/
Optional<T>& operator=(Optional<T>&& other) noexcept(std::is_nothrow_move_assignable<T>::value);

/** @brief Copy-convert the optional to external representation */
template<class U, class = decltype(Implementation::OptionalConverter<U>::to(std::declval<const Optional<T>&>()))> explicit operator U() const & {
return Implementation::OptionalConverter<U>::to(*this);
}

/** @brief Move-convert the optional to external representation */
template<class U, class = decltype(Implementation::OptionalConverter<U>::to(std::declval<Optional<T>&&>()))> explicit operator U() && {
return Implementation::OptionalConverter<U>::to(std::move(*this));
}

/**
* @brief Clear the contained value
*
Expand Down
66 changes: 66 additions & 0 deletions src/Corrade/Containers/OptionalStl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#ifndef Corrade_Containers_PointerStl_h
#define Corrade_Containers_PointerStl_h
/*
This file is part of Corrade.
Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
2017, 2018, 2019 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

/** @file
@brief STL compatibility for @ref Corrade::Containers::Optional
Including this header allows you to *explicitly* convert between
@ref Corrade::Containers::Optional and @cpp std::optional @ce using copy / move
construction and assignment. See @ref Containers-Optional-stl for more
information.
*/

#include <optional>

#include "Corrade/Containers/Optional.h"

/* Listing these namespaces doesn't anything to the docs, so don't */
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Corrade { namespace Containers { namespace Implementation {

template<class T> struct OptionalConverter<std::optional<T>> {
static Optional<T> from(const std::optional<T>& other) {
return other ? Optional<T>{*other} : Containers::NullOpt;
}

static Optional<T> from(std::optional<T>&& other) {
return other ? Optional<T>{*std::move(other)} : Containers::NullOpt;
}

static std::optional<T> to(const Optional<T>& other) {
return other ? std::optional<T>{*other} : std::nullopt;
}

static std::optional<T> to(Optional<T>&& other) {
return other ? std::optional<T>{*std::move(other)} : std::nullopt;
}
};

}}}
#endif

#endif
12 changes: 12 additions & 0 deletions src/Corrade/Containers/Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,15 @@ set_target_properties(
ContainersStridedArrayViewTest
ContainersTagsTest
PROPERTIES FOLDER "Corrade/Containers/Test")

# Copied verbatim from src/Corrade/Test/CMakeLists.txt, please keep in sync
# (especially for AppleClang)
if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "7.0") OR
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0") OR
#(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "10.0") OR
(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.10"))
corrade_add_test(ContainersOptionalStlTest OptionalStlTest.cpp)
set_target_properties(ContainersOptionalStlTest PROPERTIES
CORRADE_CXX_STANDARD 17
FOLDER "Corrade/Containers/Test")
endif()
103 changes: 103 additions & 0 deletions src/Corrade/Containers/Test/OptionalStlTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@

/*
This file is part of Corrade.
Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
2017, 2018, 2019 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#include "Corrade/Containers/OptionalStl.h"
#include "Corrade/Containers/Pointer.h"
#include "Corrade/TestSuite/Tester.h"

namespace Corrade { namespace Containers { namespace Test { namespace {

struct OptionalStlTest: TestSuite::Tester {
explicit OptionalStlTest();

void convertCopy();
void convertCopyNull();
void convertMove();
void convertMoveNull();
};

OptionalStlTest::OptionalStlTest() {
addTests({&OptionalStlTest::convertCopy,
&OptionalStlTest::convertCopyNull,
&OptionalStlTest::convertMove,
&OptionalStlTest::convertMoveNull});
}

void OptionalStlTest::convertCopy() {
std::optional<int> a = 5;
CORRADE_VERIFY(a);
CORRADE_COMPARE(*a, 5);

Optional<int> b{a};
CORRADE_VERIFY(b);
CORRADE_COMPARE(*b, 5);

std::optional<int> c{b};
CORRADE_VERIFY(c);
CORRADE_COMPARE(*c, 5);
}

void OptionalStlTest::convertCopyNull() {
std::optional<int> a;
CORRADE_VERIFY(!a);

Optional<int> b(a);
CORRADE_VERIFY(!b);

std::optional<int> c(b);
CORRADE_VERIFY(!c);
}

void OptionalStlTest::convertMove() {
std::optional<Pointer<int>> a{pointer(new int{15})};
CORRADE_VERIFY(a);
CORRADE_COMPARE(**a, 15);

Optional<Pointer<int>> b(std::move(a));
CORRADE_VERIFY(b);
CORRADE_VERIFY(!*a);
CORRADE_COMPARE(**b, 15);

std::optional<Pointer<int>> c(std::move(b));
CORRADE_VERIFY(c);
CORRADE_VERIFY(!*b);
CORRADE_COMPARE(**c, 15);
}

void OptionalStlTest::convertMoveNull() {
std::optional<Pointer<int>> a;
CORRADE_VERIFY(!a);

Optional<Pointer<int>> b(std::move(a));
CORRADE_VERIFY(!b);

std::optional<Pointer<int>> c(std::move(b));
CORRADE_VERIFY(!c);
}

}}}}

CORRADE_TEST_MAIN(Corrade::Containers::Test::OptionalStlTest)
Loading

0 comments on commit 69e6593

Please sign in to comment.