diff --git a/doc/src/api/vpr/index.rst b/doc/src/api/vpr/index.rst
index 53c6b35bc36..37410b72b9c 100644
--- a/doc/src/api/vpr/index.rst
+++ b/doc/src/api/vpr/index.rst
@@ -7,6 +7,7 @@ VPR API
:maxdepth: 1
contexts
- netlist
mapping
+ netlist
+ route_tree
rr_graph
diff --git a/doc/src/api/vpr/route_tree.rst b/doc/src/api/vpr/route_tree.rst
new file mode 100644
index 00000000000..7be12dda86a
--- /dev/null
+++ b/doc/src/api/vpr/route_tree.rst
@@ -0,0 +1,22 @@
+========
+Route Tree
+========
+
+RouteTree
+-------
+
+.. doxygenfile:: route_tree.h
+ :project: vpr
+ :sections: detaileddescription
+
+
+.. doxygenclass:: RouteTree
+ :project: vpr
+ :members:
+
+RouteTreeNode
+-------------
+
+.. doxygenclass:: RouteTreeNode
+ :project: vpr
+ :members:
diff --git a/libs/libvtrutil/src/tl_optional.hpp b/libs/libvtrutil/src/tl_optional.hpp
new file mode 100644
index 00000000000..294755b69a1
--- /dev/null
+++ b/libs/libvtrutil/src/tl_optional.hpp
@@ -0,0 +1,2072 @@
+/* TartanLlama's optional.hpp.
+ * It is wrapped in vtr namespace in vtr_optional.h.
+ * Original repo: https://github.com/TartanLlama/optional
+ */
+
+///
+// optional - An implementation of std::optional with extensions
+// Written in 2017 by Sy Brand (tartanllama@gmail.com, @TartanLlama)
+//
+// Documentation available at https://tl.tartanllama.xyz/
+//
+// To the extent possible under law, the author(s) have dedicated all
+// copyright and related and neighboring rights to this software to the
+// public domain worldwide. This software is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication
+// along with this software. If not, see
+// .
+///
+
+#ifndef TL_OPTIONAL_HPP
+#define TL_OPTIONAL_HPP
+
+#define TL_OPTIONAL_VERSION_MAJOR 1
+#define TL_OPTIONAL_VERSION_MINOR 0
+#define TL_OPTIONAL_VERSION_PATCH 0
+
+#include
+#include
+#include
+#include
+#include
+
+#if (defined(_MSC_VER) && _MSC_VER == 1900)
+# define TL_OPTIONAL_MSVC2015
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
+# define TL_OPTIONAL_GCC49
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && !defined(__clang__))
+# define TL_OPTIONAL_GCC54
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && !defined(__clang__))
+# define TL_OPTIONAL_GCC55
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
+// GCC < 5 doesn't support overloading on const&& for member functions
+# define TL_OPTIONAL_NO_CONSTRR
+
+// GCC < 5 doesn't support some standard C++11 type traits
+# define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ std::has_trivial_copy_constructor::value
+# define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign::value
+
+// This one will be different for GCC 5.7 if it's ever supported
+# define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value
+
+// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector
+// for non-copyable types
+#elif (defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__))
+# ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
+# define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX
+namespace tl {
+namespace detail {
+template
+struct is_trivially_copy_constructible : std::is_trivially_copy_constructible {};
+# ifdef _GLIBCXX_VECTOR
+template
+struct is_trivially_copy_constructible>
+ : std::is_trivially_copy_constructible {};
+# endif
+} // namespace detail
+} // namespace tl
+# endif
+
+# define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ tl::detail::is_trivially_copy_constructible::value
+# define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+ std::is_trivially_copy_assignable::value
+# define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value
+#else
+# define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \
+ std::is_trivially_copy_constructible::value
+# define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \
+ std::is_trivially_copy_assignable::value
+# define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value
+#endif
+
+#if __cplusplus > 201103L
+# define TL_OPTIONAL_CXX14
+#endif
+
+// constexpr implies const in C++11, not C++14
+#if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || defined(TL_OPTIONAL_GCC49))
+# define TL_OPTIONAL_11_CONSTEXPR
+#else
+# define TL_OPTIONAL_11_CONSTEXPR constexpr
+#endif
+
+namespace tl {
+#ifndef TL_MONOSTATE_INPLACE_MUTEX
+# define TL_MONOSTATE_INPLACE_MUTEX
+/// Used to represent an optional with no data; essentially a bool
+class monostate {};
+
+/// A tag type to tell optional to construct its value in-place
+struct in_place_t {
+ explicit in_place_t() = default;
+};
+/// A tag to tell optional to construct its value in-place
+static constexpr in_place_t in_place{};
+#endif
+
+template
+class optional;
+
+namespace detail {
+#ifndef TL_TRAITS_MUTEX
+# define TL_TRAITS_MUTEX
+// C++14-style aliases for brevity
+template
+using remove_const_t = typename std::remove_const::type;
+template
+using remove_reference_t = typename std::remove_reference::type;
+template
+using decay_t = typename std::decay::type;
+template
+using enable_if_t = typename std::enable_if::type;
+template
+using conditional_t = typename std::conditional::type;
+
+// std::conjunction from C++17
+template
+struct conjunction : std::true_type {};
+template
+struct conjunction : B {};
+template
+struct conjunction
+ : std::conditional, 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
+struct is_pointer_to_non_const_member_func : std::false_type {};
+template
+struct is_pointer_to_non_const_member_func : std::true_type {};
+template
+struct is_pointer_to_non_const_member_func : std::true_type {};
+template
+struct is_pointer_to_non_const_member_func : std::true_type {};
+template
+struct is_pointer_to_non_const_member_func : std::true_type {};
+template
+struct is_pointer_to_non_const_member_func : std::true_type {};
+template
+struct is_pointer_to_non_const_member_func : std::true_type {};
+
+template
+struct is_const_or_const_ref : std::false_type {};
+template
+struct is_const_or_const_ref : std::true_type {};
+template
+struct is_const_or_const_ref : std::true_type {};
+# endif
+
+// std::invoke from C++17
+// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
+template::value && is_const_or_const_ref::value)>,
+# endif
+ typename = enable_if_t>::value>,
+ int = 0>
+constexpr auto invoke(Fn&& f, Args&&... args) noexcept(
+ noexcept(std::mem_fn(f)(std::forward(args)...)))
+ -> decltype(std::mem_fn(f)(std::forward(args)...)) {
+ return std::mem_fn(f)(std::forward(args)...);
+}
+
+template>::value>>
+constexpr auto invoke(Fn&& f, Args&&... args) noexcept(
+ noexcept(std::forward(f)(std::forward(args)...)))
+ -> decltype(std::forward(f)(std::forward(args)...)) {
+ return std::forward(f)(std::forward(args)...);
+}
+
+// std::invoke_result from C++17
+template
+struct invoke_result_impl;
+
+template
+struct invoke_result_impl<
+ F,
+ decltype(detail::invoke(std::declval(), std::declval()...), void()),
+ Us...> {
+ using type = decltype(detail::invoke(std::declval(), std::declval()...));
+};
+
+template
+using invoke_result = invoke_result_impl;
+
+template
+using invoke_result_t = typename invoke_result::type;
+
+# if defined(_MSC_VER) && _MSC_VER <= 1900
+// TODO make a version which works with MSVC 2015
+template
+struct is_swappable : std::true_type {};
+
+template
+struct is_nothrow_swappable : std::true_type {};
+# else
+// https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept
+namespace swap_adl_tests {
+// if swap ADL finds this then it would call std::swap otherwise (same
+// signature)
+struct tag {};
+
+template
+tag swap(T&, T&);
+template
+tag swap(T (&a)[N], T (&b)[N]);
+
+// helper functions to test if an unqualified swap is possible, and if it
+// becomes std::swap
+template
+std::false_type can_swap(...) noexcept(false);
+template(), std::declval()))>
+std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(),
+ std::declval())));
+
+template
+std::false_type uses_std(...);
+template
+std::is_same(), std::declval())), tag>
+uses_std(int);
+
+template
+struct is_std_swap_noexcept
+ : std::integral_constant::value && std::is_nothrow_move_assignable::value> {};
+
+template
+struct is_std_swap_noexcept : is_std_swap_noexcept {};
+
+template
+struct is_adl_swap_noexcept
+ : std::integral_constant(0))> {};
+} // namespace swap_adl_tests
+
+template
+struct is_swappable
+ : std::integral_constant<
+ bool,
+ decltype(detail::swap_adl_tests::can_swap(0))::value && (!decltype(detail::swap_adl_tests::uses_std(0))::value || (std::is_move_assignable::value && std::is_move_constructible::value))> {};
+
+template
+struct is_swappable
+ : std::integral_constant<
+ bool,
+ decltype(detail::swap_adl_tests::can_swap(0))::value && (!decltype(detail::swap_adl_tests::uses_std(0))::value || is_swappable::value)> {};
+
+template
+struct is_nothrow_swappable
+ : std::integral_constant<
+ bool,
+ is_swappable::value && ((decltype(detail::swap_adl_tests::uses_std(0))::value && detail::swap_adl_tests::is_std_swap_noexcept::value) || (!decltype(detail::swap_adl_tests::uses_std(0))::value && detail::swap_adl_tests::is_adl_swap_noexcept::value))> {
+};
+# endif
+#endif
+
+// std::void_t from C++17
+template
+struct voider { using type = void; };
+template
+using void_t = typename voider::type;
+
+// Trait for checking if a type is a tl::optional
+template
+struct is_optional_impl : std::false_type {};
+template
+struct is_optional_impl> : std::true_type {};
+template
+using is_optional = is_optional_impl>;
+
+// Change void to tl::monostate
+template
+using fixup_void = conditional_t::value, monostate, U>;
+
+template>
+using get_map_return = optional>>;
+
+// Check if invoking F for some Us returns void
+template
+struct returns_void_impl;
+template
+struct returns_void_impl>, U...>
+ : std::is_void> {};
+template
+using returns_void = returns_void_impl;
+
+template
+using enable_if_ret_void = enable_if_t::value>;
+
+template
+using disable_if_ret_void = enable_if_t::value>;
+
+template
+using enable_forward_value = detail::enable_if_t::value && !std::is_same, in_place_t>::value && !std::is_same, detail::decay_t>::value>;
+
+template
+using enable_from_other = detail::enable_if_t<
+ std::is_constructible::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value>;
+
+template
+using enable_assign_forward = detail::enable_if_t<
+ !std::is_same, detail::decay_t>::value && !detail::conjunction, std::is_same>>::value && std::is_constructible::value && std::is_assignable::value>;
+
+template
+using enable_assign_from_other = detail::enable_if_t<
+ std::is_constructible::value && std::is_assignable::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value && !std::is_assignable&>::value && !std::is_assignable&&>::value && !std::is_assignable&>::value && !std::is_assignable&&>::value>;
+
+// The storage base manages the actual storage, and correctly propagates
+// trivial destruction from T. This case is for when T is not trivially
+// destructible.
+template::value>
+struct optional_storage_base {
+ TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
+ : m_dummy()
+ , m_has_value(false) {}
+
+ template
+ TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u)
+ : m_value(std::forward(u)...)
+ , m_has_value(true) {}
+
+ ~optional_storage_base() {
+ if (m_has_value) {
+ m_value.~T();
+ m_has_value = false;
+ }
+ }
+
+ struct dummy {};
+ union {
+ dummy m_dummy;
+ T m_value;
+ };
+
+ bool m_has_value;
+};
+
+// This case is for when T is trivially destructible.
+template
+struct optional_storage_base {
+ TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept
+ : m_dummy()
+ , m_has_value(false) {}
+
+ template
+ TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U&&... u)
+ : m_value(std::forward(u)...)
+ , m_has_value(true) {}
+
+ // No destructor, so this class is trivially destructible
+
+ struct dummy {};
+ union {
+ dummy m_dummy;
+ T m_value;
+ };
+
+ bool m_has_value = false;
+};
+
+// This base class provides some handy member functions which can be used in
+// further derived classes
+template
+struct optional_operations_base : optional_storage_base {
+ using optional_storage_base::optional_storage_base;
+
+ void hard_reset() noexcept {
+ get().~T();
+ this->m_has_value = false;
+ }
+
+ template
+ void construct(Args&&... args) noexcept {
+ new (std::addressof(this->m_value)) T(std::forward(args)...);
+ this->m_has_value = true;
+ }
+
+ template
+ void assign(Opt&& rhs) {
+ if (this->has_value()) {
+ if (rhs.has_value()) {
+ this->m_value = std::forward(rhs).get();
+ } else {
+ this->m_value.~T();
+ this->m_has_value = false;
+ }
+ }
+
+ else if (rhs.has_value()) {
+ construct(std::forward(rhs).get());
+ }
+ }
+
+ bool has_value() const { return this->m_has_value; }
+
+ TL_OPTIONAL_11_CONSTEXPR T& get() & { return this->m_value; }
+ TL_OPTIONAL_11_CONSTEXPR const T& get() const& { return this->m_value; }
+ TL_OPTIONAL_11_CONSTEXPR T&& get() && { return std::move(this->m_value); }
+#ifndef TL_OPTIONAL_NO_CONSTRR
+ constexpr const T&& get() const&& { return std::move(this->m_value); }
+#endif
+};
+
+// This class manages conditionally having a trivial copy constructor
+// This specialization is for when T is trivially copy constructible
+template
+struct optional_copy_base : optional_operations_base {
+ using optional_operations_base::optional_operations_base;
+};
+
+// This specialization is for when T is not trivially copy constructible
+template
+struct optional_copy_base : optional_operations_base {
+ using optional_operations_base::optional_operations_base;
+
+ optional_copy_base() = default;
+ optional_copy_base(const optional_copy_base& rhs)
+ : optional_operations_base() {
+ if (rhs.has_value()) {
+ this->construct(rhs.get());
+ } else {
+ this->m_has_value = false;
+ }
+ }
+
+ optional_copy_base(optional_copy_base&& rhs) = default;
+ optional_copy_base& operator=(const optional_copy_base& rhs) = default;
+ optional_copy_base& operator=(optional_copy_base&& rhs) = default;
+};
+
+// This class manages conditionally having a trivial move constructor
+// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
+// doesn't implement an analogue to std::is_trivially_move_constructible. We
+// have to make do with a non-trivial move constructor even if T is trivially
+// move constructible
+#ifndef TL_OPTIONAL_GCC49
+template::value>
+struct optional_move_base : optional_copy_base {
+ using optional_copy_base::optional_copy_base;
+};
+#else
+template
+struct optional_move_base;
+#endif
+template
+struct optional_move_base : optional_copy_base {
+ using optional_copy_base::optional_copy_base;
+
+ optional_move_base() = default;
+ optional_move_base(const optional_move_base& rhs) = default;
+
+ optional_move_base(optional_move_base&& rhs) noexcept(
+ std::is_nothrow_move_constructible::value) {
+ if (rhs.has_value()) {
+ this->construct(std::move(rhs.get()));
+ } else {
+ this->m_has_value = false;
+ }
+ }
+ optional_move_base& operator=(const optional_move_base& rhs) = default;
+ optional_move_base& operator=(optional_move_base&& rhs) = default;
+};
+
+// This class manages conditionally having a trivial copy assignment operator
+template
+struct optional_copy_assign_base : optional_move_base {
+ using optional_move_base::optional_move_base;
+};
+
+template
+struct optional_copy_assign_base : optional_move_base {
+ using optional_move_base::optional_move_base;
+
+ optional_copy_assign_base() = default;
+ optional_copy_assign_base(const optional_copy_assign_base& rhs) = default;
+
+ optional_copy_assign_base(optional_copy_assign_base&& rhs) = default;
+ optional_copy_assign_base& operator=(const optional_copy_assign_base& rhs) {
+ this->assign(rhs);
+ return *this;
+ }
+ optional_copy_assign_base&
+ operator=(optional_copy_assign_base&& rhs)
+ = default;
+};
+
+// This class manages conditionally having a trivial move assignment operator
+// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it
+// doesn't implement an analogue to std::is_trivially_move_assignable. We have
+// to make do with a non-trivial move assignment operator even if T is trivially
+// move assignable
+#ifndef TL_OPTIONAL_GCC49
+template::value&& std::is_trivially_move_constructible::value&& std::is_trivially_move_assignable::value>
+struct optional_move_assign_base : optional_copy_assign_base {
+ using optional_copy_assign_base::optional_copy_assign_base;
+};
+#else
+template
+struct optional_move_assign_base;
+#endif
+
+template
+struct optional_move_assign_base : optional_copy_assign_base {
+ using optional_copy_assign_base::optional_copy_assign_base;
+
+ optional_move_assign_base() = default;
+ optional_move_assign_base(const optional_move_assign_base& rhs) = default;
+
+ optional_move_assign_base(optional_move_assign_base&& rhs) = default;
+
+ optional_move_assign_base&
+ operator=(const optional_move_assign_base& rhs)
+ = default;
+
+ optional_move_assign_base&
+ operator=(optional_move_assign_base&& rhs) noexcept(
+ std::is_nothrow_move_constructible::value&& std::is_nothrow_move_assignable::value) {
+ this->assign(std::move(rhs));
+ return *this;
+ }
+};
+
+// optional_delete_ctor_base will conditionally delete copy and move
+// constructors depending on whether T is copy/move constructible
+template::value, bool EnableMove = std::is_move_constructible::value>
+struct optional_delete_ctor_base {
+ optional_delete_ctor_base() = default;
+ optional_delete_ctor_base(const optional_delete_ctor_base&) = default;
+ optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default;
+ optional_delete_ctor_base&
+ operator=(const optional_delete_ctor_base&)
+ = default;
+ optional_delete_ctor_base&
+ operator=(optional_delete_ctor_base&&) noexcept = default;
+};
+
+template
+struct optional_delete_ctor_base {
+ optional_delete_ctor_base() = default;
+ optional_delete_ctor_base(const optional_delete_ctor_base&) = default;
+ optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete;
+ optional_delete_ctor_base&
+ operator=(const optional_delete_ctor_base&)
+ = default;
+ optional_delete_ctor_base&
+ operator=(optional_delete_ctor_base&&) noexcept = default;
+};
+
+template
+struct optional_delete_ctor_base {
+ optional_delete_ctor_base() = default;
+ optional_delete_ctor_base(const optional_delete_ctor_base&) = delete;
+ optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = default;
+ optional_delete_ctor_base&
+ operator=(const optional_delete_ctor_base&)
+ = default;
+ optional_delete_ctor_base&
+ operator=(optional_delete_ctor_base&&) noexcept = default;
+};
+
+template
+struct optional_delete_ctor_base {
+ optional_delete_ctor_base() = default;
+ optional_delete_ctor_base(const optional_delete_ctor_base&) = delete;
+ optional_delete_ctor_base(optional_delete_ctor_base&&) noexcept = delete;
+ optional_delete_ctor_base&
+ operator=(const optional_delete_ctor_base&)
+ = default;
+ optional_delete_ctor_base&
+ operator=(optional_delete_ctor_base&&) noexcept = default;
+};
+
+// optional_delete_assign_base will conditionally delete copy and move
+// constructors depending on whether T is copy/move constructible + assignable
+template::value && std::is_copy_assignable::value),
+ bool EnableMove = (std::is_move_constructible::value && std::is_move_assignable::value)>
+struct optional_delete_assign_base {
+ optional_delete_assign_base() = default;
+ optional_delete_assign_base(const optional_delete_assign_base&) = default;
+ optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
+ optional_delete_assign_base&
+ operator=(const optional_delete_assign_base&)
+ = default;
+ optional_delete_assign_base&
+ operator=(optional_delete_assign_base&&) noexcept = default;
+};
+
+template
+struct optional_delete_assign_base {
+ optional_delete_assign_base() = default;
+ optional_delete_assign_base(const optional_delete_assign_base&) = default;
+ optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
+ optional_delete_assign_base&
+ operator=(const optional_delete_assign_base&)
+ = default;
+ optional_delete_assign_base&
+ operator=(optional_delete_assign_base&&) noexcept = delete;
+};
+
+template
+struct optional_delete_assign_base {
+ optional_delete_assign_base() = default;
+ optional_delete_assign_base(const optional_delete_assign_base&) = default;
+ optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
+ optional_delete_assign_base&
+ operator=(const optional_delete_assign_base&)
+ = delete;
+ optional_delete_assign_base&
+ operator=(optional_delete_assign_base&&) noexcept = default;
+};
+
+template
+struct optional_delete_assign_base {
+ optional_delete_assign_base() = default;
+ optional_delete_assign_base(const optional_delete_assign_base&) = default;
+ optional_delete_assign_base(optional_delete_assign_base&&) noexcept = default;
+ optional_delete_assign_base&
+ operator=(const optional_delete_assign_base&)
+ = delete;
+ optional_delete_assign_base&
+ operator=(optional_delete_assign_base&&) noexcept = delete;
+};
+
+} // namespace detail
+
+/// A tag type to represent an empty optional
+struct nullopt_t {
+ struct do_not_use {};
+ constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {}
+};
+/// Represents an empty optional
+static constexpr nullopt_t nullopt{nullopt_t::do_not_use{},
+ nullopt_t::do_not_use{}};
+
+class bad_optional_access : public std::exception {
+ public:
+ bad_optional_access() = default;
+ const char* what() const noexcept { return "Optional has no value"; }
+};
+
+/// An optional object is an object that contains the storage for another
+/// object and manages the lifetime of this contained object, if any. The
+/// contained object may be initialized after the optional object has been
+/// initialized, and may be destroyed before the optional object has been
+/// destroyed. The initialization state of the contained object is tracked by
+/// the optional object.
+template
+class optional : private detail::optional_move_assign_base,
+ private detail::optional_delete_ctor_base,
+ private detail::optional_delete_assign_base {
+ using base = detail::optional_move_assign_base;
+
+ static_assert(!std::is_same::value,
+ "instantiation of optional with in_place_t is ill-formed");
+ static_assert(!std::is_same, nullopt_t>::value,
+ "instantiation of optional with nullopt_t is ill-formed");
+
+ public:
+// The different versions for C++14 and 11 are needed because deduced return
+// types are not SFINAE-safe. This provides better support for things like
+// generic lambdas. C.f.
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html
+#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55)
+ /// Carries out some operation which returns an optional on the stored
+ /// object if there is one.
+ template
+ TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) & {
+ using result = detail::invoke_result_t;
+ static_assert(detail::is_optional::value,
+ "F must return an optional");
+
+ return has_value() ? detail::invoke(std::forward(f), **this)
+ : result(nullopt);
+ }
+
+ template
+ TL_OPTIONAL_11_CONSTEXPR auto and_then(F&& f) && {
+ using result = detail::invoke_result_t;
+ static_assert(detail::is_optional