summaryrefslogtreecommitdiff
path: root/Utilities/std
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/std')
-rw-r--r--Utilities/std/cm/bits/erase_if.hxx29
-rw-r--r--Utilities/std/cm/deque40
-rw-r--r--Utilities/std/cm/list39
-rw-r--r--Utilities/std/cm/map44
-rw-r--r--Utilities/std/cm/memory37
-rw-r--r--Utilities/std/cm/set43
-rw-r--r--Utilities/std/cm/string42
-rw-r--r--Utilities/std/cm/type_traits63
-rw-r--r--Utilities/std/cm/unordered_map45
-rw-r--r--Utilities/std/cm/unordered_set45
-rw-r--r--Utilities/std/cm/vector40
-rw-r--r--Utilities/std/cmext/algorithm163
-rw-r--r--Utilities/std/cmext/iterator49
-rw-r--r--Utilities/std/cmext/memory40
-rw-r--r--Utilities/std/cmext/type_traits86
15 files changed, 804 insertions, 1 deletions
diff --git a/Utilities/std/cm/bits/erase_if.hxx b/Utilities/std/cm/bits/erase_if.hxx
new file mode 100644
index 000000000..8952fb589
--- /dev/null
+++ b/Utilities/std/cm/bits/erase_if.hxx
@@ -0,0 +1,29 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#ifndef cm_bits_erase_if_hxx
+#define cm_bits_erase_if_hxx
+
+namespace cm {
+namespace internals {
+
+template <typename Container, typename Predicate>
+void erase_if(Container& cont, Predicate pred)
+{
+ for (typename Container::iterator iter = cont.begin(), last = cont.end();
+ iter != last;) {
+ if (pred(*iter)) {
+ iter = cont.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+}
+
+} // namespace internals
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/deque b/Utilities/std/cm/deque
new file mode 100644
index 000000000..4bb672557
--- /dev/null
+++ b/Utilities/std/cm/deque
@@ -0,0 +1,40 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_deque
+#define cm_deque
+
+#include <algorithm>
+#include <deque> // IWYU pragma: export
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) && \
+ defined(__cpp_lib_erase_if)
+
+using std::erase;
+using std::erase_if;
+
+#else
+
+template <typename T, typename Allocator, typename V>
+inline void erase(std::deque<T, Allocator>& cont, const V& value)
+{
+ cont.erase(std::remove(cont.begin(), cont.end(), value), cont.end());
+}
+
+template <typename T, typename Allocator, typename Predicate>
+inline void erase_if(std::deque<T, Allocator>& cont, Predicate pred)
+{
+ cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/list b/Utilities/std/cm/list
new file mode 100644
index 000000000..ba5d94a08
--- /dev/null
+++ b/Utilities/std/cm/list
@@ -0,0 +1,39 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_list
+#define cm_list
+
+#include <list> // IWYU pragma: export
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) && \
+ defined(__cpp_lib_erase_if)
+
+using std::erase;
+using std::erase_if;
+
+#else
+
+template <typename T, typename Allocator, typename V>
+inline void erase(std::list<T, Allocator>& cont, const V& value)
+{
+ cont.remove_if([&](auto& elem) { return elem == value; });
+}
+
+template <typename T, typename Allocator, typename Predicate>
+inline void erase_if(std::list<T, Allocator>& cont, Predicate pred)
+{
+ cont.remove_if(pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/map b/Utilities/std/cm/map
new file mode 100644
index 000000000..e348decff
--- /dev/null
+++ b/Utilities/std/cm/map
@@ -0,0 +1,44 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_map
+#define cm_map
+
+#include <map> // IWYU pragma: export
+
+#include <cm/bits/erase_if.hxx>
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) && \
+ defined(__cpp_lib_erase_if)
+
+using std::erase_if;
+
+#else
+
+template <typename Key, typename T, typename Compare, typename Allocator,
+ typename Predicate>
+inline void erase_if(std::map<Key, T, Compare, Allocator>& cont,
+ Predicate pred)
+{
+ internals::erase_if(cont, pred);
+}
+
+template <typename Key, typename T, typename Compare, typename Allocator,
+ typename Predicate>
+inline void erase_if(std::multimap<Key, T, Compare, Allocator>& cont,
+ Predicate pred)
+{
+ internals::erase_if(cont, pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/memory b/Utilities/std/cm/memory
index 8ebded277..dd0f8226d 100644
--- a/Utilities/std/cm/memory
+++ b/Utilities/std/cm/memory
@@ -8,6 +8,8 @@
#include <memory> // IWYU pragma: export
#if !defined(CMake_HAVE_CXX_MAKE_UNIQUE)
+# include <cstddef>
+# include <type_traits>
# include <utility>
#endif
@@ -19,12 +21,45 @@ using std::make_unique;
#else
+namespace internals {
+
+template <typename T>
+struct make_unique_if
+{
+ using single = std::unique_ptr<T>;
+};
+
+template <typename T>
+struct make_unique_if<T[]>
+{
+ using unbound_array = std::unique_ptr<T[]>;
+};
+
+template <typename T, std::size_t N>
+struct make_unique_if<T[N]>
+{
+ using bound_array = void;
+};
+}
+
template <typename T, typename... Args>
-std::unique_ptr<T> make_unique(Args&&... args)
+typename internals::make_unique_if<T>::single make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
+template <typename T>
+typename internals::make_unique_if<T>::unbound_array make_unique(std::size_t n)
+{
+ using E = typename std::remove_extent<T>::type;
+
+ return std::unique_ptr<T>(new E[n]());
+}
+
+template <typename T, typename... Args>
+typename internals::make_unique_if<T>::bound_array make_unique(Args&&...) =
+ delete;
+
#endif
} // namespace cm
diff --git a/Utilities/std/cm/set b/Utilities/std/cm/set
new file mode 100644
index 000000000..56dd474c1
--- /dev/null
+++ b/Utilities/std/cm/set
@@ -0,0 +1,43 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_set
+#define cm_set
+
+#include <set> // IWYU pragma: export
+
+#include <cm/bits/erase_if.hxx>
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) && \
+ defined(__cpp_lib_erase_if)
+
+using std::erase_if;
+
+#else
+
+template <typename Key, typename Compare, typename Allocator,
+ typename Predicate>
+inline void erase_if(std::set<Key, Compare, Allocator>& cont, Predicate pred)
+{
+ internals::erase_if(cont, pred);
+}
+
+template <typename Key, typename Compare, typename Allocator,
+ typename Predicate>
+inline void erase_if(std::multiset<Key, Compare, Allocator>& cont,
+ Predicate pred)
+{
+ internals::erase_if(cont, pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/string b/Utilities/std/cm/string
new file mode 100644
index 000000000..cc4c79689
--- /dev/null
+++ b/Utilities/std/cm/string
@@ -0,0 +1,42 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_string
+#define cm_string
+
+#include <algorithm>
+#include <string> // IWYU pragma: export
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) && \
+ defined(__cpp_lib_erase_if)
+
+using std::erase;
+using std::erase_if;
+
+#else
+
+template <typename T, typename Traits, typename Allocator, typename V>
+inline void erase(std::basic_string<T, Traits, Allocator>& cont,
+ const V& value)
+{
+ cont.erase(std::remove(cont.begin(), cont.end(), value), cont.end());
+}
+
+template <typename T, typename Traits, typename Allocator, typename Predicate>
+inline void erase_if(std::basic_string<T, Traits, Allocator>& cont,
+ Predicate pred)
+{
+ cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/type_traits b/Utilities/std/cm/type_traits
new file mode 100644
index 000000000..e32c2c676
--- /dev/null
+++ b/Utilities/std/cm/type_traits
@@ -0,0 +1,63 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_type_traits
+#define cm_type_traits
+
+#include <type_traits> // IWYU pragma: export
+
+namespace cm {
+
+#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
+
+// Miscellaneous transformations
+template <bool B, typename T = void>
+using enable_if_t = std::enable_if_t<B, T>;
+
+#else
+
+// Miscellaneous transformations
+template <bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+#endif
+
+#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703)
+
+// Helper classes
+using std::bool_constant;
+
+// Miscellaneous transformations
+using std::invoke_result;
+using std::invoke_result_t;
+
+using std::void_t;
+
+#else
+
+// Helper classes
+template <bool B>
+using bool_constant = std::integral_constant<bool, B>;
+
+// Miscellaneous transformations
+template <typename F, typename... ArgTypes>
+using invoke_result = std::result_of<F(ArgTypes...)>;
+
+template <class F, typename... ArgTypes>
+using invoke_result_t = typename invoke_result<F, ArgTypes...>::type;
+
+template <typename... ArgTypes>
+struct make_void
+{
+ typedef void type;
+};
+template <typename... ArgTypes>
+using void_t = typename make_void<ArgTypes...>::type;
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/unordered_map b/Utilities/std/cm/unordered_map
new file mode 100644
index 000000000..5b8a456fd
--- /dev/null
+++ b/Utilities/std/cm/unordered_map
@@ -0,0 +1,45 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_unordered_map
+#define cm_unordered_map
+
+#include <unordered_map> // IWYU pragma: export
+
+#include <cm/bits/erase_if.hxx>
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) && \
+ defined(__cpp_lib_erase_if)
+
+using std::erase_if;
+
+#else
+
+template <typename Key, typename T, typename Hash, typename KeyEqual,
+ typename Allocator, typename Predicate>
+inline void erase_if(
+ std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& cont, Predicate pred)
+{
+ internals::erase_if(cont, pred);
+}
+
+template <typename Key, typename T, typename Hash, typename KeyEqual,
+ typename Allocator, typename Predicate>
+inline void erase_if(
+ std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& cont,
+ Predicate pred)
+{
+ internals::erase_if(cont, pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/unordered_set b/Utilities/std/cm/unordered_set
new file mode 100644
index 000000000..9debac43f
--- /dev/null
+++ b/Utilities/std/cm/unordered_set
@@ -0,0 +1,45 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_unordered_set
+#define cm_unordered_set
+
+#include <unordered_set> // IWYU pragma: export
+
+#include <cm/bits/erase_if.hxx>
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) && \
+ defined(__cpp_lib_erase_if)
+
+using std::erase_if;
+
+#else
+
+template <typename Key, typename Hash, typename KeyEqual, typename Allocator,
+ typename Predicate>
+inline void erase_if(std::unordered_set<Key, Hash, KeyEqual, Allocator>& cont,
+ Predicate pred)
+{
+ internals::erase_if(cont, pred);
+}
+
+template <typename Key, typename Hash, typename KeyEqual, typename Allocator,
+ typename Predicate>
+inline void erase_if(
+ std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& cont,
+ Predicate pred)
+{
+ internals::erase_if(cont, pred);
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/vector b/Utilities/std/cm/vector
new file mode 100644
index 000000000..2dbe70439
--- /dev/null
+++ b/Utilities/std/cm/vector
@@ -0,0 +1,40 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_vector
+#define cm_vector
+
+#include <algorithm>
+#include <vector> // IWYU pragma: export
+
+namespace cm {
+
+// should be updated when C++20 is finalized
+#if (__cplusplus > 201703L || \
+ (defined(_MSVC_LANG) && _MSVC_LANG > 201703)) && \
+ defined(__cpp_lib_erase_if)
+
+using std::erase;
+using std::erase_if;
+
+#else
+
+template <typename T, typename Allocator, typename V>
+inline void erase(std::vector<T, Allocator>& cont, const V& value)
+{
+ cont.erase(std::remove(cont.begin(), cont.end(), value), cont.end());
+}
+
+template <typename T, typename Allocator, typename Predicate>
+inline void erase_if(std::vector<T, Allocator>& cont, Predicate pred)
+{
+ cont.erase(std::remove_if(cont.begin(), cont.end(), pred), cont.end());
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cmext/algorithm b/Utilities/std/cmext/algorithm
new file mode 100644
index 000000000..44e61f45d
--- /dev/null
+++ b/Utilities/std/cmext/algorithm
@@ -0,0 +1,163 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmext_algorithm
+#define cmext_algorithm
+
+#include <algorithm>
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include <cm/type_traits>
+#include <cmext/iterator>
+
+#if defined(__SUNPRO_CC) && defined(__sparc)
+# include <list>
+# include <vector>
+#else
+# include <cmext/type_traits>
+#endif
+
+namespace cm {
+
+#if defined(__SUNPRO_CC) && defined(__sparc)
+// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
+// templates with constraints.
+// So, on this platform, use only simple templates.
+# define APPEND_TWO(C1, C2) \
+ template <typename T, typename U> \
+ void append(C1<std::unique_ptr<T>>& v, C2<std::unique_ptr<U>>&& r) \
+ { \
+ std::transform( \
+ r.begin(), r.end(), std::back_inserter(v), \
+ [](std::unique_ptr<U>& item) { return std::move(item); }); \
+ r.clear(); \
+ } \
+ \
+ template <typename T, typename U> \
+ void append(C1<T*>& v, C2<std::unique_ptr<U>> const& r) \
+ { \
+ std::transform( \
+ r.begin(), r.end(), std::back_inserter(v), \
+ [](const std::unique_ptr<U>& item) { return item.get(); }); \
+ }
+
+# define APPEND_ONE(C) \
+ template <typename T, typename InputIt, \
+ cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = \
+ 0> \
+ void append(C<T>& v, InputIt first, InputIt last) \
+ { \
+ v.insert(v.end(), first, last); \
+ } \
+ \
+ template <typename T, typename Range, \
+ cm::enable_if_t<cm::is_input_range<Range>::value, int> = 0> \
+ void append(C<T>& v, Range const& r) \
+ { \
+ v.insert(v.end(), r.begin(), r.end()); \
+ }
+
+# define APPEND(C) \
+ APPEND_TWO(C, C) \
+ APPEND_ONE(C)
+
+# define APPEND_MIX(C1, C2) \
+ APPEND_TWO(C1, C2) \
+ APPEND_TWO(C2, C1)
+
+// For now, manage only support for std::vector and std::list.
+// Other sequential container support can be added if needed.
+APPEND(std::vector)
+APPEND(std::list)
+APPEND_MIX(std::vector, std::list)
+
+# undef APPEND
+# undef APPEND_MIX
+# undef APPEND_TWO
+# undef APPEND_ONE
+
+#else
+
+template <
+ typename Container1, typename Container2,
+ cm::enable_if_t<
+ cm::is_sequence_container<Container1>::value &&
+ cm::is_unique_ptr<typename Container1::value_type>::value &&
+ cm::is_unique_ptr<typename Container2::value_type>::value &&
+ std::is_convertible<typename Container2::value_type::pointer,
+ typename Container1::value_type::pointer>::value,
+ int> = 0>
+void append(Container1& v, Container2&& r)
+{
+ std::transform(
+ r.begin(), r.end(), std::back_inserter(v),
+ [](typename Container2::value_type& item) { return std::move(item); });
+ r.clear();
+}
+
+template <typename Container1, typename Container2,
+ cm::enable_if_t<
+ cm::is_sequence_container<Container1>::value &&
+ std::is_pointer<typename Container1::value_type>::value &&
+ cm::is_unique_ptr<typename Container2::value_type>::value &&
+ std::is_convertible<typename Container2::value_type::pointer,
+ typename Container1::value_type>::value,
+ int> = 0>
+# if defined(__SUNPRO_CC)
+void append(Container1& v, Container2 const& r, detail::overload_selector<0>)
+# else
+void append(Container1& v, Container2 const& r)
+# endif
+{
+ std::transform(
+ r.begin(), r.end(), std::back_inserter(v),
+ [](const typename Container2::value_type& item) { return item.get(); });
+}
+
+template <
+ typename Container, typename InputIt,
+ cm::enable_if_t<
+ cm::is_sequence_container<Container>::value &&
+ cm::is_input_iterator<InputIt>::value &&
+ std::is_convertible<typename std::iterator_traits<InputIt>::value_type,
+ typename Container::value_type>::value,
+ int> = 0>
+void append(Container& v, InputIt first, InputIt last)
+{
+ v.insert(v.end(), first, last);
+}
+
+template <typename Container, typename Range,
+ cm::enable_if_t<
+ cm::is_sequence_container<Container>::value &&
+ cm::is_input_range<Range>::value &&
+ !cm::is_unique_ptr<typename Container::value_type>::value &&
+ !cm::is_unique_ptr<typename Range::value_type>::value &&
+ std::is_convertible<typename Range::value_type,
+ typename Container::value_type>::value,
+ int> = 0>
+# if defined(__SUNPRO_CC)
+void append(Container& v, Range const& r, detail::overload_selector<1>)
+# else
+void append(Container& v, Range const& r)
+# endif
+{
+ v.insert(v.end(), r.begin(), r.end());
+}
+
+# if defined(__SUNPRO_CC)
+template <typename T, typename U>
+void append(T& v, U const& r)
+{
+ cm::append(v, r, detail::overload_selector<1>{});
+}
+# endif
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cmext/iterator b/Utilities/std/cmext/iterator
new file mode 100644
index 000000000..ffe94b17d
--- /dev/null
+++ b/Utilities/std/cmext/iterator
@@ -0,0 +1,49 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmext_iterator
+#define cmext_iterator
+
+#include <iterator>
+
+#include <cm/type_traits>
+
+namespace cm {
+
+// checks if a type is an iterator type
+template <typename I>
+using is_iterator =
+ std::is_integral<typename std::iterator_traits<I>::difference_type>;
+
+// checks if a type is an input iterator type
+template <typename I>
+using is_input_iterator =
+ std::is_base_of<std::input_iterator_tag,
+ typename std::iterator_traits<I>::iterator_category>;
+
+// checks if a type is a range type: must have a difference_type type
+template <typename Range>
+using is_range = cm::bool_constant<
+ cm::is_iterator<decltype(std::declval<const Range>().begin())>::value &&
+ cm::is_iterator<decltype(std::declval<const Range>().end())>::value>;
+
+// checks if a type is an input range type: must have methods begin() and end()
+// returning an input iterator
+template <typename Range>
+using is_input_range =
+#if defined(_MSC_VER) && _MSC_VER < 1920
+ // MS C++ is not able to evaluate complex type introspection,
+ // so use a simplified version
+ cm::is_input_iterator<typename Range::const_iterator>;
+#else
+ cm::bool_constant<
+ cm::is_input_iterator<decltype(
+ std::declval<const Range>().begin())>::value &&
+ cm::is_input_iterator<decltype(std::declval<const Range>().end())>::value>;
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cmext/memory b/Utilities/std/cmext/memory
new file mode 100644
index 000000000..50e79dfe2
--- /dev/null
+++ b/Utilities/std/cmext/memory
@@ -0,0 +1,40 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmext_memory
+#define cmext_memory
+
+#include <typeinfo>
+
+#include <cm/type_traits>
+
+namespace cm {
+
+template <typename T, typename O,
+ cm::enable_if_t<
+ std::is_pointer<cm::invoke_result_t<decltype(&O::get), O>>::value,
+ int> = 0>
+T& static_reference_cast(O& item)
+{
+ return *(static_cast<T*>(item.get()));
+}
+template <typename T, typename O,
+ cm::enable_if_t<
+ std::is_pointer<cm::invoke_result_t<decltype(&O::get), O>>::value,
+ int> = 0>
+T& dynamic_reference_cast(O& item)
+{
+ auto p = dynamic_cast<T*>(item.get());
+
+ if (p == nullptr) {
+ throw std::bad_cast();
+ }
+
+ return *p;
+}
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cmext/type_traits b/Utilities/std/cmext/type_traits
new file mode 100644
index 000000000..00984cba2
--- /dev/null
+++ b/Utilities/std/cmext/type_traits
@@ -0,0 +1,86 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmext_type_traits
+#define cmext_type_traits
+
+#include <cm/type_traits>
+
+namespace cm {
+
+#if defined(__SUNPRO_CC)
+// Oracle DeveloperStudio C++ compiler do not support overloaded templates with
+// same signature but different constraints over template arguments
+// (i.e. meta-programming).
+// As a work-around, use a structure to avoid templates with same signature.
+namespace detail {
+template <int N>
+struct overload_selector : overload_selector<N - 1>
+{
+};
+
+template <>
+struct overload_selector<0>
+{
+};
+}
+#endif
+
+// type traits for managed pointer types
+template <typename>
+struct is_unique_ptr : std::false_type
+{
+};
+template <typename T>
+struct is_unique_ptr<std::unique_ptr<T>> : std::true_type
+{
+};
+
+// type traits for containers
+template <typename, typename = void_t<>>
+struct is_container : std::false_type
+{
+};
+template <typename T>
+struct is_container<
+ T,
+ cm::void_t<typename T::value_type, typename T::size_type,
+ typename T::difference_type, typename T::iterator>>
+ : std::true_type
+{
+};
+
+template <typename, typename = void_t<>>
+struct is_associative_container : std::false_type
+{
+};
+template <typename T>
+struct is_associative_container<
+ T, cm::void_t<typename T::key_type, typename T::key_compare>>
+ : cm::is_container<T>
+{
+};
+
+template <typename, typename = void_t<>>
+struct is_unordered_associative_container : std::false_type
+{
+};
+template <typename T>
+struct is_unordered_associative_container<
+ T,
+ cm::void_t<typename T::key_type, typename T::hasher, typename T::key_equal,
+ typename T::local_iterator>> : cm::is_container<T>
+{
+};
+
+template <typename T>
+using is_sequence_container =
+ cm::bool_constant<cm::is_container<T>::value &&
+ !cm::is_associative_container<T>::value &&
+ !cm::is_unordered_associative_container<T>::value>;
+
+} // namespace cm
+
+#endif