summaryrefslogtreecommitdiff
path: root/Utilities
diff options
context:
space:
mode:
authorMarc Chevrier <marc.chevrier@gmail.com>2019-08-04 10:49:16 +0200
committerBrad King <brad.king@kitware.com>2019-09-20 10:01:37 -0400
commitc688b401d3adaacc820ef4b589010e8aefa808b1 (patch)
tree83e46e3dc7c9847692e61d0e6629b1cf9b65d2a5 /Utilities
parent9c31d83aa2a3d3f5921f4a5a559e126e285b96c5 (diff)
downloadcmake-c688b401d3adaacc820ef4b589010e8aefa808b1.tar.gz
cmstd: Modernize CMake system headers
Provide a standardized way to handle the C++ "standard" headers customized to be used with current CMake C++ standard constraints. Offer under directory `cm` headers which can be used as direct replacements of the standard ones. For example: #include <cm/string_view> can be used safely for CMake development in place of the `<string_view>` standard header. Fixes: #19491
Diffstat (limited to 'Utilities')
-rw-r--r--Utilities/IWYU/mapping.imp1
-rw-r--r--Utilities/std/.gitattributes1
-rw-r--r--Utilities/std/CMakeLists.txt10
-rw-r--r--Utilities/std/cm/bits/string_view.cxx301
-rw-r--r--Utilities/std/cm/iterator78
-rw-r--r--Utilities/std/cm/memory32
-rw-r--r--Utilities/std/cm/optional344
-rw-r--r--Utilities/std/cm/shared_mutex76
-rw-r--r--Utilities/std/cm/string_view218
-rw-r--r--Utilities/std/cm/utility34
10 files changed, 1094 insertions, 1 deletions
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index 78026fa844..ef31e8befe 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -95,7 +95,6 @@
{ include: [ "<inttypes.h>", public, "\"cm_kwiml.h\"", public ] },
# Self-sufficient wrapper for <sys/stat.h>
- { include: [ "<sys/stat.h>", public, "\"cm_sys_stat.h\"", public ] },
{ symbol: [ "mode_t", private, "\"cm_sys_stat.h\"", public ] },
# Wrappers for 3rd-party libraries used from the system.
diff --git a/Utilities/std/.gitattributes b/Utilities/std/.gitattributes
new file mode 100644
index 0000000000..cd205494f3
--- /dev/null
+++ b/Utilities/std/.gitattributes
@@ -0,0 +1 @@
+cm/* our-c-style
diff --git a/Utilities/std/CMakeLists.txt b/Utilities/std/CMakeLists.txt
new file mode 100644
index 0000000000..63c0a60eae
--- /dev/null
+++ b/Utilities/std/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+# source files for CMake std library
+set(SRCS cm/bits/string_view.cxx
+ cm/memory
+ cm/optional
+ cm/shared_mutex
+ cm/string_view
+ cm/utility)
+
+add_library(cmstd STATIC ${SRCS})
diff --git a/Utilities/std/cm/bits/string_view.cxx b/Utilities/std/cm/bits/string_view.cxx
new file mode 100644
index 0000000000..3b283da4aa
--- /dev/null
+++ b/Utilities/std/cm/bits/string_view.cxx
@@ -0,0 +1,301 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#include <cm/string_view> // IWYU pragma: associated
+
+#ifndef CMake_HAVE_CXX_STRING_VIEW
+
+# include "cm_kwiml.h"
+
+# include <algorithm>
+# include <ostream>
+# include <stdexcept>
+
+namespace cm {
+
+string_view::const_reference string_view::at(size_type pos) const
+{
+ if (pos >= size_) {
+ throw std::out_of_range("Index out of range in string_view::at");
+ }
+ return data_[pos];
+}
+
+string_view::size_type string_view::copy(char* dest, size_type count,
+ size_type pos) const
+{
+ if (pos > size_) {
+ throw std::out_of_range("Index out of range in string_view::copy");
+ }
+ size_type const rcount = std::min(count, size_ - pos);
+ traits_type::copy(dest, data_ + pos, rcount);
+ return rcount;
+}
+
+string_view string_view::substr(size_type pos, size_type count) const
+{
+ if (pos > size_) {
+ throw std::out_of_range("Index out of range in string_view::substr");
+ }
+ size_type const rcount = std::min(count, size_ - pos);
+ return string_view(data_ + pos, rcount);
+}
+
+int string_view::compare(string_view v) const noexcept
+{
+ size_type const rlen = std::min(size_, v.size_);
+ int c = traits_type::compare(data_, v.data_, rlen);
+ if (c == 0) {
+ if (size_ < v.size_) {
+ c = -1;
+ } else if (size_ > v.size_) {
+ c = 1;
+ }
+ }
+ return c;
+}
+
+int string_view::compare(size_type pos1, size_type count1, string_view v) const
+{
+ return substr(pos1, count1).compare(v);
+}
+
+int string_view::compare(size_type pos1, size_type count1, string_view v,
+ size_type pos2, size_type count2) const
+{
+ return substr(pos1, count1).compare(v.substr(pos2, count2));
+}
+
+int string_view::compare(const char* s) const
+{
+ return compare(string_view(s));
+}
+
+int string_view::compare(size_type pos1, size_type count1, const char* s) const
+{
+ return substr(pos1, count1).compare(string_view(s));
+}
+
+int string_view::compare(size_type pos1, size_type count1, const char* s,
+ size_type count2) const
+{
+ return substr(pos1, count1).compare(string_view(s, count2));
+}
+
+string_view::size_type string_view::find(string_view v, size_type pos) const
+ noexcept
+{
+ for (; pos + v.size_ <= size_; ++pos) {
+ if (std::char_traits<char>::compare(data_ + pos, v.data_, v.size_) == 0) {
+ return pos;
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find(char c, size_type pos) const noexcept
+{
+ return find(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find(const char* s, size_type pos,
+ size_type count) const
+{
+ return find(string_view(s, count), pos);
+}
+
+string_view::size_type string_view::find(const char* s, size_type pos) const
+{
+ return find(string_view(s), pos);
+}
+
+string_view::size_type string_view::rfind(string_view v, size_type pos) const
+ noexcept
+{
+ if (size_ >= v.size_) {
+ for (pos = std::min(pos, size_ - v.size_) + 1; pos > 0;) {
+ --pos;
+ if (std::char_traits<char>::compare(data_ + pos, v.data_, v.size_) ==
+ 0) {
+ return pos;
+ }
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::rfind(char c, size_type pos) const noexcept
+{
+ return rfind(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::rfind(const char* s, size_type pos,
+ size_type count) const
+{
+ return rfind(string_view(s, count), pos);
+}
+
+string_view::size_type string_view::rfind(const char* s, size_type pos) const
+{
+ return rfind(string_view(s), pos);
+}
+
+string_view::size_type string_view::find_first_of(string_view v,
+ size_type pos) const noexcept
+{
+ for (; pos < size_; ++pos) {
+ if (traits_type::find(v.data_, v.size_, data_[pos])) {
+ return pos;
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_first_of(char c, size_type pos) const
+ noexcept
+{
+ return find_first_of(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find_first_of(const char* s, size_type pos,
+ size_type count) const
+{
+ return find_first_of(string_view(s, count), pos);
+}
+
+string_view::size_type string_view::find_first_of(const char* s,
+ size_type pos) const
+{
+ return find_first_of(string_view(s), pos);
+}
+
+string_view::size_type string_view::find_last_of(string_view v,
+ size_type pos) const noexcept
+{
+ if (size_ > 0) {
+ for (pos = std::min(pos, size_ - 1) + 1; pos > 0;) {
+ --pos;
+ if (traits_type::find(v.data_, v.size_, data_[pos])) {
+ return pos;
+ }
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_last_of(char c, size_type pos) const
+ noexcept
+{
+ return find_last_of(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find_last_of(const char* s, size_type pos,
+ size_type count) const
+{
+ return find_last_of(string_view(s, count), pos);
+}
+
+string_view::size_type string_view::find_last_of(const char* s,
+ size_type pos) const
+{
+ return find_last_of(string_view(s), pos);
+}
+
+string_view::size_type string_view::find_first_not_of(string_view v,
+ size_type pos) const
+ noexcept
+{
+ for (; pos < size_; ++pos) {
+ if (!traits_type::find(v.data_, v.size_, data_[pos])) {
+ return pos;
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_first_not_of(char c,
+ size_type pos) const
+ noexcept
+{
+ return find_first_not_of(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find_first_not_of(const char* s,
+ size_type pos,
+ size_type count) const
+{
+ return find_first_not_of(string_view(s, count), pos);
+}
+
+string_view::size_type string_view::find_first_not_of(const char* s,
+ size_type pos) const
+{
+ return find_first_not_of(string_view(s), pos);
+}
+
+string_view::size_type string_view::find_last_not_of(string_view v,
+ size_type pos) const
+ noexcept
+{
+ if (size_ > 0) {
+ for (pos = std::min(pos, size_ - 1) + 1; pos > 0;) {
+ --pos;
+ if (!traits_type::find(v.data_, v.size_, data_[pos])) {
+ return pos;
+ }
+ }
+ }
+ return npos;
+}
+
+string_view::size_type string_view::find_last_not_of(char c,
+ size_type pos) const
+ noexcept
+{
+ return find_last_not_of(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find_last_not_of(const char* s,
+ size_type pos,
+ size_type count) const
+{
+ return find_last_not_of(string_view(s, count), pos);
+}
+
+string_view::size_type string_view::find_last_not_of(const char* s,
+ size_type pos) const
+{
+ return find_last_not_of(string_view(s), pos);
+}
+
+std::ostream& operator<<(std::ostream& o, string_view v)
+{
+ return o.write(v.data(), v.size());
+}
+
+std::string& operator+=(std::string& s, string_view v)
+{
+ s.append(v.data(), v.size());
+ return s;
+}
+}
+
+std::hash<cm::string_view>::result_type std::hash<cm::string_view>::operator()(
+ argument_type const& s) const noexcept
+{
+ // FNV-1a hash.
+ static KWIML_INT_uint64_t const fnv_offset_basis = 0xcbf29ce484222325;
+ static KWIML_INT_uint64_t const fnv_prime = 0x100000001b3;
+ KWIML_INT_uint64_t h = fnv_offset_basis;
+ for (char const& c : s) {
+ h = h ^ KWIML_INT_uint64_t(KWIML_INT_uint8_t(c));
+ h = h * fnv_prime;
+ }
+ return result_type(h);
+}
+#else
+// Avoid empty translation unit.
+void cm_string_view_cxx()
+{
+}
+#endif
diff --git a/Utilities/std/cm/iterator b/Utilities/std/cm/iterator
new file mode 100644
index 0000000000..083bce33d0
--- /dev/null
+++ b/Utilities/std/cm/iterator
@@ -0,0 +1,78 @@
+// -*-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_iterator
+#define cm_iterator
+
+#include <iterator> // IWYU pragma: export
+
+namespace cm {
+
+#if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
+using std::make_reverse_iterator;
+
+using std::cbegin;
+using std::cend;
+#else
+template <class Iter>
+std::reverse_iterator<Iter> make_reverse_iterator(Iter it)
+{
+ return std::reverse_iterator<Iter>(it);
+}
+
+// std::c{begin,end} backport from C++14
+template <class C>
+# if defined(_MSC_VER) && _MSC_VER < 1900
+auto cbegin(C const& c)
+# else
+constexpr auto cbegin(C const& c) noexcept(noexcept(std::begin(c)))
+# endif
+ -> decltype(std::begin(c))
+{
+ return std::begin(c);
+}
+
+template <class C>
+# if defined(_MSC_VER) && _MSC_VER < 1900
+auto cend(C const& c)
+# else
+constexpr auto cend(C const& c) noexcept(noexcept(std::end(c)))
+# endif
+ -> decltype(std::end(c))
+{
+ return std::end(c);
+}
+#endif
+
+#if __cplusplus >= 201703L || defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
+using std::size;
+#else
+
+// std::size backport from C++17.
+template <class C>
+# if !defined(_MSC_VER) || _MSC_VER >= 1900
+constexpr
+# endif
+ auto
+ size(C const& c) -> decltype(c.size())
+{
+ return c.size();
+}
+
+template <typename T, size_t N>
+# if !defined(_MSC_VER) || _MSC_VER >= 1900
+constexpr
+# endif
+ std::size_t
+ size(const T (&)[N]) throw()
+{
+ return N;
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/memory b/Utilities/std/cm/memory
new file mode 100644
index 0000000000..8ebded2779
--- /dev/null
+++ b/Utilities/std/cm/memory
@@ -0,0 +1,32 @@
+// -*-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_memory
+#define cm_memory
+
+#include <memory> // IWYU pragma: export
+#if !defined(CMake_HAVE_CXX_MAKE_UNIQUE)
+# include <utility>
+#endif
+
+namespace cm {
+
+#if defined(CMake_HAVE_CXX_MAKE_UNIQUE)
+
+using std::make_unique;
+
+#else
+
+template <typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args&&... args)
+{
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+#endif
+
+} // namespace cm
+
+#endif
diff --git a/Utilities/std/cm/optional b/Utilities/std/cm/optional
new file mode 100644
index 0000000000..80b0951604
--- /dev/null
+++ b/Utilities/std/cm/optional
@@ -0,0 +1,344 @@
+// -*-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_optional
+#define cm_optional
+
+#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+# define CMake_HAVE_CXX_OPTIONAL
+#endif
+
+#if defined(CMake_HAVE_CXX_OPTIONAL)
+# include <optional> // IWYU pragma: export
+#else
+# include <memory>
+
+# include <cm/utility>
+#endif
+
+namespace cm {
+
+#if defined(CMake_HAVE_CXX_OPTIONAL)
+
+using std::nullopt_t;
+using std::nullopt;
+using std::optional;
+using std::bad_optional_access;
+using std::make_optional;
+
+#else
+
+class bad_optional_access : public std::exception
+{
+ using std::exception::exception;
+};
+
+struct nullopt_t
+{
+ explicit constexpr nullopt_t(int) {}
+};
+
+constexpr nullopt_t nullopt{ 0 };
+
+template <typename T>
+class optional
+{
+public:
+ using value_type = T;
+
+ optional() noexcept = default;
+ optional(nullopt_t) noexcept;
+ optional(const optional& other);
+ optional(optional&& other) noexcept;
+
+ template <typename... Args>
+ explicit optional(cm::in_place_t, Args&&... args);
+
+ template <
+ typename U = T,
+ typename = typename std::enable_if<
+ std::is_constructible<T, U&&>::value &&
+ !std::is_same<typename std::decay<U>::type, cm::in_place_t>::value &&
+ !std::is_same<typename std::decay<U>::type,
+ cm::optional<T>>::value>::type>
+ optional(U&& v);
+
+ ~optional();
+
+ optional& operator=(nullopt_t) noexcept;
+ optional& operator=(const optional& other);
+ optional& operator=(optional&& other) noexcept;
+
+ template <
+ typename U = T,
+ typename = typename std::enable_if<
+ !std::is_same<typename std::decay<U>::type, cm::optional<T>>::value &&
+ std::is_constructible<T, U>::value && std::is_assignable<T&, U>::value &&
+ (!std::is_scalar<T>::value ||
+ !std::is_same<typename std::decay<U>::type, T>::value)>::type>
+ optional& operator=(U&& v);
+
+ const T* operator->() const;
+ T* operator->();
+ const T& operator*() const&;
+ T& operator*() &;
+ const T&& operator*() const&&;
+ T&& operator*() &&;
+
+ explicit operator bool() const noexcept;
+ bool has_value() const noexcept;
+
+ T& value() &;
+ const T& value() const&;
+
+ T&& value() &&;
+ const T&& value() const&&;
+
+ template <typename U>
+ T value_or(U&& default_value) const&;
+
+ template <typename U>
+ T value_or(U&& default_value) &&;
+
+ void swap(optional& other) noexcept;
+ void reset() noexcept;
+
+ template <typename... Args>
+ T& emplace(Args&&... args);
+
+private:
+ bool _has_value = false;
+ std::allocator<T> _allocator;
+ union _mem_union
+ {
+ T value;
+
+ // Explicit constructor and destructor is required to make this work
+ _mem_union() noexcept {}
+ ~_mem_union() noexcept {}
+ } _mem;
+};
+
+template <typename T>
+optional<typename std::decay<T>::type> make_optional(T&& value)
+{
+ return optional<typename std::decay<T>::type>(std::forward<T>(value));
+}
+
+template <typename T, class... Args>
+optional<T> make_optional(Args&&... args)
+{
+ return optional<T>(in_place, std::forward<Args>(args)...);
+}
+
+template <typename T>
+optional<T>::optional(nullopt_t) noexcept
+{
+}
+
+template <typename T>
+optional<T>::optional(const optional& other)
+{
+ *this = other;
+}
+
+template <typename T>
+optional<T>::optional(optional&& other) noexcept
+{
+ *this = std::move(other);
+}
+
+template <typename T>
+template <typename... Args>
+optional<T>::optional(cm::in_place_t, Args&&... args)
+{
+ this->emplace(std::forward<Args>(args)...);
+}
+
+template <typename T>
+template <typename U, typename>
+optional<T>::optional(U&& v)
+{
+ this->emplace(std::forward<U>(v));
+}
+
+template <typename T>
+optional<T>::~optional()
+{
+ this->reset();
+}
+
+template <typename T>
+optional<T>& optional<T>::operator=(nullopt_t) noexcept
+{
+ this->reset();
+ return *this;
+}
+
+template <typename T>
+optional<T>& optional<T>::operator=(const optional& other)
+{
+ if (other.has_value()) {
+ if (this->has_value()) {
+ this->value() = *other;
+ } else {
+ this->emplace(*other);
+ }
+ } else {
+ this->reset();
+ }
+ return *this;
+}
+
+template <typename T>
+optional<T>& optional<T>::operator=(optional&& other) noexcept
+{
+ if (other.has_value()) {
+ if (this->has_value()) {
+ this->value() = std::move(*other);
+ } else {
+ this->emplace(std::move(*other));
+ }
+ } else {
+ this->reset();
+ }
+ return *this;
+}
+
+template <typename T>
+template <typename U, typename>
+optional<T>& optional<T>::operator=(U&& v)
+{
+ if (this->has_value()) {
+ this->value() = v;
+ } else {
+ this->emplace(std::forward<U>(v));
+ }
+ return *this;
+}
+
+template <typename T>
+const T* optional<T>::operator->() const
+{
+ return &**this;
+}
+
+template <typename T>
+T* optional<T>::operator->()
+{
+ return &**this;
+}
+
+template <typename T>
+const T& optional<T>::operator*() const&
+{
+ return this->_mem.value;
+}
+
+template <typename T>
+T& optional<T>::operator*() &
+{
+ return this->_mem.value;
+}
+
+template <typename T>
+const T&& optional<T>::operator*() const&&
+{
+ return std::move(**this);
+}
+
+template <typename T>
+T&& optional<T>::operator*() &&
+{
+ return std::move(**this);
+}
+
+template <typename T>
+bool optional<T>::has_value() const noexcept
+{
+ return this->_has_value;
+}
+
+template <typename T>
+optional<T>::operator bool() const noexcept
+{
+ return this->has_value();
+}
+
+template <typename T>
+T& optional<T>::value() &
+{
+ if (!this->has_value()) {
+ throw cm::bad_optional_access{};
+ }
+ return **this;
+}
+
+template <typename T>
+const T& optional<T>::value() const&
+{
+ if (!this->has_value()) {
+ throw cm::bad_optional_access{};
+ }
+ return **this;
+}
+
+template <typename T>
+template <typename U>
+T optional<T>::value_or(U&& default_value) const&
+{
+ return bool(*this) ? **this : static_cast<T>(std::forward<U>(default_value));
+}
+
+template <typename T>
+template <typename U>
+T optional<T>::value_or(U&& default_value) &&
+{
+ return bool(*this) ? std::move(**this)
+ : static_cast<T>(std::forward<U>(default_value));
+}
+
+template <typename T>
+void optional<T>::swap(optional& other) noexcept
+{
+ if (this->has_value()) {
+ if (other.has_value()) {
+ using std::swap;
+ swap(**this, *other);
+ } else {
+ other.emplace(std::move(**this));
+ this->reset();
+ }
+ } else if (other.has_value()) {
+ this->emplace(std::move(*other));
+ other.reset();
+ }
+}
+
+template <typename T>
+void optional<T>::reset() noexcept
+{
+ if (this->has_value()) {
+ this->_has_value = false;
+ std::allocator_traits<std::allocator<T>>::destroy(this->_allocator,
+ &**this);
+ }
+}
+
+template <typename T>
+template <typename... Args>
+T& optional<T>::emplace(Args&&... args)
+{
+ this->reset();
+ std::allocator_traits<std::allocator<T>>::construct(
+ this->_allocator, &**this, std::forward<Args>(args)...);
+ this->_has_value = true;
+ return this->value();
+}
+
+#endif
+}
+
+#endif
diff --git a/Utilities/std/cm/shared_mutex b/Utilities/std/cm/shared_mutex
new file mode 100644
index 0000000000..2ac9447dc7
--- /dev/null
+++ b/Utilities/std/cm/shared_mutex
@@ -0,0 +1,76 @@
+// -*-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_shared_mutex
+#define cm_shared_mutex
+
+#if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
+# define CMake_HAVE_CXX_SHARED_LOCK
+#endif
+#if __cplusplus >= 201703L || defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
+# define CMake_HAVE_CXX_SHARED_MUTEX
+#endif
+
+#if defined(CMake_HAVE_CXX_SHARED_LOCK)
+# include <shared_mutex> // IWYU pragma: export
+#endif
+#if !defined(CMake_HAVE_CXX_SHARED_MUTEX)
+# include "cm_uv.h"
+#endif
+
+namespace cm {
+#if defined(CMake_HAVE_CXX_SHARED_MUTEX)
+using std::shared_mutex;
+#else
+class shared_mutex
+{
+ uv_rwlock_t _M_;
+
+public:
+ using native_handle_type = uv_rwlock_t*;
+
+ shared_mutex() { uv_rwlock_init(&_M_); }
+ ~shared_mutex() { uv_rwlock_destroy(&_M_); }
+
+ shared_mutex(shared_mutex const&) = delete;
+ shared_mutex& operator=(shared_mutex const&) = delete;
+
+ void lock() { uv_rwlock_wrlock(&_M_); }
+ bool try_lock() { return uv_rwlock_trywrlock(&_M_) == 0; }
+ void unlock() { uv_rwlock_wrunlock(&_M_); }
+
+ void lock_shared() { uv_rwlock_rdlock(&_M_); }
+ void unlock_shared() { uv_rwlock_rdunlock(&_M_); }
+
+ native_handle_type native_handle() { return &_M_; }
+};
+#endif
+
+#if defined(CMake_HAVE_CXX_SHARED_LOCK)
+using std::shared_lock;
+#else
+template <typename T>
+class shared_lock
+{
+ T& _mutex;
+
+public:
+ using mutex_type = T;
+
+ shared_lock(T& m)
+ : _mutex(m)
+ {
+ _mutex.lock_shared();
+ }
+
+ ~shared_lock() { _mutex.unlock_shared(); }
+
+ shared_lock(shared_lock const&) = delete;
+ shared_lock& operator=(shared_lock const&) = delete;
+};
+#endif
+}
+
+#endif
diff --git a/Utilities/std/cm/string_view b/Utilities/std/cm/string_view
new file mode 100644
index 0000000000..4d359cb5c3
--- /dev/null
+++ b/Utilities/std/cm/string_view
@@ -0,0 +1,218 @@
+// -*-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_view
+#define cm_string_view
+
+#if __cplusplus >= 201703L || defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
+# define CMake_HAVE_CXX_STRING_VIEW
+#endif
+
+#ifdef CMake_HAVE_CXX_STRING_VIEW
+# include <string_view> // IWYU pragma: export
+namespace cm {
+using std::string_view;
+}
+#else
+# include <cstddef>
+# include <functional>
+# include <iosfwd>
+# include <iterator>
+# include <string>
+
+namespace cm {
+
+class string_view
+{
+public:
+ using traits_type = std::string::traits_type;
+ using value_type = char;
+ using pointer = char*;
+ using const_pointer = const char*;
+ using reference = char&;
+ using const_reference = char const&;
+ using const_iterator = const char*;
+ using iterator = const_iterator;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using reverse_iterator = const_reverse_iterator;
+ using size_type = std::string::size_type;
+ using difference_type = std::string::difference_type;
+
+ static size_type const npos = static_cast<size_type>(-1);
+
+ string_view() noexcept = default;
+ string_view(string_view const&) noexcept = default;
+
+ string_view(const char* s, size_t count) noexcept
+ : data_(s)
+ , size_(count)
+ {
+ }
+
+ string_view(const char* s) noexcept
+ : data_(s)
+ , size_(traits_type::length(s))
+ {
+ }
+
+ // C++17 does not define this constructor. Instead it defines
+ // a conversion operator on std::string to create a string_view.
+ // Since this implementation is used in C++11, std::string does
+ // not have that conversion.
+ string_view(std::string const& s) noexcept
+ : data_(s.data())
+ , size_(s.size())
+ {
+ }
+
+ // C++17 does not define this conversion. Instead it defines
+ // a constructor on std::string that can take a string_view.
+ // Since this implementation is used in C++11, std::string does
+ // not have that constructor.
+ explicit operator std::string() const { return std::string(data_, size_); }
+
+ string_view& operator=(string_view const&) = default;
+
+ const_iterator begin() const noexcept { return data_; }
+ const_iterator end() const noexcept { return data_ + size_; }
+ const_iterator cbegin() const noexcept { return begin(); }
+ const_iterator cend() const noexcept { return end(); }
+
+ const_reverse_iterator rbegin() const noexcept
+ {
+ return const_reverse_iterator(end());
+ }
+ const_reverse_iterator rend() const noexcept
+ {
+ return const_reverse_iterator(begin());
+ }
+ const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+ const_reverse_iterator crend() const noexcept { return rend(); }
+
+ const_reference operator[](size_type pos) const noexcept
+ {
+ return data_[pos];
+ }
+ const_reference at(size_type pos) const;
+ const_reference front() const noexcept { return data_[0]; }
+ const_reference back() const noexcept { return data_[size_ - 1]; }
+ const_pointer data() const noexcept { return data_; }
+
+ size_type size() const noexcept { return size_; }
+ size_type length() const noexcept { return size_; }
+ size_type max_size() const noexcept { return npos - 1; }
+ bool empty() const noexcept { return size_ == 0; }
+
+ void remove_prefix(size_type n) noexcept
+ {
+ data_ += n;
+ size_ -= n;
+ }
+ void remove_suffix(size_type n) noexcept { size_ -= n; }
+ void swap(string_view& v) noexcept
+ {
+ string_view tmp = v;
+ v = *this;
+ *this = tmp;
+ }
+
+ size_type copy(char* dest, size_type count, size_type pos = 0) const;
+ string_view substr(size_type pos = 0, size_type count = npos) const;
+
+ int compare(string_view v) const noexcept;
+ int compare(size_type pos1, size_type count1, string_view v) const;
+ int compare(size_type pos1, size_type count1, string_view v, size_type pos2,
+ size_type count2) const;
+ int compare(const char* s) const;
+ int compare(size_type pos1, size_type count1, const char* s) const;
+ int compare(size_type pos1, size_type count1, const char* s,
+ size_type count2) const;
+
+ size_type find(string_view v, size_type pos = 0) const noexcept;
+ size_type find(char c, size_type pos = 0) const noexcept;
+ size_type find(const char* s, size_type pos, size_type count) const;
+ size_type find(const char* s, size_type pos = 0) const;
+
+ size_type rfind(string_view v, size_type pos = npos) const noexcept;
+ size_type rfind(char c, size_type pos = npos) const noexcept;
+ size_type rfind(const char* s, size_type pos, size_type count) const;
+ size_type rfind(const char* s, size_type pos = npos) const;
+
+ size_type find_first_of(string_view v, size_type pos = 0) const noexcept;
+ size_type find_first_of(char c, size_type pos = 0) const noexcept;
+ size_type find_first_of(const char* s, size_type pos, size_type count) const;
+ size_type find_first_of(const char* s, size_type pos = 0) const;
+
+ size_type find_last_of(string_view v, size_type pos = npos) const noexcept;
+ size_type find_last_of(char c, size_type pos = npos) const noexcept;
+ size_type find_last_of(const char* s, size_type pos, size_type count) const;
+ size_type find_last_of(const char* s, size_type pos = npos) const;
+
+ size_type find_first_not_of(string_view v, size_type pos = 0) const noexcept;
+ size_type find_first_not_of(char c, size_type pos = 0) const noexcept;
+ size_type find_first_not_of(const char* s, size_type pos,
+ size_type count) const;
+ size_type find_first_not_of(const char* s, size_type pos = 0) const;
+
+ size_type find_last_not_of(string_view v, size_type pos = npos) const
+ noexcept;
+ size_type find_last_not_of(char c, size_type pos = npos) const noexcept;
+ size_type find_last_not_of(const char* s, size_type pos,
+ size_type count) const;
+ size_type find_last_not_of(const char* s, size_type pos = npos) const;
+
+private:
+ const char* data_ = nullptr;
+ size_type size_ = 0;
+};
+
+std::ostream& operator<<(std::ostream& o, string_view v);
+
+std::string& operator+=(std::string& s, string_view v);
+
+inline bool operator==(string_view l, string_view r) noexcept
+{
+ return l.compare(r) == 0;
+}
+
+inline bool operator!=(string_view l, string_view r) noexcept
+{
+ return l.compare(r) != 0;
+}
+
+inline bool operator<(string_view l, string_view r) noexcept
+{
+ return l.compare(r) < 0;
+}
+
+inline bool operator<=(string_view l, string_view r) noexcept
+{
+ return l.compare(r) <= 0;
+}
+
+inline bool operator>(string_view l, string_view r) noexcept
+{
+ return l.compare(r) > 0;
+}
+
+inline bool operator>=(string_view l, string_view r) noexcept
+{
+ return l.compare(r) >= 0;
+}
+}
+
+namespace std {
+
+template <>
+struct hash<cm::string_view>
+{
+ using argument_type = cm::string_view;
+ using result_type = size_t;
+ result_type operator()(argument_type const& s) const noexcept;
+};
+}
+
+#endif
+#endif
diff --git a/Utilities/std/cm/utility b/Utilities/std/cm/utility
new file mode 100644
index 0000000000..3acac4f69d
--- /dev/null
+++ b/Utilities/std/cm/utility
@@ -0,0 +1,34 @@
+// -*-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_utility
+#define cm_utility
+
+#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+# define CMake_HAVE_CXX_IN_PLACE
+#endif
+
+#include <utility> // IWYU pragma: export
+
+namespace cm {
+
+#if defined(CMake_HAVE_CXX_IN_PLACE)
+
+using std::in_place_t;
+using std::in_place;
+
+#else
+
+struct in_place_t
+{
+ explicit in_place_t() = default;
+};
+
+constexpr in_place_t in_place{};
+
+#endif
+}
+
+#endif