diff --git a/3rdparty/include/gsl/algorithm b/3rdparty/include/gsl/algorithm new file mode 100644 index 00000000000..584f5cd12be --- /dev/null +++ b/3rdparty/include/gsl/algorithm @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_ALGORITHM_H +#define GSL_ALGORITHM_H + +#include "assert" // for Expects +#include "span" // for dynamic_extent, span + +#include // for copy_n +#include // for ptrdiff_t +#include // for is_assignable + +#ifdef _MSC_VER +#pragma warning(push) + +// turn off some warnings that are noisy about our Expects statements +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4996) // unsafe use of std::copy_n + +#endif // _MSC_VER + +namespace gsl +{ +// Note: this will generate faster code than std::copy using span iterator in older msvc+stl +// not necessary for msvc since VS2017 15.8 (_MSC_VER >= 1915) +template +void copy(span src, span dest) +{ + static_assert(std::is_assignable::value, + "Elements of source span can not be assigned to elements of destination span"); + static_assert(SrcExtent == dynamic_extent || DestExtent == dynamic_extent || + (SrcExtent <= DestExtent), + "Source range is longer than target range"); + + Expects(dest.size() >= src.size()); + // clang-format off + GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute + // clang-format on + std::copy_n(src.data(), src.size(), dest.data()); +} + +} // namespace gsl + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // GSL_ALGORITHM_H diff --git a/3rdparty/include/gsl/assert b/3rdparty/include/gsl/assert new file mode 100644 index 00000000000..a6012048fc8 --- /dev/null +++ b/3rdparty/include/gsl/assert @@ -0,0 +1,136 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_CONTRACTS_H +#define GSL_CONTRACTS_H + +// +// Temporary until MSVC STL supports no-exceptions mode. +// Currently terminate is a no-op in this mode, so we add termination behavior back +// +#if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)) +#define GSL_KERNEL_MODE + +#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND +#include +#define RANGE_CHECKS_FAILURE 0 + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#endif // defined(__clang__) + +#else // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && + // !_HAS_EXCEPTIONS)) + +#include + +#endif // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && + // !_HAS_EXCEPTIONS)) + +// +// make suppress attributes parse for some compilers +// Hopefully temporary until suppression standardization occurs +// +#if defined(__clang__) +#define GSL_SUPPRESS(x) [[gsl::suppress("x")]] +#else +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define GSL_SUPPRESS(x) [[gsl::suppress(x)]] +#else +#define GSL_SUPPRESS(x) +#endif // _MSC_VER +#endif // __clang__ + +#define GSL_STRINGIFY_DETAIL(x) #x +#define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x) + +#if defined(__clang__) || defined(__GNUC__) +#define GSL_LIKELY(x) __builtin_expect(!!(x), 1) +#define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0) + +#else + +#define GSL_LIKELY(x) (!!(x)) +#define GSL_UNLIKELY(x) (!!(x)) +#endif // defined(__clang__) || defined(__GNUC__) + +// +// GSL_ASSUME(cond) +// +// Tell the optimizer that the predicate cond must hold. It is unspecified +// whether or not cond is actually evaluated. +// +#ifdef _MSC_VER +#define GSL_ASSUME(cond) __assume(cond) +#elif defined(__GNUC__) +#define GSL_ASSUME(cond) ((cond) ? static_cast(0) : __builtin_unreachable()) +#else +#define GSL_ASSUME(cond) static_cast((cond) ? 0 : 0) +#endif + +// +// GSL.assert: assertions +// + +namespace gsl +{ + +namespace details +{ +#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) + + typedef void(__cdecl* terminate_handler)(); + + // clang-format off + GSL_SUPPRESS(f.6) // NO-FORMAT: attribute + // clang-format on + [[noreturn]] inline void __cdecl default_terminate_handler() + { + __fastfail(RANGE_CHECKS_FAILURE); + } + + inline gsl::details::terminate_handler& get_terminate_handler() noexcept + { + static terminate_handler handler = &default_terminate_handler; + return handler; + } + +#endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) + + [[noreturn]] inline void terminate() noexcept + { +#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) + (*gsl::details::get_terminate_handler())(); +#else + std::terminate(); +#endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) + } + +} // namespace details +} // namespace gsl + +#define GSL_CONTRACT_CHECK(type, cond) \ + (GSL_LIKELY(cond) ? static_cast(0) : gsl::details::terminate()) + +#define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond) +#define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond) + +#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif // GSL_CONTRACTS_H diff --git a/3rdparty/include/gsl/byte b/3rdparty/include/gsl/byte new file mode 100644 index 00000000000..9231340b568 --- /dev/null +++ b/3rdparty/include/gsl/byte @@ -0,0 +1,213 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_BYTE_H +#define GSL_BYTE_H + +// +// make suppress attributes work for some compilers +// Hopefully temporary until suppression standardization occurs +// +#if defined(__clang__) +#define GSL_SUPPRESS(x) [[gsl::suppress("x")]] +#else +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define GSL_SUPPRESS(x) [[gsl::suppress(x)]] +#else +#define GSL_SUPPRESS(x) +#endif // _MSC_VER +#endif // __clang__ + +#include + +// VS2017 15.8 added support for the __cpp_lib_byte definition +// To do: drop _HAS_STD_BYTE when support for pre 15.8 expires +#ifdef _MSC_VER + +#pragma warning(push) + +// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. +#pragma warning(disable : 26493) // don't use c-style casts // TODO: MSVC suppression in templates + // does not always work + +#ifndef GSL_USE_STD_BYTE +// this tests if we are under MSVC and the standard lib has std::byte and it is enabled +#if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || \ + (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603) + +#define GSL_USE_STD_BYTE 1 + +#else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= + // 201603) + +#define GSL_USE_STD_BYTE 0 + +#endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= + // 201603) +#endif // GSL_USE_STD_BYTE + +#else // _MSC_VER + +#ifndef GSL_USE_STD_BYTE +#include /* __cpp_lib_byte */ +// this tests if we are under GCC or Clang with enough -std=c++1z power to get us std::byte +// also check if libc++ version is sufficient (> 5.0) or libstdc++ actually contains std::byte +#if defined(__cplusplus) && (__cplusplus >= 201703L) && \ + (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || \ + defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) + +#define GSL_USE_STD_BYTE 1 + +#else // defined(__cplusplus) && (__cplusplus >= 201703L) && + // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || + // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) + +#define GSL_USE_STD_BYTE 0 + +#endif // defined(__cplusplus) && (__cplusplus >= 201703L) && + // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || + // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000)) +#endif // GSL_USE_STD_BYTE + +#endif // _MSC_VER + +// Use __may_alias__ attribute on gcc and clang +#if defined __clang__ || (defined(__GNUC__) && __GNUC__ > 5) +#define byte_may_alias __attribute__((__may_alias__)) +#else // defined __clang__ || defined __GNUC__ +#define byte_may_alias +#endif // defined __clang__ || defined __GNUC__ + +#if GSL_USE_STD_BYTE +#include +#endif + +namespace gsl +{ +#if GSL_USE_STD_BYTE + +using std::byte; +using std::to_integer; + +#else // GSL_USE_STD_BYTE + +// This is a simple definition for now that allows +// use of byte within span<> to be standards-compliant +enum class byte_may_alias byte : unsigned char +{ +}; + +template ::value>> +constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept +{ + return b = byte(static_cast(b) << shift); +} + +template ::value>> +constexpr byte operator<<(byte b, IntegerType shift) noexcept +{ + return byte(static_cast(b) << shift); +} + +template ::value>> +constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept +{ + return b = byte(static_cast(b) >> shift); +} + +template ::value>> +constexpr byte operator>>(byte b, IntegerType shift) noexcept +{ + return byte(static_cast(b) >> shift); +} + +constexpr byte& operator|=(byte& l, byte r) noexcept +{ + return l = byte(static_cast(l) | static_cast(r)); +} + +constexpr byte operator|(byte l, byte r) noexcept +{ + return byte(static_cast(l) | static_cast(r)); +} + +constexpr byte& operator&=(byte& l, byte r) noexcept +{ + return l = byte(static_cast(l) & static_cast(r)); +} + +constexpr byte operator&(byte l, byte r) noexcept +{ + return byte(static_cast(l) & static_cast(r)); +} + +constexpr byte& operator^=(byte& l, byte r) noexcept +{ + return l = byte(static_cast(l) ^ static_cast(r)); +} + +constexpr byte operator^(byte l, byte r) noexcept +{ + return byte(static_cast(l) ^ static_cast(r)); +} + +constexpr byte operator~(byte b) noexcept { return byte(~static_cast(b)); } + +template ::value>> +constexpr IntegerType to_integer(byte b) noexcept +{ + return static_cast(b); +} + +#endif // GSL_USE_STD_BYTE + +template +constexpr byte to_byte_impl(T t) noexcept +{ + static_assert( + E, "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. " + "If you are calling to_byte with an integer contant use: gsl::to_byte() version."); + return static_cast(t); +} +template <> +// NOTE: need suppression since c++14 does not allow "return {t}" +// GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work +constexpr byte to_byte_impl(unsigned char t) noexcept +{ + return byte(t); +} + +template +constexpr byte to_byte(T t) noexcept +{ + return to_byte_impl::value, T>(t); +} + +template +constexpr byte to_byte() noexcept +{ + static_assert(I >= 0 && I <= 255, + "gsl::byte only has 8 bits of storage, values must be in range 0-255"); + return static_cast(I); +} + +} // namespace gsl + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // GSL_BYTE_H diff --git a/3rdparty/include/gsl/gsl b/3rdparty/include/gsl/gsl new file mode 100644 index 00000000000..3d9e288f2bd --- /dev/null +++ b/3rdparty/include/gsl/gsl @@ -0,0 +1,32 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_GSL_H +#define GSL_GSL_H + +#include "algorithm" // copy +#include "assert" // Ensures/Expects +#include "byte" // byte +#include "pointers" // owner, not_null +#include "span" // span +#include "string_span" // zstring, string_span, zstring_builder... +#include "util" // finally()/narrow_cast()... + +#ifdef __cpp_exceptions +#include "narrow" // narrow() +#endif + +#endif // GSL_GSL_H diff --git a/3rdparty/include/gsl/gsl_algorithm b/3rdparty/include/gsl/gsl_algorithm new file mode 100644 index 00000000000..d516e2ee69c --- /dev/null +++ b/3rdparty/include/gsl/gsl_algorithm @@ -0,0 +1,4 @@ +#pragma once +#pragma message( \ + "This header will soon be removed. Use instead of ") +#include "algorithm" diff --git a/3rdparty/include/gsl/gsl_assert b/3rdparty/include/gsl/gsl_assert new file mode 100644 index 00000000000..35a6e7859b9 --- /dev/null +++ b/3rdparty/include/gsl/gsl_assert @@ -0,0 +1,3 @@ +#pragma once +#pragma message("This header will soon be removed. Use instead of ") +#include "assert" diff --git a/3rdparty/include/gsl/gsl_byte b/3rdparty/include/gsl/gsl_byte new file mode 100644 index 00000000000..399025cb022 --- /dev/null +++ b/3rdparty/include/gsl/gsl_byte @@ -0,0 +1,3 @@ +#pragma once +#pragma message("This header will soon be removed. Use instead of ") +#include "byte" diff --git a/3rdparty/include/gsl/gsl_narrow b/3rdparty/include/gsl/gsl_narrow new file mode 100644 index 00000000000..59685fc8f50 --- /dev/null +++ b/3rdparty/include/gsl/gsl_narrow @@ -0,0 +1,3 @@ +#pragma once +#pragma message("This header will soon be removed. Use instead of ") +#include "narrow" diff --git a/3rdparty/include/gsl/gsl_util b/3rdparty/include/gsl/gsl_util new file mode 100644 index 00000000000..bd17d3e27a7 --- /dev/null +++ b/3rdparty/include/gsl/gsl_util @@ -0,0 +1,3 @@ +#pragma once +#pragma message("This header will soon be removed. Use instead of ") +#include "util" diff --git a/3rdparty/include/gsl/narrow b/3rdparty/include/gsl/narrow new file mode 100644 index 00000000000..1451c54f873 --- /dev/null +++ b/3rdparty/include/gsl/narrow @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_NARROW_H +#define GSL_NARROW_H +#include "assert" // for Expects +#include "util" // for narrow_cast +namespace gsl +{ +struct narrowing_error : public std::exception +{ + const char* what() const noexcept override { return "narrowing_error"; } +}; + +// narrow() : a checked version of narrow_cast() that throws if the cast changed the value +template ::value>::type* = nullptr> +// clang-format off +GSL_SUPPRESS(type.1) // NO-FORMAT: attribute +GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) + // clang-format on + constexpr T narrow(U u) noexcept(false) +{ + constexpr const bool is_different_signedness = + (std::is_signed::value != std::is_signed::value); + +GSL_SUPPRESS(es.103) // NO-FORMAT: attribute // don't overflow +GSL_SUPPRESS(es.104) // NO-FORMAT: attribute // don't underflow +GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior + const T t = narrow_cast(u); // While this is technically undefined behavior in some cases (i.e., if the source value is of floating-point type + // and cannot fit into the destination integral type), the resultant behavior is benign on the platforms + // that we target (i.e., no hardware trap representations are hit). + + if (static_cast(t) != u || (is_different_signedness && ((t < T{}) != (u < U{})))) + { + throw narrowing_error{}; + } + + return t; +} + +template ::value>::type* = nullptr> +// clang-format off +GSL_SUPPRESS(type.1) // NO-FORMAT: attribute +GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false) + // clang-format on + constexpr T narrow(U u) noexcept(false) +{ + const T t = narrow_cast(u); + + if (static_cast(t) != u) + { + throw narrowing_error{}; + } + + return t; +} +} // namespace gsl +#endif // GSL_NARROW_H diff --git a/3rdparty/include/gsl/pointers b/3rdparty/include/gsl/pointers new file mode 100644 index 00000000000..a0a77ac9c26 --- /dev/null +++ b/3rdparty/include/gsl/pointers @@ -0,0 +1,323 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_POINTERS_H +#define GSL_POINTERS_H + +#include "assert" // for Ensures, Expects + +#include // for forward +#include // for ptrdiff_t, nullptr_t, size_t +#include // for shared_ptr, unique_ptr +#include // for hash +#include // for enable_if_t, is_convertible, is_assignable + +#if !defined(GSL_NO_IOSTREAMS) +#include // for ostream +#endif // !defined(GSL_NO_IOSTREAMS) + +namespace gsl +{ + +namespace details +{ + template + struct is_comparable_to_nullptr : std::false_type + { + }; + + template + struct is_comparable_to_nullptr< + T, + std::enable_if_t() != nullptr), bool>::value>> + : std::true_type + { + }; +} // namespace details + +// +// GSL.owner: ownership pointers +// +using std::shared_ptr; +using std::unique_ptr; + +// +// owner +// +// owner is designed as a bridge for code that must deal directly with owning pointers for some +// reason +// +// T must be a pointer type +// - disallow construction from any type other than pointer type +// +template ::value>> +using owner = T; + +// +// not_null +// +// Restricts a pointer or smart pointer to only hold non-null values. +// +// Has zero size overhead over T. +// +// If T is a pointer (i.e. T == U*) then +// - allow construction from U* +// - disallow construction from nullptr_t +// - disallow default construction +// - ensure construction from null U* fails +// - allow implicit conversion to U* +// +template +class not_null +{ +public: + static_assert(details::is_comparable_to_nullptr::value, "T cannot be compared to nullptr."); + + template ::value>> + constexpr not_null(U&& u) : ptr_(std::forward(u)) + { + Expects(ptr_ != nullptr); + } + + template ::value>> + constexpr not_null(T u) : ptr_(std::move(u)) + { + Expects(ptr_ != nullptr); + } + + template ::value>> + constexpr not_null(const not_null& other) : not_null(other.get()) + {} + + not_null(const not_null& other) = default; + not_null& operator=(const not_null& other) = default; + constexpr std::conditional_t::value, T, const T&> get() const + { + Ensures(ptr_ != nullptr); + return ptr_; + } + + constexpr operator T() const { return get(); } + constexpr decltype(auto) operator->() const { return get(); } + constexpr decltype(auto) operator*() const { return *get(); } + + // prevents compilation when someone attempts to assign a null pointer constant + not_null(std::nullptr_t) = delete; + not_null& operator=(std::nullptr_t) = delete; + + // unwanted operators...pointers only point to single objects! + not_null& operator++() = delete; + not_null& operator--() = delete; + not_null operator++(int) = delete; + not_null operator--(int) = delete; + not_null& operator+=(std::ptrdiff_t) = delete; + not_null& operator-=(std::ptrdiff_t) = delete; + void operator[](std::ptrdiff_t) const = delete; + +private: + T ptr_; +}; + +template +auto make_not_null(T&& t) noexcept +{ + return not_null>>{std::forward(t)}; +} + +#if !defined(GSL_NO_IOSTREAMS) +template +std::ostream& operator<<(std::ostream& os, const not_null& val) +{ + os << val.get(); + return os; +} +#endif // !defined(GSL_NO_IOSTREAMS) + +template +auto operator==(const not_null& lhs, + const not_null& rhs) noexcept(noexcept(lhs.get() == rhs.get())) + -> decltype(lhs.get() == rhs.get()) +{ + return lhs.get() == rhs.get(); +} + +template +auto operator!=(const not_null& lhs, + const not_null& rhs) noexcept(noexcept(lhs.get() != rhs.get())) + -> decltype(lhs.get() != rhs.get()) +{ + return lhs.get() != rhs.get(); +} + +template +auto operator<(const not_null& lhs, + const not_null& rhs) noexcept(noexcept(lhs.get() < rhs.get())) + -> decltype(lhs.get() < rhs.get()) +{ + return lhs.get() < rhs.get(); +} + +template +auto operator<=(const not_null& lhs, + const not_null& rhs) noexcept(noexcept(lhs.get() <= rhs.get())) + -> decltype(lhs.get() <= rhs.get()) +{ + return lhs.get() <= rhs.get(); +} + +template +auto operator>(const not_null& lhs, + const not_null& rhs) noexcept(noexcept(lhs.get() > rhs.get())) + -> decltype(lhs.get() > rhs.get()) +{ + return lhs.get() > rhs.get(); +} + +template +auto operator>=(const not_null& lhs, + const not_null& rhs) noexcept(noexcept(lhs.get() >= rhs.get())) + -> decltype(lhs.get() >= rhs.get()) +{ + return lhs.get() >= rhs.get(); +} + +// more unwanted operators +template +std::ptrdiff_t operator-(const not_null&, const not_null&) = delete; +template +not_null operator-(const not_null&, std::ptrdiff_t) = delete; +template +not_null operator+(const not_null&, std::ptrdiff_t) = delete; +template +not_null operator+(std::ptrdiff_t, const not_null&) = delete; + +} // namespace gsl + +namespace std +{ +template +struct hash> +{ + std::size_t operator()(const gsl::not_null& value) const { return hash{}(value.get()); } +}; + +} // namespace std + +namespace gsl +{ + +// +// strict_not_null +// +// Restricts a pointer or smart pointer to only hold non-null values, +// +// - provides a strict (i.e. explicit constructor from T) wrapper of not_null +// - to be used for new code that wishes the design to be cleaner and make not_null +// checks intentional, or in old code that would like to make the transition. +// +// To make the transition from not_null, incrementally replace not_null +// by strict_not_null and fix compilation errors +// +// Expect to +// - remove all unneeded conversions from raw pointer to not_null and back +// - make API clear by specifying not_null in parameters where needed +// - remove unnecessary asserts +// +template +class strict_not_null : public not_null +{ +public: + template ::value>> + constexpr explicit strict_not_null(U&& u) : not_null(std::forward(u)) + {} + + template ::value>> + constexpr explicit strict_not_null(T u) : not_null(u) + {} + + template ::value>> + constexpr strict_not_null(const not_null& other) : not_null(other) + {} + + template ::value>> + constexpr strict_not_null(const strict_not_null& other) : not_null(other) + {} + + strict_not_null(strict_not_null&& other) = default; + strict_not_null(const strict_not_null& other) = default; + strict_not_null& operator=(const strict_not_null& other) = default; + strict_not_null& operator=(const not_null& other) + { + not_null::operator=(other); + return *this; + } + + // prevents compilation when someone attempts to assign a null pointer constant + strict_not_null(std::nullptr_t) = delete; + strict_not_null& operator=(std::nullptr_t) = delete; + + // unwanted operators...pointers only point to single objects! + strict_not_null& operator++() = delete; + strict_not_null& operator--() = delete; + strict_not_null operator++(int) = delete; + strict_not_null operator--(int) = delete; + strict_not_null& operator+=(std::ptrdiff_t) = delete; + strict_not_null& operator-=(std::ptrdiff_t) = delete; + void operator[](std::ptrdiff_t) const = delete; +}; + +// more unwanted operators +template +std::ptrdiff_t operator-(const strict_not_null&, const strict_not_null&) = delete; +template +strict_not_null operator-(const strict_not_null&, std::ptrdiff_t) = delete; +template +strict_not_null operator+(const strict_not_null&, std::ptrdiff_t) = delete; +template +strict_not_null operator+(std::ptrdiff_t, const strict_not_null&) = delete; + +template +auto make_strict_not_null(T&& t) noexcept +{ + return strict_not_null>>{std::forward(t)}; +} + +#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) + +// deduction guides to prevent the ctad-maybe-unsupported warning +template +not_null(T) -> not_null; +template +strict_not_null(T) -> strict_not_null; + +#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) ) + +} // namespace gsl + +namespace std +{ +template +struct hash> +{ + std::size_t operator()(const gsl::strict_not_null& value) const + { + return hash{}(value.get()); + } +}; + +} // namespace std + +#endif // GSL_POINTERS_H diff --git a/3rdparty/include/gsl/span b/3rdparty/include/gsl/span new file mode 100644 index 00000000000..12f8f81db84 --- /dev/null +++ b/3rdparty/include/gsl/span @@ -0,0 +1,821 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_SPAN_H +#define GSL_SPAN_H + +#include "assert" // for Expects +#include "byte" // for byte +#include "util" // for narrow_cast + +#include // for array +#include // for ptrdiff_t, size_t, nullptr_t +#include "span_ext" // for span specialization of gsl::at and other span-related extensions +#include // for reverse_iterator, distance, random_access_... +#include // for enable_if_t, declval, is_convertible, inte... + +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) + +// turn off some warnings that are noisy about our Expects statements +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning( \ + disable : 4146) // unary minus operator applied to unsigned type, result still unsigned +#pragma warning(disable : 4702) // unreachable code + +// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. +#pragma warning(disable : 26495) // uninitalized member when constructor calls constructor +#pragma warning(disable : 26446) // parser bug does not allow attributes on some templates + +#endif // _MSC_VER + +// See if we have enough C++17 power to use a static constexpr data member +// without needing an out-of-line definition +#if !(defined(__cplusplus) && (__cplusplus >= 201703L)) +#define GSL_USE_STATIC_CONSTEXPR_WORKAROUND +#endif // !(defined(__cplusplus) && (__cplusplus >= 201703L)) + +// GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t) +// While there is a conversion from signed to unsigned, it happens at +// compiletime, so the compiler wouldn't have to warn indiscriminately, but +// could check if the source value actually doesn't fit into the target type +// and only warn in those cases. +#if defined(__GNUC__) && __GNUC__ > 6 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +namespace gsl +{ + +// implementation details +namespace details +{ + template + struct is_span_oracle : std::false_type + { + }; + + template + struct is_span_oracle> : std::true_type + { + }; + + template + struct is_span : public is_span_oracle> + { + }; + + template + struct is_std_array_oracle : std::false_type + { + }; + + template + struct is_std_array_oracle> : std::true_type + { + }; + + template + struct is_std_array : is_std_array_oracle> + { + }; + + template + struct is_allowed_extent_conversion + : std::integral_constant + { + }; + + template + struct is_allowed_element_type_conversion + : std::integral_constant::value> + { + }; + + template + class span_iterator + { + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = std::remove_cv_t; + using difference_type = std::ptrdiff_t; + using pointer = Type*; + using reference = Type&; + +#ifdef _MSC_VER + using _Unchecked_type = pointer; +#endif // _MSC_VER + constexpr span_iterator() = default; + + constexpr span_iterator(pointer begin, pointer end, pointer current) + : begin_(begin), end_(end), current_(current) + {} + + constexpr operator span_iterator() const noexcept + { + return {begin_, end_, current_}; + } + + constexpr reference operator*() const noexcept + { + Expects(begin_ && end_); + Expects(begin_ <= current_ && current_ < end_); + return *current_; + } + + constexpr pointer operator->() const noexcept + { + Expects(begin_ && end_); + Expects(begin_ <= current_ && current_ < end_); + return current_; + } + constexpr span_iterator& operator++() noexcept + { + Expects(begin_ && current_ && end_); + Expects(current_ < end_); + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + ++current_; + return *this; + } + + constexpr span_iterator operator++(int) noexcept + { + span_iterator ret = *this; + ++*this; + return ret; + } + + constexpr span_iterator& operator--() noexcept + { + Expects(begin_ && end_); + Expects(begin_ < current_); + --current_; + return *this; + } + + constexpr span_iterator operator--(int) noexcept + { + span_iterator ret = *this; + --*this; + return ret; + } + + constexpr span_iterator& operator+=(const difference_type n) noexcept + { + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(end_ - current_ >= n); + if (n < 0) Expects(current_ - begin_ >= -n); + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + current_ += n; + return *this; + } + + constexpr span_iterator operator+(const difference_type n) const noexcept + { + span_iterator ret = *this; + ret += n; + return ret; + } + + friend constexpr span_iterator operator+(const difference_type n, + const span_iterator& rhs) noexcept + { + return rhs + n; + } + + constexpr span_iterator& operator-=(const difference_type n) noexcept + { + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(current_ - begin_ >= n); + if (n < 0) Expects(end_ - current_ >= -n); + current_ -= n; + return *this; + } + + constexpr span_iterator operator-(const difference_type n) const noexcept + { + span_iterator ret = *this; + ret -= n; + return ret; + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr difference_type operator-(const span_iterator& rhs) const noexcept + { + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ - rhs.current_; + } + + constexpr reference operator[](const difference_type n) const noexcept + { + return *(*this + n); + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator==(const span_iterator& rhs) const noexcept + { + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ == rhs.current_; + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator!=(const span_iterator& rhs) const noexcept + { + return !(*this == rhs); + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<(const span_iterator& rhs) const noexcept + { + Expects(begin_ == rhs.begin_ && end_ == rhs.end_); + return current_ < rhs.current_; + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>(const span_iterator& rhs) const noexcept + { + return rhs < *this; + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator<=(const span_iterator& rhs) const noexcept + { + return !(rhs < *this); + } + + template < + class Type2, + std::enable_if_t, value_type>::value, int> = 0> + constexpr bool operator>=(const span_iterator& rhs) const noexcept + { + return !(*this < rhs); + } + +#ifdef _MSC_VER + // MSVC++ iterator debugging support; allows STL algorithms in 15.8+ + // to unwrap span_iterator to a pointer type after a range check in STL + // algorithm calls + friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept + { // test that [lhs, rhs) forms a valid range inside an STL algorithm + Expects(lhs.begin_ == rhs.begin_ // range spans have to match + && lhs.end_ == rhs.end_ && + lhs.current_ <= rhs.current_); // range must not be transposed + } + + constexpr void _Verify_offset(const difference_type n) const noexcept + { // test that *this + n is within the range of this call + if (n != 0) Expects(begin_ && current_ && end_); + if (n > 0) Expects(end_ - current_ >= n); + if (n < 0) Expects(current_ - begin_ >= -n); + } + + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + constexpr pointer _Unwrapped() const noexcept + { // after seeking *this to a high water mark, or using one of the + // _Verify_xxx functions above, unwrap this span_iterator to a raw + // pointer + return current_; + } + + // Tell the STL that span_iterator should not be unwrapped if it can't + // validate in advance, even in release / optimized builds: +#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) + static constexpr const bool _Unwrap_when_unverified = false; +#else + static constexpr bool _Unwrap_when_unverified = false; +#endif + // clang-format off + GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive + // clang-format on + constexpr void _Seek_to(const pointer p) noexcept + { // adjust the position of *this to previously verified location p + // after _Unwrapped + current_ = p; + } +#endif + + pointer begin_ = nullptr; + pointer end_ = nullptr; + pointer current_ = nullptr; + }; + + template + class extent_type + { + public: + using size_type = std::size_t; + + constexpr extent_type() noexcept = default; + + constexpr explicit extent_type(extent_type); + + constexpr explicit extent_type(size_type size) { Expects(size == Ext); } + + constexpr size_type size() const noexcept { return Ext; } + + private: +#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) + static constexpr const size_type size_ = Ext; // static size equal to Ext +#else + static constexpr size_type size_ = Ext; // static size equal to Ext +#endif + }; + + template <> + class extent_type + { + public: + using size_type = std::size_t; + + template + constexpr explicit extent_type(extent_type ext) : size_(ext.size()) + {} + + constexpr explicit extent_type(size_type size) : size_(size) + { + Expects(size != dynamic_extent); + } + + constexpr size_type size() const noexcept { return size_; } + + private: + size_type size_; + }; + + template + constexpr extent_type::extent_type(extent_type ext) + { + Expects(ext.size() == Ext); + } + + template + struct calculate_subspan_type + { + using type = span; + }; +} // namespace details + +// [span], class template span +template +class span +{ +public: + // constants and types + using element_type = ElementType; + using value_type = std::remove_cv_t; + using size_type = std::size_t; + using pointer = element_type*; + using const_pointer = const element_type*; + using reference = element_type&; + using const_reference = const element_type&; + using difference_type = std::ptrdiff_t; + + using iterator = details::span_iterator; + using reverse_iterator = std::reverse_iterator; + +#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) + static constexpr const size_type extent{Extent}; +#else + static constexpr size_type extent{Extent}; +#endif + + // [span.cons], span constructors, copy, assignment, and destructor + template " SFINAE, since "std::enable_if_t" is ill-formed when Extent is greater than 0. + class = std::enable_if_t<(Dependent || + details::is_allowed_extent_conversion<0, Extent>::value)>> + constexpr span() noexcept : storage_(nullptr, details::extent_type<0>()) + {} + + template = 0> + constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count) + { + Expects(count == Extent); + } + + template = 0> + constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count) + {} + + template = 0> + constexpr explicit span(pointer firstElem, pointer lastElem) noexcept + : storage_(firstElem, narrow_cast(lastElem - firstElem)) + { + Expects(lastElem - firstElem == static_cast(Extent)); + } + + template = 0> + constexpr span(pointer firstElem, pointer lastElem) noexcept + : storage_(firstElem, narrow_cast(lastElem - firstElem)) + {} + + template ::value, int> = 0> + constexpr span(element_type (&arr)[N]) noexcept + : storage_(KnownNotNull{arr}, details::extent_type()) + {} + + template < + class T, std::size_t N, + std::enable_if_t<(details::is_allowed_extent_conversion::value && + details::is_allowed_element_type_conversion::value), + int> = 0> + constexpr span(std::array& arr) noexcept + : storage_(KnownNotNull{arr.data()}, details::extent_type()) + {} + + template ::value && + details::is_allowed_element_type_conversion::value), + int> = 0> + constexpr span(const std::array& arr) noexcept + : storage_(KnownNotNull{arr.data()}, details::extent_type()) + {} + + // NB: the SFINAE on these constructors uses .data() as an incomplete/imperfect proxy for the + // requirement on Container to be a contiguous sequence container. + template ::value && + !details::is_std_array::value && + std::is_pointer().data())>::value && + std::is_convertible< + std::remove_pointer_t().data())> (*)[], + element_type (*)[]>::value, + int> = 0> + constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size()) + {} + + template ::value && + !details::is_std_array::value && + std::is_pointer().data())>::value && + std::is_convertible< + std::remove_pointer_t().data())> (*)[], + element_type (*)[]>::value, + int> = 0> + constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) + {} + + template < + std::size_t MyExtent = Extent, class Container, + std::enable_if_t< + MyExtent != dynamic_extent && std::is_const::value && + !details::is_span::value && !details::is_std_array::value && + std::is_pointer().data())>::value && + std::is_convertible< + std::remove_pointer_t().data())> (*)[], + element_type (*)[]>::value, + int> = 0> + constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size()) + {} + + template < + std::size_t MyExtent = Extent, class Container, + std::enable_if_t< + MyExtent == dynamic_extent && std::is_const::value && + !details::is_span::value && !details::is_std_array::value && + std::is_pointer().data())>::value && + std::is_convertible< + std::remove_pointer_t().data())> (*)[], + element_type (*)[]>::value, + int> = 0> + constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size()) + {} + + constexpr span(const span& other) noexcept = default; + + template ::value, + int> = 0> + constexpr span(const span& other) noexcept + : storage_(other.data(), details::extent_type(other.size())) + {} + + template ::value, + int> = 0> + constexpr explicit span(const span& other) noexcept + : storage_(other.data(), details::extent_type(other.size())) + {} + + ~span() noexcept = default; + constexpr span& operator=(const span& other) noexcept = default; + + // [span.sub], span subviews + template + constexpr span first() const noexcept + { + Expects(Count <= size()); + return span{data(), Count}; + } + + template + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + constexpr span last() const noexcept + { + Expects(Count <= size()); + return span{data() + (size() - Count), Count}; + } + + template + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + constexpr auto subspan() const noexcept -> + typename details::calculate_subspan_type::type + { + Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); + using type = + typename details::calculate_subspan_type::type; + return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; + } + + constexpr span first(size_type count) const noexcept + { + Expects(count <= size()); + return {data(), count}; + } + + constexpr span last(size_type count) const noexcept + { + Expects(count <= size()); + return make_subspan(size() - count, dynamic_extent, subspan_selector{}); + } + + constexpr span + subspan(size_type offset, size_type count = dynamic_extent) const noexcept + { + return make_subspan(offset, count, subspan_selector{}); + } + + // [span.obs], span observers + constexpr size_type size() const noexcept { return storage_.size(); } + + constexpr size_type size_bytes() const noexcept + { + Expects(size() < dynamic_extent / sizeof(element_type)); + return size() * sizeof(element_type); + } + + constexpr bool empty() const noexcept { return size() == 0; } + + // [span.elem], span element access + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + constexpr reference operator[](size_type idx) const noexcept + { + Expects(idx < size()); + return data()[idx]; + } + + constexpr reference front() const noexcept + { + Expects(size() > 0); + return data()[0]; + } + + constexpr reference back() const noexcept + { + Expects(size() > 0); + return data()[size() - 1]; + } + + constexpr pointer data() const noexcept { return storage_.data(); } + + // [span.iter], span iterator support + constexpr iterator begin() const noexcept + { + const auto data = storage_.data(); + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + return {data, data + size(), data}; + } + + constexpr iterator end() const noexcept + { + const auto data = storage_.data(); + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + const auto endData = data + storage_.size(); + return {data, endData, endData}; + } + + constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } + constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } + +#ifdef _MSC_VER + // Tell MSVC how to unwrap spans in range-based-for + constexpr pointer _Unchecked_begin() const noexcept { return data(); } + constexpr pointer _Unchecked_end() const noexcept + { + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + return data() + size(); + } +#endif // _MSC_VER + +private: + // Needed to remove unnecessary null check in subspans + struct KnownNotNull + { + pointer p; + }; + + // this implementation detail class lets us take advantage of the + // empty base class optimization to pay for only storage of a single + // pointer in the case of fixed-size spans + template + class storage_type : public ExtentType + { + public: + // KnownNotNull parameter is needed to remove unnecessary null check + // in subspans and constructors from arrays + template + constexpr storage_type(KnownNotNull data, OtherExtentType ext) + : ExtentType(ext), data_(data.p) + { + Expects(ExtentType::size() != dynamic_extent); + } + + template + constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) + { + Expects(ExtentType::size() != dynamic_extent); + Expects(data || ExtentType::size() == 0); + } + + constexpr pointer data() const noexcept { return data_; } + + private: + pointer data_; + }; + + storage_type> storage_; + + // The rest is needed to remove unnecessary null check + // in subspans and constructors from arrays + constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {} + + template + class subspan_selector + { + }; + + template + constexpr span + make_subspan(size_type offset, size_type count, subspan_selector) const noexcept + { + const span tmp(*this); + return tmp.subspan(offset, count); + } + + // clang-format off + GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + constexpr span + make_subspan(size_type offset, size_type count, subspan_selector) const noexcept + { + Expects(size() >= offset); + + if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } + + Expects(size() - offset >= count); + return {KnownNotNull{data() + offset}, count}; + } +}; + +#if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) + +// Deduction Guides +template +span(Type (&)[Extent]) -> span; + +template +span(std::array&) -> span; + +template +span(const std::array&) -> span; + +template ().data())>> +span(Container&) -> span; + +template ().data())>> +span(const Container&) -> span; + +#endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) ) + +#if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) +template +constexpr const typename span::size_type span::extent; +#endif + +namespace details +{ + // if we only supported compilers with good constexpr support then + // this pair of classes could collapse down to a constexpr function + + // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as + // constexpr + // and so will fail compilation of the template + template + struct calculate_byte_size : std::integral_constant + { + static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big."); + }; + + template + struct calculate_byte_size + : std::integral_constant + { + }; +} // namespace details + +// [span.objectrep], views of object representation +template +span::value> +as_bytes(span s) noexcept +{ + using type = span::value>; + + // clang-format off + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on + return type{reinterpret_cast(s.data()), s.size_bytes()}; +} + +template ::value, int> = 0> +span::value> +as_writable_bytes(span s) noexcept +{ + using type = span::value>; + + // clang-format off + GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on + return type{reinterpret_cast(s.data()), s.size_bytes()}; +} + +} // namespace gsl + +#if defined(_MSC_VER) && !defined(__clang__) + +#pragma warning(pop) +#endif // _MSC_VER + +#if defined(__GNUC__) && __GNUC__ > 6 +#pragma GCC diagnostic pop +#endif // __GNUC__ > 6 + +#endif // GSL_SPAN_H diff --git a/3rdparty/include/gsl/span_ext b/3rdparty/include/gsl/span_ext new file mode 100644 index 00000000000..fd4d1cebc0a --- /dev/null +++ b/3rdparty/include/gsl/span_ext @@ -0,0 +1,212 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_SPAN_EXT_H +#define GSL_SPAN_EXT_H + +/////////////////////////////////////////////////////////////////////////////// +// +// File: span_ext +// Purpose: continue offering features that have been cut from the official +// implementation of span. +// While modernizing gsl::span a number of features needed to be removed to +// be compliant with the design of std::span +// +/////////////////////////////////////////////////////////////////////////////// + +#include "assert" // GSL_KERNEL_MODE +#include "util" // for narrow_cast, narrow + +#include // for ptrdiff_t, size_t +#include + +#ifndef GSL_KERNEL_MODE +#include // for lexicographical_compare +#endif // GSL_KERNEL_MODE + +namespace gsl +{ + +// [span.views.constants], constants +constexpr const std::size_t dynamic_extent = narrow_cast(-1); + +template +class span; + +// std::equal and std::lexicographical_compare are not /kernel compatible +// so all comparison operators must be removed for kernel mode. +#ifndef GSL_KERNEL_MODE + +// [span.comparison], span comparison operators +template +constexpr bool operator==(span l, span r) +{ + return std::equal(l.begin(), l.end(), r.begin(), r.end()); +} + +template +constexpr bool operator!=(span l, span r) +{ + return !(l == r); +} + +template +constexpr bool operator<(span l, span r) +{ + return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); +} + +template +constexpr bool operator<=(span l, span r) +{ + return !(l > r); +} + +template +constexpr bool operator>(span l, span r) +{ + return r < l; +} + +template +constexpr bool operator>=(span l, span r) +{ + return !(l < r); +} + +#endif // GSL_KERNEL_MODE + +// +// make_span() - Utility functions for creating spans +// +template +constexpr span make_span(ElementType* ptr, typename span::size_type count) +{ + return span(ptr, count); +} + +template +constexpr span make_span(ElementType* firstElem, ElementType* lastElem) +{ + return span(firstElem, lastElem); +} + +template +constexpr span make_span(ElementType (&arr)[N]) noexcept +{ + return span(arr); +} + +template +constexpr span make_span(Container& cont) +{ + return span(cont); +} + +template +constexpr span make_span(const Container& cont) +{ + return span(cont); +} + +template +constexpr span make_span(Ptr& cont, std::size_t count) +{ + return span(cont, count); +} + +template +constexpr span make_span(Ptr& cont) +{ + return span(cont); +} + +// Specialization of gsl::at for span +template +constexpr ElementType& at(span s, index i) +{ + // No bounds checking here because it is done in span::operator[] called below + Ensures(i >= 0); + return s[narrow_cast(i)]; +} + +// [span.obs] Free observer functions +template +constexpr std::ptrdiff_t ssize(const span& s) noexcept +{ + return static_cast(s.size()); +} + +// [span.iter] Free functions for begin/end functions +template +constexpr typename span::iterator +begin(const span& s) noexcept +{ + return s.begin(); +} + +template +constexpr typename span::iterator +end(const span& s) noexcept +{ + return s.end(); +} + +template +constexpr typename span::reverse_iterator +rbegin(const span& s) noexcept +{ + return s.rbegin(); +} + +template +constexpr typename span::reverse_iterator +rend(const span& s) noexcept +{ + return s.rend(); +} + +template +constexpr typename span::iterator +cbegin(const span& s) noexcept +{ + return s.begin(); +} + +template +constexpr typename span::iterator +cend(const span& s) noexcept +{ + return s.end(); +} + +template +constexpr typename span::reverse_iterator +crbegin(const span& s) noexcept +{ + return s.rbegin(); +} + +template +constexpr typename span::reverse_iterator +crend(const span& s) noexcept +{ + return s.rend(); +} + +} // namespace gsl + +#endif // GSL_SPAN_EXT_H diff --git a/3rdparty/include/gsl/string_span b/3rdparty/include/gsl/string_span new file mode 100644 index 00000000000..7d6006c654f --- /dev/null +++ b/3rdparty/include/gsl/string_span @@ -0,0 +1,759 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_STRING_SPAN_H +#define GSL_STRING_SPAN_H + +#include "assert" // for Ensures, Expects +#include "span_ext" // for operator!=, operator==, dynamic_extent +#include "util" // for narrow_cast + +#include // for equal, lexicographical_compare +#include // for array +#include // for size_t, nullptr_t +#include // for PTRDIFF_MAX +#include +#include // for basic_string, allocator, char_traits +#include // for declval, is_convertible, enable_if_t, add_... + +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(push) + +// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. +#pragma warning(disable : 26446) // TODO: bug in parser - attributes and templates +#pragma warning(disable : 26481) // TODO: suppress does not work inside templates sometimes +#pragma warning(disable : 4996) // use of functions & classes marked [[deprecated]] +#endif // _MSC_VER + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +namespace gsl +{ +// +// czstring and wzstring +// +// These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays) +// that allow static analysis to help find bugs. +// +// There are no additional features/semantics that we can find a way to add inside the +// type system for these types that will not either incur significant runtime costs or +// (sometimes needlessly) break existing programs when introduced. +// + +template +using basic_zstring = CharT*; + +using czstring = basic_zstring; + +using cwzstring = basic_zstring; + +using cu16zstring = basic_zstring; + +using cu32zstring = basic_zstring; + +using zstring = basic_zstring; + +using wzstring = basic_zstring; + +using u16zstring = basic_zstring; + +using u32zstring = basic_zstring; + +namespace details +{ + template + [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see " + "isocpp/CppCoreGuidelines PR#1680")]] constexpr std::size_t + string_length(const CharT* str, std::size_t n) + { + if (str == nullptr || n == dynamic_extent) return 0; + + const span str_span{str, n}; + + std::size_t len = 0; + while (len < n && str_span[len]) len++; + + return len; + } +} // namespace details + +// +// ensure_sentinel() +// +// Provides a way to obtain an span from a contiguous sequence +// that ends with a (non-inclusive) sentinel value. +// +// Will fail-fast if sentinel cannot be found before max elements are examined. +// +template +[[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see " + "isocpp/CppCoreGuidelines PR#1680")]] constexpr span +ensure_sentinel(T* seq, std::size_t max = static_cast(-1)) +{ + Ensures(seq != nullptr); + + // clang-format off + GSL_SUPPRESS(f.23) // TODO: false positive // TODO: suppress does not work + // clang-format on + auto cur = seq; + Ensures(cur != nullptr); // workaround for removing the warning + + // clang-format off + GSL_SUPPRESS(bounds.1) // TODO: suppress does not work + // clang-format on + while (static_cast(cur - seq) < max && *cur != Sentinel) ++cur; + Ensures(*cur == Sentinel); + return {seq, static_cast(cur - seq)}; +} + +// +// ensure_z - creates a span for a zero terminated strings. The span will not contain the zero +// termination. Will fail fast if a null-terminator cannot be found before the limit of size_type. +// +template +[[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see " + "isocpp/CppCoreGuidelines PR#1680")]] constexpr span +ensure_z(CharT* const& sz, std::size_t max = static_cast(-1)) +{ + return ensure_sentinel(sz, max); +} + +template +constexpr span ensure_z(CharT (&sz)[N]) +{ + return ensure_z(&sz[0], N); +} + +template +[[deprecated( + "string_span was removed from the C++ Core Guidelines. For more information, see " + "isocpp/CppCoreGuidelines PR#1680")]] constexpr span::type, + dynamic_extent> +ensure_z(Cont& cont) +{ + return ensure_z(cont.data(), cont.size()); +} + +template +class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, " + "see isocpp/CppCoreGuidelines PR#1680")]] basic_string_span; + +namespace details +{ + template + struct [[deprecated( + "string_span was removed from the C++ Core Guidelines. For more information, " + "see isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span_oracle : std::false_type{}; + + template + struct [[deprecated( + "string_span was removed from the C++ Core Guidelines. For more information, see " + "isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span_oracle> + : std::true_type{}; + + template + struct [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span + : is_basic_string_span_oracle>{}; +} // namespace details + +// +// string_span and relatives +// +template +class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, " + "see isocpp/CppCoreGuidelines PR#1680")]] basic_string_span +{ +public: + using element_type = CharT; + using value_type = std::remove_cv_t; + using pointer = std::add_pointer_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t>; + using impl_type = span; + + using size_type = typename impl_type::size_type; + using iterator = typename impl_type::iterator; + using reverse_iterator = typename impl_type::reverse_iterator; + + // default (empty) + constexpr basic_string_span() noexcept = default; + + // copy + constexpr basic_string_span(const basic_string_span& other) noexcept = default; + + // assign + constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default; + + constexpr basic_string_span(pointer ptr, size_type length) : span_(ptr, length) {} + constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {} + + // From static arrays - if 0-terminated, remove 0 from the view + // All other containers allow 0s within the length, so we do not remove them + template + constexpr basic_string_span(element_type(&arr)[N]) : span_(remove_z(arr)) + {} + + template > + constexpr basic_string_span(std::array & arr) noexcept : span_(arr) + {} + + template > + constexpr basic_string_span(const std::array& arr) noexcept : span_(arr) + {} + + // Container signature should work for basic_string after C++17 version exists + template + // GSL_SUPPRESS(bounds.4) // TODO: parser bug + constexpr basic_string_span(std::basic_string & str) + : span_(&str[0], str.length()) + {} + + template + constexpr basic_string_span(const std::basic_string& str) + : span_(&str[0], str.length()) + {} + + // from containers. Containers must have a pointer type and data() function signatures + template ::value && + std::is_convertible::value && + std::is_convertible().data())>::value>> + constexpr basic_string_span(Container & cont) : span_(cont) + {} + + template ::value && + std::is_convertible::value && + std::is_convertible().data())>::value>> + constexpr basic_string_span(const Container& cont) : span_(cont) + {} + + // from string_span + template < + class OtherValueType, std::size_t OtherExtent, + class = std::enable_if_t::impl_type, impl_type>::value>> + constexpr basic_string_span(basic_string_span other) + : span_(other.data(), other.length()) + {} + + template + constexpr basic_string_span first() const + { + return {span_.template first()}; + } + + constexpr basic_string_span first(size_type count) const + { + return {span_.first(count)}; + } + + template + constexpr basic_string_span last() const + { + return {span_.template last()}; + } + + constexpr basic_string_span last(size_type count) const + { + return {span_.last(count)}; + } + + template + constexpr basic_string_span subspan() const + { + return {span_.template subspan()}; + } + + constexpr basic_string_span subspan( + size_type offset, size_type count = dynamic_extent) const + { + return {span_.subspan(offset, count)}; + } + + constexpr reference operator[](size_type idx) const { return span_[idx]; } + constexpr reference operator()(size_type idx) const { return span_[idx]; } + + constexpr pointer data() const { return span_.data(); } + + constexpr size_type length() const noexcept { return span_.size(); } + constexpr size_type size() const noexcept { return span_.size(); } + constexpr size_type size_bytes() const noexcept { return span_.size_bytes(); } + constexpr size_type length_bytes() const noexcept { return span_.length_bytes(); } + constexpr bool empty() const noexcept { return size() == 0; } + + constexpr iterator begin() const noexcept { return span_.begin(); } + constexpr iterator end() const noexcept { return span_.end(); } + + constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); } + constexpr reverse_iterator rend() const noexcept { return span_.rend(); } + +private: + static constexpr impl_type remove_z(pointer const& sz, std::size_t max) + { + return impl_type(sz, details::string_length(sz, max)); + } + + template + static constexpr impl_type remove_z(element_type(&sz)[N]) + { + return remove_z(&sz[0], N); + } + + impl_type span_; +}; + +template +using string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_string_span; + +template +using cstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_string_span; + +template +using wstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_string_span; + +template +using cwstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_string_span; + +template +using u16string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_string_span; + +template +using cu16string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_string_span; + +template +using u32string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_string_span; + +template +using cu32string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_string_span; + +// +// to_string() allow (explicit) conversions from string_span to string +// + +template +constexpr std::basic_string::type> +to_string(basic_string_span view) +{ + return {view.data(), narrow_cast(view.length())}; +} + +template , + typename Allocator = std::allocator, typename gCharT, std::size_t Extent> +constexpr std::basic_string +to_basic_string(basic_string_span view) +{ + return {view.data(), narrow_cast(view.length())}; +} + +template +constexpr basic_string_span::value> +as_bytes(basic_string_span s) noexcept +{ + // clang-format off + GSL_SUPPRESS(type.1) + // clang-format on + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +template ::value>> +constexpr basic_string_span::value> +as_writable_bytes(basic_string_span s) noexcept +{ + // clang-format off + GSL_SUPPRESS(type.1) + // clang-format on + return {reinterpret_cast(s.data()), s.size_bytes()}; +} + +// zero-terminated string span, used to convert +// zero-terminated spans to legacy strings +template +class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, " + "see isocpp/CppCoreGuidelines PR#1680")]] basic_zstring_span +{ +public: + using value_type = CharT; + using const_value_type = std::add_const_t; + + using pointer = std::add_pointer_t; + using const_pointer = std::add_pointer_t; + + using zstring_type = basic_zstring; + using const_zstring_type = basic_zstring; + + using impl_type = span; + using string_span_type = basic_string_span; + + constexpr basic_zstring_span(impl_type s) : span_(s) + { + // expects a zero-terminated span + Expects(s.size() > 0); + Expects(s[s.size() - 1] == value_type{}); + } + + // copy + constexpr basic_zstring_span(const basic_zstring_span& other) = default; + + // move + constexpr basic_zstring_span(basic_zstring_span && other) = default; + + // assign + constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default; + + // move assign + constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default; + + constexpr bool empty() const noexcept { return false; } + + constexpr string_span_type as_string_span() const noexcept + { + return {span_.data(), span_.size() - 1}; + } + constexpr string_span_type ensure_z() const { return gsl::ensure_z(span_); } + + constexpr const_zstring_type assume_z() const noexcept { return span_.data(); } + +private: + impl_type span_; +}; + +template +using zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_zstring_span; + +template +using wzstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_zstring_span; + +template +using u16zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_zstring_span; + +template +using u32zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_zstring_span; + +template +using czstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_zstring_span; + +template +using cwzstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " + "information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_zstring_span; + +template +using cu16zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For " + "more information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_zstring_span; + +template +using cu32zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For " + "more information, see isocpp/CppCoreGuidelines PR#1680")]] = + basic_zstring_span; + +// operator == +template ::value || + std::is_convertible>>::value>> +bool operator==(const gsl::basic_string_span& one, const T& other) +{ + const gsl::basic_string_span> tmp(other); + return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); +} + +template ::value && + std::is_convertible>>::value>> +bool operator==(const T& one, const gsl::basic_string_span& other) +{ + const gsl::basic_string_span> tmp(one); + return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end()); +} + +// operator != +template , Extent>>::value>> +bool operator!=(gsl::basic_string_span one, const T& other) +{ + return !(one == other); +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename = std::enable_if_t< + std::is_convertible, Extent>>::value && + !gsl::details::is_basic_string_span::value>> +bool operator!=(const T& one, gsl::basic_string_span other) +{ + return !(one == other); +} + +// operator< +template , Extent>>::value>> +bool operator<(gsl::basic_string_span one, const T& other) +{ + const gsl::basic_string_span, Extent> tmp(other); + return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename = std::enable_if_t< + std::is_convertible, Extent>>::value && + !gsl::details::is_basic_string_span::value>> +bool operator<(const T& one, gsl::basic_string_span other) +{ + gsl::basic_string_span, Extent> tmp(one); + return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); +} + +#ifndef _MSC_VER + +// VS treats temp and const containers as convertible to basic_string_span, +// so the cases below are already covered by the previous operators + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename DataType = typename T::value_type, + typename = std::enable_if_t< + !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && + std::is_convertible::value && + std::is_same().size(), *std::declval().data())>, + DataType>::value>> +bool operator<(gsl::basic_string_span one, const T& other) +{ + gsl::basic_string_span, Extent> tmp(other); + return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename DataType = typename T::value_type, + typename = std::enable_if_t< + !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && + std::is_convertible::value && + std::is_same().size(), *std::declval().data())>, + DataType>::value>> +bool operator<(const T& one, gsl::basic_string_span other) +{ + gsl::basic_string_span, Extent> tmp(one); + return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); +} +#endif + +// operator <= +template , Extent>>::value>> +bool operator<=(gsl::basic_string_span one, const T& other) +{ + return !(other < one); +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename = std::enable_if_t< + std::is_convertible, Extent>>::value && + !gsl::details::is_basic_string_span::value>> +bool operator<=(const T& one, gsl::basic_string_span other) +{ + return !(other < one); +} + +#ifndef _MSC_VER + +// VS treats temp and const containers as convertible to basic_string_span, +// so the cases below are already covered by the previous operators + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename DataType = typename T::value_type, + typename = std::enable_if_t< + !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && + std::is_convertible::value && + std::is_same().size(), *std::declval().data())>, + DataType>::value>> +bool operator<=(gsl::basic_string_span one, const T& other) +{ + return !(other < one); +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename DataType = typename T::value_type, + typename = std::enable_if_t< + !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && + std::is_convertible::value && + std::is_same().size(), *std::declval().data())>, + DataType>::value>> +bool operator<=(const T& one, gsl::basic_string_span other) +{ + return !(other < one); +} +#endif + +// operator> +template , Extent>>::value>> +bool operator>(gsl::basic_string_span one, const T& other) +{ + return other < one; +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename = std::enable_if_t< + std::is_convertible, Extent>>::value && + !gsl::details::is_basic_string_span::value>> +bool operator>(const T& one, gsl::basic_string_span other) +{ + return other < one; +} + +#ifndef _MSC_VER + +// VS treats temp and const containers as convertible to basic_string_span, +// so the cases below are already covered by the previous operators + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename DataType = typename T::value_type, + typename = std::enable_if_t< + !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && + std::is_convertible::value && + std::is_same().size(), *std::declval().data())>, + DataType>::value>> +bool operator>(gsl::basic_string_span one, const T& other) +{ + return other < one; +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename DataType = typename T::value_type, + typename = std::enable_if_t< + !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && + std::is_convertible::value && + std::is_same().size(), *std::declval().data())>, + DataType>::value>> +bool operator>(const T& one, gsl::basic_string_span other) +{ + return other < one; +} +#endif + +// operator >= +template , Extent>>::value>> +bool operator>=(gsl::basic_string_span one, const T& other) +{ + return !(one < other); +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename = std::enable_if_t< + std::is_convertible, Extent>>::value && + !gsl::details::is_basic_string_span::value>> +bool operator>=(const T& one, gsl::basic_string_span other) +{ + return !(one < other); +} + +#ifndef _MSC_VER + +// VS treats temp and const containers as convertible to basic_string_span, +// so the cases below are already covered by the previous operators + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename DataType = typename T::value_type, + typename = std::enable_if_t< + !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && + std::is_convertible::value && + std::is_same().size(), *std::declval().data())>, + DataType>::value>> +bool operator>=(gsl::basic_string_span one, const T& other) +{ + return !(one < other); +} + +template < + typename CharT, std::size_t Extent = dynamic_extent, typename T, + typename DataType = typename T::value_type, + typename = std::enable_if_t< + !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && + std::is_convertible::value && + std::is_same().size(), *std::declval().data())>, + DataType>::value>> +bool operator>=(const T& one, gsl::basic_string_span other) +{ + return !(one < other); +} +#endif +} // namespace gsl + +#if defined(_MSC_VER) && !defined(__clang__) +#pragma warning(pop) + +#endif // _MSC_VER + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif +#endif // GSL_STRING_SPAN_H diff --git a/3rdparty/include/gsl/util b/3rdparty/include/gsl/util new file mode 100644 index 00000000000..b6dbd1837ff --- /dev/null +++ b/3rdparty/include/gsl/util @@ -0,0 +1,160 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2015 Microsoft Corporation. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef GSL_UTIL_H +#define GSL_UTIL_H + +#include "assert" // for Expects + +#include +#include // for ptrdiff_t, size_t +#include // for initializer_list +#include // for is_signed, integral_constant +#include // for exchange, forward + +#if defined(__has_include) && __has_include() +#include +#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L +#include +#endif // __cpp_lib_span >= 202002L +#endif //__has_include() + +#if defined(_MSC_VER) && !defined(__clang__) + +#pragma warning(push) +#pragma warning(disable : 4127) // conditional expression is constant + +#endif // _MSC_VER + +#if defined(__cplusplus) && (__cplusplus >= 201703L) +#define GSL_NODISCARD [[nodiscard]] +#else +#define GSL_NODISCARD +#endif // defined(__cplusplus) && (__cplusplus >= 201703L) + +namespace gsl +{ +// +// GSL.util: utilities +// + +// index type for all container indexes/subscripts/sizes +using index = std::ptrdiff_t; + +// final_action allows you to ensure something gets run at the end of a scope +template +class final_action +{ +public: + static_assert(!std::is_reference::value && !std::is_const::value && + !std::is_volatile::value, + "Final_action should store its callable by value"); + + explicit final_action(F f) noexcept : f_(std::move(f)) {} + + final_action(final_action&& other) noexcept + : f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false)) + {} + + final_action(const final_action&) = delete; + final_action& operator=(const final_action&) = delete; + final_action& operator=(final_action&&) = delete; + + // clang-format off + GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws + // clang-format on + ~final_action() noexcept + { + if (invoke_) f_(); + } + +private: + F f_; + bool invoke_{true}; +}; + +// finally() - convenience function to generate a final_action +template +GSL_NODISCARD final_action::type>::type> +finally(F&& f) noexcept +{ + return final_action::type>::type>( + std::forward(f)); +} + +// narrow_cast(): a searchable way to do narrowing casts of values +template +// clang-format off +GSL_SUPPRESS(type.1) // NO-FORMAT: attribute + // clang-format on + constexpr T narrow_cast(U&& u) noexcept +{ + return static_cast(std::forward(u)); +} + +// +// at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector +// +template +// clang-format off +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute + // clang-format on + constexpr T& at(T (&arr)[N], const index i) +{ + Expects(i >= 0 && i < narrow_cast(N)); + return arr[narrow_cast(i)]; +} + +template +// clang-format off +GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute +GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute + // clang-format on + constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) +{ + Expects(i >= 0 && i < narrow_cast(cont.size())); + using size_type = decltype(cont.size()); + return cont[narrow_cast(i)]; +} + +template +// clang-format off +GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute + // clang-format on + constexpr T at(const std::initializer_list cont, const index i) +{ + Expects(i >= 0 && i < narrow_cast(cont.size())); + return *(cont.begin() + i); +} + +#if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L +template +constexpr auto at(std::span sp, const index i) -> decltype(sp[sp.size()]) +{ + Expects(i >= 0 && i < narrow_cast(sp.size())); + return sp[gsl::narrow_cast(i)]; +} +#endif // __cpp_lib_span >= 202002L +} // namespace gsl + +#if defined(_MSC_VER) && !defined(__clang__) + +#pragma warning(pop) + +#endif // _MSC_VER + +#endif // GSL_UTIL_H diff --git a/3rdparty/include/uuid.h b/3rdparty/include/uuid.h new file mode 100644 index 00000000000..d48059d7722 --- /dev/null +++ b/3rdparty/include/uuid.h @@ -0,0 +1,967 @@ +#ifndef STDUUID_H +#define STDUUID_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus + +# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +# define LIBUUID_CPP20_OR_GREATER +# endif + +#endif + + +#ifdef LIBUUID_CPP20_OR_GREATER +#include +#else +#include +#endif + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#ifdef UUID_TIME_GENERATOR +#include +#pragma comment(lib, "IPHLPAPI.lib") +#endif + +#elif defined(__linux__) || defined(__unix__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#elif defined(__APPLE__) + +#ifdef UUID_SYSTEM_GENERATOR +#include +#endif + +#endif + +namespace uuids +{ +#ifdef __cpp_lib_span + template + using span = std::span; +#else + template + using span = gsl::span; +#endif + + namespace detail + { + template + [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept + { + if (ch >= static_cast('0') && ch <= static_cast('9')) + return static_cast(ch - static_cast('0')); + if (ch >= static_cast('a') && ch <= static_cast('f')) + return static_cast(10 + ch - static_cast('a')); + if (ch >= static_cast('A') && ch <= static_cast('F')) + return static_cast(10 + ch - static_cast('A')); + return 0; + } + + template + [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept + { + return + (ch >= static_cast('0') && ch <= static_cast('9')) || + (ch >= static_cast('a') && ch <= static_cast('f')) || + (ch >= static_cast('A') && ch <= static_cast('F')); + } + + template + [[nodiscard]] constexpr std::basic_string_view to_string_view(TChar const * str) noexcept + { + if (str) return str; + return {}; + } + + template + [[nodiscard]] + constexpr std::basic_string_view< + typename StringType::value_type, + typename StringType::traits_type> + to_string_view(StringType const & str) noexcept + { + return str; + } + + class sha1 + { + public: + using digest32_t = uint32_t[5]; + using digest8_t = uint8_t[20]; + + static constexpr unsigned int block_bytes = 64; + + [[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept + { + return (value << count) ^ (value >> (32 - count)); + } + + sha1() { reset(); } + + void reset() noexcept + { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + } + + void process_byte(uint8_t octet) + { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == block_bytes) + { + this->m_blockByteIndex = 0; + process_block(); + } + } + + void process_block(void const * const start, void const * const end) + { + const uint8_t* begin = static_cast(start); + const uint8_t* finish = static_cast(end); + while (begin != finish) + { + process_byte(*begin); + begin++; + } + } + + void process_bytes(void const * const data, size_t const len) + { + const uint8_t* block = static_cast(data); + process_block(block, block + len); + } + + uint32_t const * get_digest(digest32_t digest) + { + size_t const bitCount = this->m_byteCount * 8; + process_byte(0x80); + if (this->m_blockByteIndex > 56) { + while (m_blockByteIndex != 0) { + process_byte(0); + } + while (m_blockByteIndex < 56) { + process_byte(0); + } + } + else { + while (m_blockByteIndex < 56) { + process_byte(0); + } + } + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(static_cast((bitCount >> 24) & 0xFF)); + process_byte(static_cast((bitCount >> 16) & 0xFF)); + process_byte(static_cast((bitCount >> 8) & 0xFF)); + process_byte(static_cast((bitCount) & 0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + uint8_t const * get_digest_bytes(digest8_t digest) + { + digest32_t d32; + get_digest(d32); + size_t di = 0; + digest[di++] = static_cast(d32[0] >> 24); + digest[di++] = static_cast(d32[0] >> 16); + digest[di++] = static_cast(d32[0] >> 8); + digest[di++] = static_cast(d32[0] >> 0); + + digest[di++] = static_cast(d32[1] >> 24); + digest[di++] = static_cast(d32[1] >> 16); + digest[di++] = static_cast(d32[1] >> 8); + digest[di++] = static_cast(d32[1] >> 0); + + digest[di++] = static_cast(d32[2] >> 24); + digest[di++] = static_cast(d32[2] >> 16); + digest[di++] = static_cast(d32[2] >> 8); + digest[di++] = static_cast(d32[2] >> 0); + + digest[di++] = static_cast(d32[3] >> 24); + digest[di++] = static_cast(d32[3] >> 16); + digest[di++] = static_cast(d32[3] >> 8); + digest[di++] = static_cast(d32[3] >> 0); + + digest[di++] = static_cast(d32[4] >> 24); + digest[di++] = static_cast(d32[4] >> 16); + digest[di++] = static_cast(d32[4] >> 8); + digest[di++] = static_cast(d32[4] >> 0); + + return digest; + } + + private: + void process_block() + { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) { + w[i] = static_cast(m_block[i * 4 + 0] << 24); + w[i] |= static_cast(m_block[i * 4 + 1] << 16); + w[i] |= static_cast(m_block[i * 4 + 2] << 8); + w[i] |= static_cast(m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) { + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) + { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) { + f = (b & c) | (~b & d); + k = 0x5A827999; + } + else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } + else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } + else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = left_rotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; + + template + inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; + + template <> + inline constexpr wchar_t empty_guid[37] = L"00000000-0000-0000-0000-000000000000"; + + template + inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; + + template <> + inline constexpr wchar_t guid_encoder[17] = L"0123456789abcdef"; + } + + // -------------------------------------------------------------------------------------------------------------------------- + // UUID format https://tools.ietf.org/html/rfc4122 + // -------------------------------------------------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------------------------------------------------- + // Field NDR Data Type Octet # Note + // -------------------------------------------------------------------------------------------------------------------------- + // time_low unsigned long 0 - 3 The low field of the timestamp. + // time_mid unsigned short 4 - 5 The middle field of the timestamp. + // time_hi_and_version unsigned short 6 - 7 The high field of the timestamp multiplexed with the version number. + // clock_seq_hi_and_reserved unsigned small 8 The high field of the clock sequence multiplexed with the variant. + // clock_seq_low unsigned small 9 The low field of the clock sequence. + // node character 10 - 15 The spatially unique node identifier. + // -------------------------------------------------------------------------------------------------------------------------- + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_low | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_mid | time_hi_and_version | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |clk_seq_hi_res | clk_seq_low | node (0-1) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | node (2-5) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // -------------------------------------------------------------------------------------------------------------------------- + // enumerations + // -------------------------------------------------------------------------------------------------------------------------- + + // indicated by a bit pattern in octet 8, marked with N in xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx + enum class uuid_variant + { + // NCS backward compatibility (with the obsolete Apollo Network Computing System 1.5 UUID format) + // N bit pattern: 0xxx + // > the first 6 octets of the UUID are a 48-bit timestamp (the number of 4 microsecond units of time since 1 Jan 1980 UTC); + // > the next 2 octets are reserved; + // > the next octet is the "address family"; + // > the final 7 octets are a 56-bit host ID in the form specified by the address family + ncs, + + // RFC 4122/DCE 1.1 + // N bit pattern: 10xx + // > big-endian byte order + rfc, + + // Microsoft Corporation backward compatibility + // N bit pattern: 110x + // > little endian byte order + // > formely used in the Component Object Model (COM) library + microsoft, + + // reserved for possible future definition + // N bit pattern: 111x + reserved + }; + + // indicated by a bit pattern in octet 6, marked with M in xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx + enum class uuid_version + { + none = 0, // only possible for nil or invalid uuids + time_based = 1, // The time-based version specified in RFC 4122 + dce_security = 2, // DCE Security version, with embedded POSIX UIDs. + name_based_md5 = 3, // The name-based version specified in RFS 4122 with MD5 hashing + random_number_based = 4, // The randomly or pseudo-randomly generated version specified in RFS 4122 + name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing + }; + + // Forward declare uuid & to_string so that we can declare to_string as a friend later. + class uuid; + template , + class Allocator = std::allocator> + std::basic_string to_string(uuid const &id); + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid class + // -------------------------------------------------------------------------------------------------------------------------- + class uuid + { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + + uuid(value_type(&arr)[16]) noexcept + { + std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); + } + + constexpr uuid(std::array const & arr) noexcept : data{arr} {} + + explicit uuid(span bytes) + { + std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); + } + + template + explicit uuid(ForwardIterator first, ForwardIterator last) + { + if (std::distance(first, last) == 16) + std::copy(first, last, std::begin(data)); + } + + [[nodiscard]] constexpr uuid_variant variant() const noexcept + { + if ((data[8] & 0x80) == 0x00) + return uuid_variant::ncs; + else if ((data[8] & 0xC0) == 0x80) + return uuid_variant::rfc; + else if ((data[8] & 0xE0) == 0xC0) + return uuid_variant::microsoft; + else + return uuid_variant::reserved; + } + + [[nodiscard]] constexpr uuid_version version() const noexcept + { + if ((data[6] & 0xF0) == 0x10) + return uuid_version::time_based; + else if ((data[6] & 0xF0) == 0x20) + return uuid_version::dce_security; + else if ((data[6] & 0xF0) == 0x30) + return uuid_version::name_based_md5; + else if ((data[6] & 0xF0) == 0x40) + return uuid_version::random_number_based; + else if ((data[6] & 0xF0) == 0x50) + return uuid_version::name_based_sha1; + else + return uuid_version::none; + } + + [[nodiscard]] constexpr bool is_nil() const noexcept + { + for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false; + return true; + } + + void swap(uuid & other) noexcept + { + data.swap(other.data); + } + + [[nodiscard]] inline span as_bytes() const + { + return span(reinterpret_cast(data.data()), 16); + } + + template + [[nodiscard]] constexpr static bool is_valid_uuid(StringType const & in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + if (str.empty()) + return false; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return false; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return false; + } + + if (firstDigit) + { + firstDigit = false; + } + else + { + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return false; + } + + return true; + } + + template + [[nodiscard]] constexpr static std::optional from_string(StringType const & in_str) noexcept + { + auto str = detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + std::array data{ { 0 } }; + + if (str.empty()) return {}; + + if (str.front() == '{') + hasBraces = 1; + if (hasBraces && str.back() != '}') + return {}; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) + { + if (str[i] == '-') continue; + + if (index >= 16 || !detail::is_hex(str[i])) + { + return {}; + } + + if (firstDigit) + { + data[index] = static_cast(detail::hex2char(str[i]) << 4); + firstDigit = false; + } + else + { + data[index] = static_cast(data[index] | detail::hex2char(str[i])); + index++; + firstDigit = true; + } + } + + if (index < 16) + { + return {}; + } + + return uuid{ data }; + } + + private: + std::array data{ { 0 } }; + + friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept; + friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept; + + template + friend std::basic_ostream & operator<<(std::basic_ostream &s, uuid const & id); + + template + friend std::basic_string to_string(uuid const& id); + + friend std::hash; + }; + + // -------------------------------------------------------------------------------------------------------------------------- + // operators and non-member functions + // -------------------------------------------------------------------------------------------------------------------------- + + [[nodiscard]] inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept + { + return lhs.data == rhs.data; + } + + [[nodiscard]] inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept + { + return !(lhs == rhs); + } + + [[nodiscard]] inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept + { + return lhs.data < rhs.data; + } + + template + [[nodiscard]] inline std::basic_string to_string(uuid const & id) + { + std::basic_string uustr{detail::empty_guid}; + + for (size_t i = 0, index = 0; i < 36; ++i) + { + if (i == 8 || i == 13 || i == 18 || i == 23) + { + continue; + } + uustr[i] = detail::guid_encoder[id.data[index] >> 4 & 0x0f]; + uustr[++i] = detail::guid_encoder[id.data[index] & 0x0f]; + index++; + } + + return uustr; + } + + template + std::basic_ostream& operator<<(std::basic_ostream& s, uuid const& id) + { + s << to_string(id); + return s; + } + + inline void swap(uuids::uuid & lhs, uuids::uuid & rhs) noexcept + { + lhs.swap(rhs); + } + + // -------------------------------------------------------------------------------------------------------------------------- + // namespace IDs that could be used for generating name-based uuids + // -------------------------------------------------------------------------------------------------------------------------- + + // Name string is a fully-qualified domain name + static uuid uuid_namespace_dns{ {0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} }; + + // Name string is a URL + static uuid uuid_namespace_url{ {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} }; + + // Name string is an ISO OID (See https://oidref.com/, https://en.wikipedia.org/wiki/Object_identifier) + static uuid uuid_namespace_oid{ {0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} }; + + // Name string is an X.500 DN, in DER or a text output format (See https://en.wikipedia.org/wiki/X.500, https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) + static uuid uuid_namespace_x500{ {0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} }; + + // -------------------------------------------------------------------------------------------------------------------------- + // uuid generators + // -------------------------------------------------------------------------------------------------------------------------- + +#ifdef UUID_SYSTEM_GENERATOR + class uuid_system_generator + { + public: + using result_type = uuid; + + uuid operator()() + { +#ifdef _WIN32 + + GUID newId; + HRESULT hr = ::CoCreateGuid(&newId); + + if (FAILED(hr)) + { + throw std::system_error(hr, std::system_category(), "CoCreateGuid failed"); + } + + std::array bytes = + { { + static_cast((newId.Data1 >> 24) & 0xFF), + static_cast((newId.Data1 >> 16) & 0xFF), + static_cast((newId.Data1 >> 8) & 0xFF), + static_cast((newId.Data1) & 0xFF), + + (unsigned char)((newId.Data2 >> 8) & 0xFF), + (unsigned char)((newId.Data2) & 0xFF), + + (unsigned char)((newId.Data3 >> 8) & 0xFF), + (unsigned char)((newId.Data3) & 0xFF), + + newId.Data4[0], + newId.Data4[1], + newId.Data4[2], + newId.Data4[3], + newId.Data4[4], + newId.Data4[5], + newId.Data4[6], + newId.Data4[7] + } }; + + return uuid{ std::begin(bytes), std::end(bytes) }; + +#elif defined(__linux__) || defined(__unix__) + + uuid_t id; + uuid_generate(id); + + std::array bytes = + { { + id[0], + id[1], + id[2], + id[3], + id[4], + id[5], + id[6], + id[7], + id[8], + id[9], + id[10], + id[11], + id[12], + id[13], + id[14], + id[15] + } }; + + return uuid{ std::begin(bytes), std::end(bytes) }; + +#elif defined(__APPLE__) + auto newId = CFUUIDCreate(NULL); + auto bytes = CFUUIDGetUUIDBytes(newId); + CFRelease(newId); + + std::array arrbytes = + { { + bytes.byte0, + bytes.byte1, + bytes.byte2, + bytes.byte3, + bytes.byte4, + bytes.byte5, + bytes.byte6, + bytes.byte7, + bytes.byte8, + bytes.byte9, + bytes.byte10, + bytes.byte11, + bytes.byte12, + bytes.byte13, + bytes.byte14, + bytes.byte15 + } }; + return uuid{ std::begin(arrbytes), std::end(arrbytes) }; +#else + return uuid{}; +#endif + } + }; +#endif + + template + class basic_uuid_random_generator + { + public: + using engine_type = UniformRandomNumberGenerator; + + explicit basic_uuid_random_generator(engine_type& gen) : + generator(&gen, [](auto) {}) {} + explicit basic_uuid_random_generator(engine_type* gen) : + generator(gen, [](auto) {}) {} + + [[nodiscard]] uuid operator()() + { + alignas(uint32_t) uint8_t bytes[16]; + for (int i = 0; i < 16; i += 4) + *reinterpret_cast(bytes + i) = distribution(*generator); + + // variant must be 10xxxxxx + bytes[8] &= 0xBF; + bytes[8] |= 0x80; + + // version must be 0100xxxx + bytes[6] &= 0x4F; + bytes[6] |= 0x40; + + return uuid{std::begin(bytes), std::end(bytes)}; + } + + private: + std::uniform_int_distribution distribution; + std::shared_ptr generator; + }; + + using uuid_random_generator = basic_uuid_random_generator; + + class uuid_name_generator + { + public: + explicit uuid_name_generator(uuid const& namespace_uuid) noexcept + : nsuuid(namespace_uuid) + {} + + template + [[nodiscard]] uuid operator()(StringType const & name) + { + reset(); + process_characters(detail::to_string_view(name)); + return make_uuid(); + } + + private: + void reset() + { + hasher.reset(); + std::byte bytes[16]; + auto nsbytes = nsuuid.as_bytes(); + std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); + hasher.process_bytes(bytes, 16); + } + + template + void process_characters(std::basic_string_view const str) + { + for (uint32_t c : str) + { + hasher.process_byte(static_cast(c & 0xFF)); + if constexpr (!std::is_same_v) + { + hasher.process_byte(static_cast((c >> 8) & 0xFF)); + hasher.process_byte(static_cast((c >> 16) & 0xFF)); + hasher.process_byte(static_cast((c >> 24) & 0xFF)); + } + } + } + + [[nodiscard]] uuid make_uuid() + { + detail::sha1::digest8_t digest; + hasher.get_digest_bytes(digest); + + // variant must be 0b10xxxxxx + digest[8] &= 0xBF; + digest[8] |= 0x80; + + // version must be 0b0101xxxx + digest[6] &= 0x5F; + digest[6] |= 0x50; + + return uuid{ digest, digest + 16 }; + } + + private: + uuid nsuuid; + detail::sha1 hasher; + }; + +#ifdef UUID_TIME_GENERATOR + // !!! DO NOT USE THIS IN PRODUCTION + // this implementation is unreliable for good uuids + class uuid_time_generator + { + using mac_address = std::array; + + std::optional device_address; + + [[nodiscard]] bool get_mac_address() + { + if (device_address.has_value()) + { + return true; + } + +#ifdef _WIN32 + DWORD len = 0; + auto ret = GetAdaptersInfo(nullptr, &len); + if (ret != ERROR_BUFFER_OVERFLOW) return false; + std::vector buf(len); + auto pips = reinterpret_cast(&buf.front()); + ret = GetAdaptersInfo(pips, &len); + if (ret != ERROR_SUCCESS) return false; + mac_address addr; + std::copy(pips->Address, pips->Address + 6, std::begin(addr)); + device_address = addr; +#endif + + return device_address.has_value(); + } + + [[nodiscard]] long long get_time_intervals() + { + auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); + auto diff = std::chrono::system_clock::now() - start; + auto ns = std::chrono::duration_cast(diff).count(); + return ns / 100; + } + + [[nodiscard]] static unsigned short get_clock_sequence() + { + static std::mt19937 clock_gen(std::random_device{}()); + static std::uniform_int_distribution clock_dis; + static std::atomic_ushort clock_sequence = clock_dis(clock_gen); + return clock_sequence++; + } + + public: + [[nodiscard]] uuid operator()() + { + if (get_mac_address()) + { + std::array data; + + auto tm = get_time_intervals(); + + auto clock_seq = get_clock_sequence(); + + auto ptm = reinterpret_cast(&tm); + + memcpy(&data[0], ptm + 4, 4); + memcpy(&data[4], ptm + 2, 2); + memcpy(&data[6], ptm, 2); + + memcpy(&data[8], &clock_seq, 2); + + // variant must be 0b10xxxxxx + data[8] &= 0xBF; + data[8] |= 0x80; + + // version must be 0b0001xxxx + data[6] &= 0x1F; + data[6] |= 0x10; + + memcpy(&data[10], &device_address.value()[0], 6); + + return uuids::uuid{std::cbegin(data), std::cend(data)}; + } + + return {}; + } + }; +#endif +} + +namespace std +{ + template <> + struct hash + { + using argument_type = uuids::uuid; + using result_type = std::size_t; + + [[nodiscard]] result_type operator()(argument_type const &uuid) const + { +#ifdef UUID_HASH_STRING_BASED + std::hash hasher; + return static_cast(hasher(uuids::to_string(uuid))); +#else + uint64_t l = + static_cast(uuid.data[0]) << 56 | + static_cast(uuid.data[1]) << 48 | + static_cast(uuid.data[2]) << 40 | + static_cast(uuid.data[3]) << 32 | + static_cast(uuid.data[4]) << 24 | + static_cast(uuid.data[5]) << 16 | + static_cast(uuid.data[6]) << 8 | + static_cast(uuid.data[7]); + uint64_t h = + static_cast(uuid.data[8]) << 56 | + static_cast(uuid.data[9]) << 48 | + static_cast(uuid.data[10]) << 40 | + static_cast(uuid.data[11]) << 32 | + static_cast(uuid.data[12]) << 24 | + static_cast(uuid.data[13]) << 16 | + static_cast(uuid.data[14]) << 8 | + static_cast(uuid.data[15]); + + if constexpr (sizeof(result_type) > 4) + { + return result_type(l ^ h); + } + else + { + uint64_t hash64 = l ^ h; + return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); + } +#endif + } + }; +} + +#endif /* STDUUID_H */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 858849abd2f..9f6464fb22e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,9 @@ SET(LMMS_SOURCE_DIR ${CMAKE_SOURCE_DIR}) # Import of windows.h breaks min()/max() ADD_DEFINITIONS(-DNOMINMAX) +# visible to all parts of the codebase +INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/3rdparty/include") + # CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES is not set correctly for MinGW until # CMake 3.14.1, so avoid specifying system include directories on affected # versions. Normal include directories are safe, since GCC ignores them if they diff --git a/include/JournallingObject.h b/include/JournallingObject.h index f3e134f3466..c353614d49d 100644 --- a/include/JournallingObject.h +++ b/include/JournallingObject.h @@ -26,6 +26,7 @@ #define LMMS_JOURNALLING_OBJECT_H #include +#include #include "lmms_basics.h" #include "SerializingObject.h" diff --git a/include/ProjectJournal.h b/include/ProjectJournal.h index 841bbf09435..8d8d1886d80 100644 --- a/include/ProjectJournal.h +++ b/include/ProjectJournal.h @@ -25,8 +25,9 @@ #ifndef LMMS_PROJECT_JOURNAL_H #define LMMS_PROJECT_JOURNAL_H -#include +#include #include +#include #include "lmms_basics.h" #include "DataFile.h" @@ -54,61 +55,58 @@ class ProjectJournal bool canUndo() const; bool canRedo() const; - void addJournalCheckPoint( JournallingObject *jo ); + void addJournalCheckPoint(JournallingObject* jo); bool isJournalling() const { return m_journalling; } - void setJournalling( const bool _on ) + void setJournalling(const bool enabled) { - m_journalling = _on; + m_journalling = enabled; } - // alloc new ID and register object _obj to it - jo_id_t allocID( JournallingObject * _obj ); + /** + * @brief alloc new ID and associate the given object with it + * @return New lookup key for the given object. + */ + jo_id_t allocID(JournallingObject* obj); // if there's already something known about ID _id, but it is currently // unused (e.g. after jouralling object was deleted), register object // _obj to this id - void reallocID( const jo_id_t _id, JournallingObject * _obj ); + void reallocID(jo_id_t id, JournallingObject* obj); // make ID _id unused, but keep all global journalling information // (order of journalling entries etc.) referring to _id - needed for // restoring a journalling object later - void freeID( const jo_id_t _id ) + void freeID(jo_id_t id) { - reallocID( _id, nullptr ); + reallocID(id, nullptr); } - //! hack, not used when saving a file - static jo_id_t idToSave( jo_id_t id ); - //! hack, not used when loading a savefile - static jo_id_t idFromSave( jo_id_t id ); - void clearJournal(); void stopAllJournalling(); - JournallingObject * journallingObject( const jo_id_t _id ) + JournallingObject* journallingObject(const jo_id_t id) { - if( m_joIDs.contains( _id ) ) + if(m_joIDs.count(id) != 0) //TODO Under C++20 can be replaced by (m_joIDs.contains(_id)) { - return m_joIDs[_id]; + return m_joIDs[id]; } return nullptr; } private: - using JoIdMap = QHash; + using JoIdMap = std::unordered_map; struct CheckPoint { - CheckPoint( jo_id_t initID = 0, const DataFile& initData = DataFile( DataFile::Type::JournalData ) ) : + explicit CheckPoint(jo_id_t initID = Uuid::NullUuid(), const DataFile& initData = DataFile(DataFile::Type::JournalData)) : joID( initID ), data( initData ) - { - } + {} jo_id_t joID; DataFile data; } ; diff --git a/include/UuidQt.h b/include/UuidQt.h new file mode 100644 index 00000000000..81f2520630b --- /dev/null +++ b/include/UuidQt.h @@ -0,0 +1,16 @@ +#ifndef LMMS_UUIDQT_H +#define LMMS_UUIDQT_H + +#include +#include "UuidUtility.h" + +/** + * @headerfile This header makes our UUID type compatible with QT + * object marshalling. Use it wherever needed - you'll know + * it's required when QT gives you a compiler error about it. + * Example: Putting UUIDs into QVariant. + */ + +Q_DECLARE_METATYPE(lmms::Uuid::uuid_t); + +#endif //LMMS_UUIDQT_H diff --git a/include/UuidUtility.h b/include/UuidUtility.h new file mode 100644 index 00000000000..316cc8ba699 --- /dev/null +++ b/include/UuidUtility.h @@ -0,0 +1,70 @@ +#ifndef LMMS_UUIDUTILITY_H +#define LMMS_UUIDUTILITY_H + +#include + +/* NOTE: You're wondering why I can't directly include the library header here? + * The answer is the RemoteVstPlugin target, which is categorized as an External + * Project in cmake, and thus doesn't see the same include directories as the + * rest of LMMS. + * Thus, we only predeclare the UUID type here so clients of lmms_basics.h still + * have access to this utility class, and then include where needed. + * If you have a better solution to this problem, please submit a pull request! +*/ +namespace uuids +{ + class uuid; +} + +namespace lmms +{ + + +/** + * @brief Utility class for creating UUIDs. + */ +class Uuid +{ +public: + using uuid_t = uuids::uuid; + + /** + * @brief Creates a null (invalid) UUID. + * @return The null UUID {00000000-0000-0000-0000-000000000000} + */ + static uuid_t NullUuid(); + + /** + * @brief Creates a random UUID using a standard library random number + * generator. + * @return A random UUID with only infinitesimal chance of collision. + */ + static uuid_t RandomUuid(); + + /** + * @brief Create a string representation of the given UUID. + * @return A UUID string representation. No particular format is guaranteed. + */ + static std::string AsString(uuid_t const& uuid); + + + /** + * @brief Create a UUID from a string. Throws std::invalid_argument if + * the string is malformed. + * @return A UUID that's equivalent to the given string representation. + */ + static uuid_t FromString(std::string_view const& string); + + + /** + * @brief Returns whether the given UUID is non-null. + * @return true if the given UUID is valid. + */ + static bool IsValid(uuid_t const& uuid); + +}; + + +} // namespace lmms + +#endif //LMMS_UUIDUTILITY_H diff --git a/include/lmms_basics.h b/include/lmms_basics.h index b566fa781ed..171e6edddf7 100644 --- a/include/lmms_basics.h +++ b/include/lmms_basics.h @@ -29,6 +29,7 @@ #include #include "lmmsconfig.h" +#include "UuidUtility.h" #include #include @@ -53,7 +54,7 @@ using bpm_t = uint16_t; // tempo (MIN_BPM to MAX_BPM) using bitrate_t = uint16_t; // bitrate in kbps using mix_ch_t = uint16_t; // Mixer-channel (0 to MAX_CHANNEL) -using jo_id_t = uint32_t; // (unique) ID of a journalling object +using jo_id_t = Uuid::uuid_t; // (unique) ID of a journalling object // windows headers define "min" and "max" macros, breaking the methods bwloe #undef min diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index e46a864f897..6fefe88f405 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -112,7 +112,7 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co // => it must be appended as a node QDomElement me = doc.createElement( mustQuote ? QString("automatablemodel") : name ); - me.setAttribute( "id", ProjectJournal::idToSave( id() ) ); + me.setAttribute( "id", QString::fromStdString(Uuid::AsString(id() )) ); me.setAttribute( "value", m_value ); me.setAttribute( "scale_type", m_scaleType == ScaleType::Logarithmic ? "log" : "linear" ); if(mustQuote) { @@ -258,7 +258,7 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString& if( node.isElement() ) { QDomElement nodeElement = node.toElement(); - changeID( nodeElement.attribute( "id" ).toInt() ); + changeID(Uuid::FromString(nodeElement.attribute("id" ).toStdString()) ); setValue( LocaleHelper::toFloat( nodeElement.attribute( "value" ) ) ); if( nodeElement.hasAttribute( "scale_type" ) ) { diff --git a/src/core/AutomationClip.cpp b/src/core/AutomationClip.cpp index 6035502704d..b371e3fda6b 100644 --- a/src/core/AutomationClip.cpp +++ b/src/core/AutomationClip.cpp @@ -854,8 +854,9 @@ void AutomationClip::saveSettings( QDomDocument & _doc, QDomElement & _this ) if (object) { QDomElement element = _doc.createElement( "object" ); - element.setAttribute("id", ProjectJournal::idToSave(object->id())); - _this.appendChild(element); + element.setAttribute( "id", QString::fromStdString( + Uuid::AsString(object->id()))); + _this.appendChild( element ); } } } @@ -915,7 +916,7 @@ void AutomationClip::loadSettings( const QDomElement & _this ) } else if( element.tagName() == "object" ) { - m_idsToResolve.push_back(element.attribute("id").toInt()); + m_idsToResolve.push_back(Uuid::FromString(element.attribute("id" ).toStdString())); } } @@ -1087,7 +1088,7 @@ void AutomationClip::resolveAllIDs() { // FIXME: Remove this block once the automation system gets fixed // This is a temporary fix for https://github.com/LMMS/lmms/issues/3781 - o = Engine::projectJournal()->journallingObject(ProjectJournal::idFromSave(id)); + o = Engine::projectJournal()->journallingObject(id); if( o && dynamic_cast( o ) ) { a->addObject( dynamic_cast( o ), false ); @@ -1096,7 +1097,7 @@ void AutomationClip::resolveAllIDs() { // FIXME: Remove this block once the automation system gets fixed // This is a temporary fix for https://github.com/LMMS/lmms/issues/4781 - o = Engine::projectJournal()->journallingObject(ProjectJournal::idToSave(id)); + o = Engine::projectJournal()->journallingObject(id); if( o && dynamic_cast( o ) ) { a->addObject( dynamic_cast( o ), false ); diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 26d458f9e76..92fcbc2f68a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -82,6 +82,7 @@ set(LMMS_SRCS core/ToolPlugin.cpp core/Track.cpp core/TrackContainer.cpp + core/UuidUtility.cpp core/UpgradeExtendedNoteRange.h core/UpgradeExtendedNoteRange.cpp core/Clip.cpp diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index a520e6bc5c9..614a8820a2d 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -57,8 +57,9 @@ namespace lmms { +using old_jo_id_t = uint32_t; -static void findIds(const QDomElement& elem, QList& idList); +static void findIds(const QDomElement& elem, QList& idList); // QMap with the DOM elements that access file resources @@ -1048,9 +1049,9 @@ void DataFile::upgrade_0_4_0_rc2() void DataFile::upgrade_1_0_99() { - jo_id_t last_assigned_id = 0; + old_jo_id_t last_assigned_id = 0; - QList idList; + QList idList; findIds(documentElement(), idList); QDomNodeList list = elementsByTagName("ladspacontrols"); @@ -1069,7 +1070,7 @@ void DataFile::upgrade_1_0_99() me.setAttribute("value", el.attribute("data")); me.setAttribute("scale_type", "log"); - jo_id_t id; + old_jo_id_t id; for(id = last_assigned_id + 1; idList.contains(id); id++) { @@ -2045,7 +2046,7 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) } -void findIds(const QDomElement& elem, QList& idList) +void findIds(const QDomElement& elem, QList& idList) { if(elem.hasAttribute("id")) { diff --git a/src/core/JournallingObject.cpp b/src/core/JournallingObject.cpp index 802f4291ecd..172f83ec669 100644 --- a/src/core/JournallingObject.cpp +++ b/src/core/JournallingObject.cpp @@ -74,7 +74,7 @@ QDomElement JournallingObject::saveState( QDomDocument & _doc, QDomElement _this = SerializingObject::saveState( _doc, _parent ); QDomElement journalNode = _doc.createElement( "journallingObject" ); - journalNode.setAttribute( "id", id() ); + journalNode.setAttribute( "id", QString::fromStdString(Uuid::AsString(id())) ); journalNode.setAttribute( "metadata", true ); _this.appendChild( journalNode ); @@ -99,8 +99,8 @@ void JournallingObject::restoreState( const QDomElement & _this ) { if( node.isElement() && node.nodeName() == "journal" ) { - const jo_id_t new_id = node.toElement().attribute( "id" ).toInt(); - if( new_id ) + const jo_id_t new_id = Uuid::FromString(node.toElement().attribute("id" ).toStdString()); + if( Uuid::IsValid(new_id) ) { changeID( new_id ); } @@ -130,8 +130,9 @@ void JournallingObject::changeID( jo_id_t _id ) dynamic_cast( jo )-> displayName(); } - fprintf( stderr, "JO-ID %d already in use by %s!\n", - (int) _id, used_by.toUtf8().constData() ); + // This message should never ever be seen anymore. + fprintf(stderr, "JO-ID %s already in use by %s!\n", + Uuid::AsString(_id).c_str(), used_by.toUtf8().constData() ); return; } diff --git a/src/core/ProjectJournal.cpp b/src/core/ProjectJournal.cpp index fc77c98e65d..fa1f2a10162 100644 --- a/src/core/ProjectJournal.cpp +++ b/src/core/ProjectJournal.cpp @@ -32,10 +32,6 @@ namespace lmms { -//! Avoid clashes between loaded IDs (have the bit cleared) -//! and newly created IDs (have the bit set) -static const int EO_ID_MSB = 1 << 23; - const int ProjectJournal::MAX_UNDO_STATES = 100; // TODO: make this configurable in settings ProjectJournal::ProjectJournal() : @@ -131,14 +127,8 @@ void ProjectJournal::addJournalCheckPoint( JournallingObject *jo ) jo_id_t ProjectJournal::allocID( JournallingObject * _obj ) { - jo_id_t id; - for( jo_id_t tid = rand(); m_joIDs.contains( id = tid % EO_ID_MSB - | EO_ID_MSB ); tid++ ) - { - } - + jo_id_t id = Uuid::RandomUuid(); m_joIDs[id] = _obj; - //printf("new id: %d\n", id ); return id; } @@ -147,37 +137,18 @@ jo_id_t ProjectJournal::allocID( JournallingObject * _obj ) void ProjectJournal::reallocID( const jo_id_t _id, JournallingObject * _obj ) { - //printf("realloc %d %d\n", _id, _obj ); -// if( m_joIDs.contains( _id ) ) - { - m_joIDs[_id] = _obj; - } + m_joIDs[_id] = _obj; } - - -jo_id_t ProjectJournal::idToSave( jo_id_t id ) -{ - return id & ~EO_ID_MSB; -} - -jo_id_t ProjectJournal::idFromSave( jo_id_t id ) -{ - return id | EO_ID_MSB; -} - - - - void ProjectJournal::clearJournal() { m_undoCheckPoints.clear(); m_redoCheckPoints.clear(); - for( JoIdMap::Iterator it = m_joIDs.begin(); it != m_joIDs.end(); ) + for( auto it = m_joIDs.begin(); it != m_joIDs.end(); ) { - if( it.value() == nullptr ) + if( it->second == nullptr ) { it = m_joIDs.erase( it ); } @@ -190,11 +161,11 @@ void ProjectJournal::clearJournal() void ProjectJournal::stopAllJournalling() { - for( JoIdMap::Iterator it = m_joIDs.begin(); it != m_joIDs.end(); ++it) + for(auto& m_joID : m_joIDs) { - if( it.value() != nullptr ) + if( m_joID.second != nullptr ) { - it.value()->setJournalling(false); + m_joID.second->setJournalling(false); } } setJournalling(false); diff --git a/src/core/RemotePlugin.cpp b/src/core/RemotePlugin.cpp index 088bc3cd868..0c0f6e78653 100644 --- a/src/core/RemotePlugin.cpp +++ b/src/core/RemotePlugin.cpp @@ -37,6 +37,7 @@ #include "AudioEngine.h" #include "Engine.h" #include "Song.h" +#include "UuidUtility.h" #include #include @@ -151,8 +152,9 @@ RemotePlugin::RemotePlugin() : struct sockaddr_un sa; sa.sun_family = AF_LOCAL; - m_socketFile = QDir::tempPath() + QDir::separator() + - QUuid::createUuid().toString(); + // TODO Currently converting a QString to std::string and back here; when we switch from Quuid to something else, + // that problem solves itself; but look at this line anyway because we'll probably also remove the other QT types. + m_socketFile = QDir::tempPath() + QDir::separator() + QString::fromStdString(Uuid::AsString(Uuid::RandomUuid())); auto path = m_socketFile.toUtf8(); size_t length = path.length(); if ( length >= sizeof sa.sun_path ) @@ -479,7 +481,7 @@ void RemotePlugin::resizeSharedProcessingMemory() const size_t s = (m_inputCount + m_outputCount) * Engine::audioEngine()->framesPerPeriod(); try { - m_audioBuffer.create(QUuid::createUuid().toString().toStdString(), s); + m_audioBuffer.create(Uuid::AsString(Uuid::RandomUuid()), s); } catch (const std::runtime_error& error) { diff --git a/src/core/UuidUtility.cpp b/src/core/UuidUtility.cpp new file mode 100644 index 00000000000..f9fac7a700b --- /dev/null +++ b/src/core/UuidUtility.cpp @@ -0,0 +1,46 @@ +#include "UuidUtility.h" +#include + +namespace lmms +{ + +auto Uuid::NullUuid() -> uuid_t +{ + return uuid_t{}; +} + + +auto Uuid::RandomUuid() -> uuid_t +{ + std::random_device rnd; + auto seed = std::array{}; + std::generate(std::begin(seed), std::end(seed), std::ref(rnd)); + auto seq = std::seed_seq(std::begin(seed), std::end(seed)); + auto stdGenerator = std::mt19937(seq); + + auto gen = uuids::uuid_random_generator{stdGenerator}; + return gen(); +} + +auto Uuid::AsString(uuid_t const& uuid) -> std::string +{ + return uuids::to_string(uuid); +} + +auto Uuid::FromString(std::string_view const& string) -> uuid_t +{ + auto id = uuids::uuid::from_string(string); + if (!id.has_value()) + { + throw std::invalid_argument("Malformed UUID."); + } + return id.value(); +} + +bool Uuid::IsValid(uuid_t const& uuid) +{ + return !uuid.is_nil(); +} + + +} // namespace lmms \ No newline at end of file diff --git a/src/gui/AutomatableModelView.cpp b/src/gui/AutomatableModelView.cpp index 0e364993f06..b6cbbe3f283 100644 --- a/src/gui/AutomatableModelView.cpp +++ b/src/gui/AutomatableModelView.cpp @@ -173,7 +173,7 @@ void AutomatableModelView::mousePressEvent( QMouseEvent* event ) { if( event->button() == Qt::LeftButton && event->modifiers() & Qt::ControlModifier ) { - new gui::StringPairDrag( "automatable_model", QString::number( modelUntyped()->id() ), QPixmap(), widget() ); + new gui::StringPairDrag("automatable_model", QString::fromStdString(Uuid::AsString(modelUntyped()->id()) ), QPixmap(), widget() ); event->accept(); } else if( event->button() == Qt::MiddleButton ) diff --git a/src/gui/clips/AutomationClipView.cpp b/src/gui/clips/AutomationClipView.cpp index 7ddb7015182..debea84c0af 100644 --- a/src/gui/clips/AutomationClipView.cpp +++ b/src/gui/clips/AutomationClipView.cpp @@ -40,6 +40,8 @@ #include "Engine.h" +#include "UuidQt.h" + namespace lmms::gui { @@ -104,7 +106,7 @@ void AutomationClipView::changeName() void AutomationClipView::disconnectObject( QAction * _a ) { JournallingObject * j = Engine::projectJournal()-> - journallingObject( _a->data().toInt() ); + journallingObject( _a->data().value() ); if( j && dynamic_cast( j ) ) { float oldMin = m_clip->getMin(); @@ -194,7 +196,7 @@ void AutomationClipView::constructContextMenu( QMenu * _cm ) if (object) { a = new QAction(tr("Disconnect \"%1\"").arg(object->fullDisplayName()), m); - a->setData(object->id()); + a->setData(QVariant::fromValue(object->id())); m->addAction( a ); } } @@ -424,7 +426,9 @@ void AutomationClipView::dropEvent( QDropEvent * _de ) QString val = StringPairDrag::decodeValue( _de ); if( type == "automatable_model" ) { - auto mod = dynamic_cast(Engine::projectJournal()->journallingObject(val.toInt())); + auto journalID = Uuid::FromString(val.toStdString()); + auto* mod = dynamic_cast( + Engine::projectJournal()->journallingObject( journalID)); if( mod != nullptr ) { bool added = m_clip->addObject( mod ); diff --git a/src/gui/clips/ClipView.cpp b/src/gui/clips/ClipView.cpp index 5c8a12b91e3..c3ad805c721 100644 --- a/src/gui/clips/ClipView.cpp +++ b/src/gui/clips/ClipView.cpp @@ -559,7 +559,7 @@ DataFile ClipView::createClipDataFiles( QDomElement metadata = dataFile.createElement( "copyMetadata" ); // initialTrackIndex is the index of the track that was touched metadata.setAttribute( "initialTrackIndex", initialTrackIndex ); - metadata.setAttribute( "trackContainerId", tc->id() ); + metadata.setAttribute( "trackContainerId", QString::fromStdString(Uuid::AsString(tc->id())) ); // grabbedClipPos is the pos of the bar containing the Clip we grabbed metadata.setAttribute( "grabbedClipPos", m_clip->startPosition() ); diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index 8fd892597df..a5080b26243 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -2293,7 +2293,9 @@ void AutomationEditorWindow::dropEvent( QDropEvent *_de ) QString val = StringPairDrag::decodeValue( _de ); if( type == "automatable_model" ) { - auto mod = dynamic_cast(Engine::projectJournal()->journallingObject(val.toInt())); + auto journalID = Uuid::FromString(val.toStdString()); + auto* mod = dynamic_cast( + Engine::projectJournal()->journallingObject(journalID)); if (mod != nullptr) { bool added = m_editor->m_clip->addObject( mod ); diff --git a/src/gui/instrument/PianoView.cpp b/src/gui/instrument/PianoView.cpp index c8882898bc2..293ae3d34ae 100644 --- a/src/gui/instrument/PianoView.cpp +++ b/src/gui/instrument/PianoView.cpp @@ -449,7 +449,7 @@ void PianoView::mousePressEvent(QMouseEvent *me) if (me->modifiers() & Qt::ControlModifier) { - new StringPairDrag("automatable_model", QString::number(m_movedNoteModel->id()), QPixmap(), this); + new StringPairDrag("automatable_model", QString::fromStdString(Uuid::AsString(m_movedNoteModel->id())), QPixmap(), this); me->accept(); } else diff --git a/src/gui/tracks/AutomationTrackView.cpp b/src/gui/tracks/AutomationTrackView.cpp index 53e022c1513..4b3085955e3 100644 --- a/src/gui/tracks/AutomationTrackView.cpp +++ b/src/gui/tracks/AutomationTrackView.cpp @@ -61,7 +61,9 @@ void AutomationTrackView::dropEvent( QDropEvent * _de ) QString val = StringPairDrag::decodeValue( _de ); if( type == "automatable_model" ) { - auto mod = dynamic_cast(Engine::projectJournal()->journallingObject(val.toInt())); + auto journalID = Uuid::FromString(val.toStdString()); + auto* mod = dynamic_cast( + Engine::projectJournal()->journallingObject(journalID)); if( mod != nullptr ) { TimePos pos = TimePos( trackContainerView()-> diff --git a/src/gui/tracks/TrackContentWidget.cpp b/src/gui/tracks/TrackContentWidget.cpp index 619eff8317b..c8fb7ec2066 100644 --- a/src/gui/tracks/TrackContentWidget.cpp +++ b/src/gui/tracks/TrackContentWidget.cpp @@ -349,7 +349,7 @@ bool TrackContentWidget::canPasteSelection( TimePos clipPos, const QMimeData* md const int currentTrackIndex = currentTrackIt != tracks.end() ? std::distance(tracks.begin(), currentTrackIt) : -1; // Don't paste if we're on the same bar and allowSameBar is false - auto sourceTrackContainerId = metadata.attributeNode( "trackContainerId" ).value().toUInt(); + auto sourceTrackContainerId = Uuid::FromString(metadata.attributeNode("trackContainerId" ).value().toStdString()); if( !allowSameBar && sourceTrackContainerId == t->trackContainer()->id() && clipPos == grabbedClipBar && currentTrackIndex == initialTrackIndex ) { diff --git a/src/gui/widgets/AutomatableButton.cpp b/src/gui/widgets/AutomatableButton.cpp index 6e9cd23e48e..1f7554b356f 100644 --- a/src/gui/widgets/AutomatableButton.cpp +++ b/src/gui/widgets/AutomatableButton.cpp @@ -128,7 +128,7 @@ void AutomatableButton::mousePressEvent( QMouseEvent * _me ) // A group, we must get process it instead auto groupView = (AutomatableModelView*)m_group; new StringPairDrag( "automatable_model", - QString::number( groupView->modelUntyped()->id() ), + QString::fromStdString(Uuid::AsString(groupView->modelUntyped()->id()) ), QPixmap(), widget() ); // TODO: ^^ Maybe use a predefined icon instead of the button they happened to select _me->accept();