summaryrefslogtreecommitdiffstats
path: root/src/third-party/scnlib/include/scn/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/third-party/scnlib/include/scn/util')
-rw-r--r--src/third-party/scnlib/include/scn/util/algorithm.h80
-rw-r--r--src/third-party/scnlib/include/scn/util/array.h105
-rw-r--r--src/third-party/scnlib/include/scn/util/expected.h158
-rw-r--r--src/third-party/scnlib/include/scn/util/math.h121
-rw-r--r--src/third-party/scnlib/include/scn/util/memory.h404
-rw-r--r--src/third-party/scnlib/include/scn/util/meta.h77
-rw-r--r--src/third-party/scnlib/include/scn/util/optional.h105
-rw-r--r--src/third-party/scnlib/include/scn/util/small_vector.h788
-rw-r--r--src/third-party/scnlib/include/scn/util/span.h240
-rw-r--r--src/third-party/scnlib/include/scn/util/string_view.h270
-rw-r--r--src/third-party/scnlib/include/scn/util/unique_ptr.h118
11 files changed, 2466 insertions, 0 deletions
diff --git a/src/third-party/scnlib/include/scn/util/algorithm.h b/src/third-party/scnlib/include/scn/util/algorithm.h
new file mode 100644
index 0000000..a17b6b6
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/algorithm.h
@@ -0,0 +1,80 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_ALGORITHM_H
+#define SCN_UTIL_ALGORITHM_H
+
+#include "../detail/fwd.h"
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace detail {
+ /**
+ * Implementation of `std::exchange` for C++11
+ */
+ template <typename T, typename U = T>
+ SCN_CONSTEXPR14 T exchange(T& obj, U&& new_value)
+ {
+ T old_value = SCN_MOVE(obj);
+ obj = SCN_FWD(new_value);
+ return old_value;
+ }
+
+ /**
+ * Implementation of `std::max` without including `<algorithm>`
+ */
+ template <typename T>
+ constexpr T max(T a, T b) noexcept
+ {
+ return (a < b) ? b : a;
+ }
+
+ /**
+ * Implementation of `std::min_element` without including `<algorithm>`
+ */
+ template <typename It>
+ SCN_CONSTEXPR14 It min_element(It first, It last)
+ {
+ if (first == last) {
+ return last;
+ }
+
+ It smallest = first;
+ ++first;
+ for (; first != last; ++first) {
+ if (*first < *smallest) {
+ smallest = first;
+ }
+ }
+ return smallest;
+ }
+
+ /**
+ * Implementation of `std::min` without including `<algorithm>`
+ */
+ template <typename T>
+ constexpr T min(T a, T b) noexcept
+ {
+ return (b < a) ? b : a;
+ }
+ } // namespace detail
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif
diff --git a/src/third-party/scnlib/include/scn/util/array.h b/src/third-party/scnlib/include/scn/util/array.h
new file mode 100644
index 0000000..6c86488
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/array.h
@@ -0,0 +1,105 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_ARRAY_H
+#define SCN_UTIL_ARRAY_H
+
+#include "../detail/fwd.h"
+
+#include <cstdint>
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace detail {
+ /**
+ * Implementation of `std::array` without including `<array>` (can be
+ * heavy-ish)
+ */
+ template <typename T, std::size_t N>
+ struct array {
+ static_assert(N > 0, "zero-sized array not supported");
+
+ using value_type = T;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using reference = T&;
+ using const_reference = const T&;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+
+ SCN_CONSTEXPR14 reference operator[](size_type i)
+ {
+ SCN_EXPECT(i < size());
+ return m_data[i];
+ }
+ SCN_CONSTEXPR14 const_reference operator[](size_type i) const
+ {
+ SCN_EXPECT(i < size());
+ return m_data[i];
+ }
+
+ SCN_CONSTEXPR14 iterator begin() noexcept
+ {
+ return m_data;
+ }
+ constexpr const_iterator begin() const noexcept
+ {
+ return m_data;
+ }
+ constexpr const_iterator cbegin() const noexcept
+ {
+ return m_data;
+ }
+
+ SCN_CONSTEXPR14 iterator end() noexcept
+ {
+ return m_data + N;
+ }
+ constexpr const_iterator end() const noexcept
+ {
+ return m_data + N;
+ }
+ constexpr const_iterator cend() const noexcept
+ {
+ return m_data + N;
+ }
+
+ SCN_CONSTEXPR14 pointer data() noexcept
+ {
+ return m_data;
+ }
+ constexpr const_pointer data() const noexcept
+ {
+ return m_data;
+ }
+
+ SCN_NODISCARD constexpr size_type size() const noexcept
+ {
+ return N;
+ }
+
+ T m_data[N];
+ };
+ } // namespace detail
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif
diff --git a/src/third-party/scnlib/include/scn/util/expected.h b/src/third-party/scnlib/include/scn/util/expected.h
new file mode 100644
index 0000000..f7c9a82
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/expected.h
@@ -0,0 +1,158 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_EXPECTED_H
+#define SCN_UTIL_EXPECTED_H
+
+#include "memory.h"
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ /**
+ * expected-like type.
+ * For situations where there can be a value in case of success or an error
+ * code.
+ */
+ template <typename T, typename Error, typename Enable>
+ class expected;
+
+ /**
+ * expected-like type for default-constructible success values.
+ * Not optimized for space-efficiency (both members are stored
+ * simultaneously).
+ * `error` is used as the error value and discriminant flag.
+ */
+ template <typename T, typename Error>
+ class expected<T,
+ Error,
+ typename std::enable_if<
+ std::is_default_constructible<T>::value>::type> {
+ public:
+ using success_type = T;
+ using error_type = Error;
+
+ constexpr expected() = default;
+ constexpr expected(success_type s) : m_s(s) {}
+ constexpr expected(error_type e) : m_e(e) {}
+
+ SCN_NODISCARD constexpr bool has_value() const noexcept
+ {
+ return m_e == Error{};
+ }
+ constexpr explicit operator bool() const noexcept
+ {
+ return has_value();
+ }
+ constexpr bool operator!() const noexcept
+ {
+ return !operator bool();
+ }
+
+ SCN_CONSTEXPR14 success_type& value() & noexcept
+ {
+ return m_s;
+ }
+ constexpr success_type value() const& noexcept
+ {
+ return m_s;
+ }
+ SCN_CONSTEXPR14 success_type value() && noexcept
+ {
+ return SCN_MOVE(m_s);
+ }
+
+ SCN_CONSTEXPR14 error_type& error() noexcept
+ {
+ return m_e;
+ }
+ constexpr error_type error() const noexcept
+ {
+ return m_e;
+ }
+
+ private:
+ success_type m_s{};
+ error_type m_e{error_type::success_tag()};
+ };
+
+ /**
+ * expected-like type for non-default-constructible success values.
+ * Not optimized for space-efficiency.
+ * `error` is used as the error value and discriminant flag.
+ */
+ template <typename T, typename Error>
+ class expected<T,
+ Error,
+ typename std::enable_if<
+ !std::is_default_constructible<T>::value>::type> {
+ public:
+ using success_type = T;
+ using success_storage = detail::erased_storage<T>;
+ using error_type = Error;
+
+ expected(success_type s) : m_s(SCN_MOVE(s)) {}
+ constexpr expected(error_type e) : m_e(e) {}
+
+ SCN_NODISCARD constexpr bool has_value() const noexcept
+ {
+ return m_e == Error{};
+ }
+ constexpr explicit operator bool() const noexcept
+ {
+ return has_value();
+ }
+ constexpr bool operator!() const noexcept
+ {
+ return !operator bool();
+ }
+
+ SCN_CONSTEXPR14 success_type& value() noexcept
+ {
+ return *m_s;
+ }
+ constexpr const success_type& value() const noexcept
+ {
+ return *m_s;
+ }
+
+ SCN_CONSTEXPR14 error_type& error() noexcept
+ {
+ return m_e;
+ }
+ constexpr error_type error() const noexcept
+ {
+ return m_e;
+ }
+
+ private:
+ success_storage m_s{};
+ error_type m_e{error_type::success_tag()};
+ };
+
+ template <typename T,
+ typename U = typename std::remove_cv<
+ typename std::remove_reference<T>::type>::type>
+ expected<U> make_expected(T&& val)
+ {
+ return expected<U>(std::forward<T>(val));
+ }
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif
diff --git a/src/third-party/scnlib/include/scn/util/math.h b/src/third-party/scnlib/include/scn/util/math.h
new file mode 100644
index 0000000..4cca941
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/math.h
@@ -0,0 +1,121 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_MATH_H
+#define SCN_UTIL_MATH_H
+
+#include "../detail/fwd.h"
+
+#include <cmath>
+#include <limits>
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace detail {
+ template <typename Integral>
+ SCN_CONSTEXPR14 int _max_digits(int base) noexcept
+ {
+ using lim = std::numeric_limits<Integral>;
+
+ char base8_digits[8] = {3, 5, 0, 11, 0, 0, 0, 21};
+
+ if (base == 10) {
+ return lim::digits10;
+ }
+ if (base == 8) {
+ return static_cast<int>(base8_digits[sizeof(Integral) - 1]);
+ }
+ if (base == lim::radix) {
+ return lim::digits;
+ }
+
+ auto i = lim::max();
+
+ Integral digits = 0;
+ while (i) {
+ i /= static_cast<Integral>(base);
+ digits++;
+ }
+ return static_cast<int>(digits);
+ }
+
+ /**
+ * Returns the maximum number of digits that an integer in base `base`
+ * can have, including the sign.
+ *
+ * If `base == 0`, uses `2` (longest), and adds 2 to the result, to
+ * accommodate for a base prefix (e.g. `0x`)
+ */
+ template <typename Integral>
+ SCN_CONSTEXPR14 int max_digits(int base) noexcept
+ {
+ auto b = base == 0 ? 2 : base;
+ auto d = _max_digits<Integral>(b) +
+ (std::is_signed<Integral>::value ? 1 : 0);
+ if (base == 0) {
+ return d + 2; // accommodate for 0x/0o
+ }
+ return d;
+ }
+
+ /**
+ * Implementation of `std::div`, which is constexpr pre-C++23
+ */
+ template <typename T>
+ constexpr std::pair<T, T> div(T l, T r) noexcept
+ {
+ return {l / r, l % r};
+ }
+
+ template <typename T>
+ struct zero_value;
+ template <>
+ struct zero_value<float> {
+ static constexpr float value = 0.0f;
+ };
+ template <>
+ struct zero_value<double> {
+ static constexpr double value = 0.0;
+ };
+ template <>
+ struct zero_value<long double> {
+ static constexpr long double value = 0.0l;
+ };
+
+ /**
+ * Returns `true` if `ch` is a digit for an integer in base `base`.
+ */
+ template <typename CharT>
+ bool is_base_digit(CharT ch, int base)
+ {
+ if (base <= 10) {
+ return ch >= static_cast<CharT>('0') &&
+ ch <= static_cast<CharT>('0') + base - 1;
+ }
+ return is_base_digit(ch, 10) ||
+ (ch >= static_cast<CharT>('a') &&
+ ch <= static_cast<CharT>('a') + base - 1) ||
+ (ch >= static_cast<CharT>('A') &&
+ ch <= static_cast<CharT>('A') + base - 1);
+ }
+ } // namespace detail
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif
diff --git a/src/third-party/scnlib/include/scn/util/memory.h b/src/third-party/scnlib/include/scn/util/memory.h
new file mode 100644
index 0000000..9dfb970
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/memory.h
@@ -0,0 +1,404 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_MEMORY_H
+#define SCN_UTIL_MEMORY_H
+
+#include "meta.h"
+
+#include <cstring>
+#include <new>
+
+SCN_GCC_PUSH
+SCN_GCC_IGNORE("-Wnoexcept")
+#include <iterator>
+SCN_GCC_POP
+
+#if SCN_MSVC && SCN_HAS_STRING_VIEW
+#include <string_view>
+#endif
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace detail {
+ template <typename T>
+ struct pointer_traits;
+
+ template <typename T>
+ struct pointer_traits<T*> {
+ using pointer = T*;
+ using element_type = T;
+ using difference_type = std::ptrdiff_t;
+
+ template <typename U>
+ using rebind = U*;
+
+ template <typename U = T,
+ typename std::enable_if<!std::is_void<U>::value>::type* =
+ nullptr>
+ static constexpr pointer pointer_to(U& r) noexcept
+ {
+ return &r;
+ }
+ };
+
+ template <typename T>
+ constexpr T* to_address_impl(T* p, priority_tag<2>) noexcept
+ {
+ return p;
+ }
+ template <typename Ptr>
+ SCN_CONSTEXPR14 auto to_address_impl(const Ptr& p,
+ priority_tag<1>) noexcept
+ -> decltype(::scn::detail::pointer_traits<Ptr>::to_address(p))
+ {
+ return ::scn::detail::pointer_traits<Ptr>::to_address(p);
+ }
+ template <typename Ptr>
+ constexpr auto to_address_impl(const Ptr& p, priority_tag<0>) noexcept
+ -> decltype(::scn::detail::to_address_impl(p.operator->(),
+ priority_tag<2>{}))
+ {
+ return ::scn::detail::to_address_impl(p.operator->(),
+ priority_tag<2>{});
+ }
+
+ template <typename Ptr>
+ constexpr auto to_address(Ptr&& p) noexcept
+ -> decltype(::scn::detail::to_address_impl(SCN_FWD(p),
+ priority_tag<2>{}))
+ {
+ return ::scn::detail::to_address_impl(SCN_FWD(p),
+ priority_tag<2>{});
+ }
+
+#if SCN_WINDOWS
+ template <typename I, typename B, typename E>
+ SCN_CONSTEXPR14 auto to_address_safe(I&& p, B begin, E end) noexcept
+ -> decltype(to_address(SCN_FWD(p)))
+ {
+ if (p >= begin && p < end) {
+ return to_address(SCN_FWD(p));
+ }
+ if (begin == end) {
+ return to_address(SCN_FWD(p));
+ }
+ if (p == end) {
+ return to_address(SCN_FWD(p) - 1) + 1;
+ }
+ SCN_ENSURE(false);
+ SCN_UNREACHABLE;
+ }
+#else
+ template <typename I, typename B, typename E>
+ SCN_CONSTEXPR14 auto to_address_safe(I&& p, B, E) noexcept
+ -> decltype(to_address(SCN_FWD(p)))
+ {
+ return to_address(SCN_FWD(p));
+ }
+#endif
+
+ // Workaround for MSVC _String_view_iterator
+#if SCN_MSVC && SCN_HAS_STRING_VIEW
+ template <typename Traits>
+ struct pointer_traits<std::_String_view_iterator<Traits>> {
+ using iterator = std::_String_view_iterator<Traits>;
+ using pointer = typename iterator::pointer;
+ using element_type = typename iterator::value_type;
+ using difference_type = typename iterator::difference_type;
+
+ static constexpr pointer to_address(const iterator& it) noexcept
+ {
+ // operator-> of _String_view_iterator
+ // is checked for past-the-end dereference,
+ // even though operator-> isn't dereferencing anything :)))
+ return it._Unwrapped();
+ }
+ };
+#endif
+
+ template <typename T>
+ constexpr T* launder(T* p) noexcept
+ {
+#if SCN_HAS_LAUNDER
+ return std::launder(p);
+#else
+ return p;
+#endif
+ }
+
+ template <typename ForwardIt, typename T>
+ void uninitialized_fill(ForwardIt first,
+ ForwardIt last,
+ const T& value,
+ std::true_type) noexcept
+ {
+ using value_type =
+ typename std::iterator_traits<ForwardIt>::value_type;
+ const auto dist = static_cast<size_t>(std::distance(first, last)) *
+ sizeof(value_type);
+ std::memset(&*first, static_cast<unsigned char>(value), dist);
+ }
+ template <typename ForwardIt, typename T>
+ void uninitialized_fill(ForwardIt first,
+ ForwardIt last,
+ const T& value,
+ std::false_type) noexcept
+ {
+ using value_type =
+ typename std::iterator_traits<ForwardIt>::value_type;
+ ForwardIt current = first;
+ for (; current != last; ++current) {
+ ::new (static_cast<void*>(std::addressof(*current)))
+ value_type(value);
+ }
+ }
+ template <typename ForwardIt, typename T>
+ void uninitialized_fill(ForwardIt first,
+ ForwardIt last,
+ const T& value) noexcept
+ {
+ constexpr bool B = std::is_trivially_copyable<T>::value &&
+ std::is_pointer<ForwardIt>::value &&
+ sizeof(T) == 1;
+ return uninitialized_fill(first, last, value,
+ std::integral_constant<bool, B>{});
+ }
+
+ template <typename ForwardIt>
+ void uninitialized_fill_default_construct(ForwardIt first,
+ ForwardIt last) noexcept
+ {
+ using value_type =
+ typename std::iterator_traits<ForwardIt>::value_type;
+ ForwardIt current = first;
+ for (; current != last; ++current) {
+ ::new (static_cast<void*>(std::addressof(*current))) value_type;
+ }
+ }
+ template <typename ForwardIt>
+ void uninitialized_fill_value_init(ForwardIt first,
+ ForwardIt last) noexcept
+ {
+ using value_type =
+ typename std::iterator_traits<ForwardIt>::value_type;
+ ForwardIt current = first;
+ for (; current != last; ++current) {
+ ::new (static_cast<void*>(std::addressof(*current)))
+ value_type();
+ }
+ }
+
+ template <typename InputIt,
+ typename ForwardIt,
+ typename std::enable_if<
+ !std::is_trivially_copyable<typename std::iterator_traits<
+ ForwardIt>::value_type>::value>::type* = nullptr>
+ ForwardIt uninitialized_copy(InputIt first,
+ InputIt last,
+ ForwardIt d_first) noexcept
+ {
+ using value_type =
+ typename std::iterator_traits<ForwardIt>::value_type;
+ ForwardIt current = d_first;
+ for (; first != last; ++first, (void)++current) {
+ ::new (static_cast<void*>(std::addressof(*current)))
+ value_type(*first);
+ }
+ return current;
+ }
+ template <typename InputIt,
+ typename ForwardIt,
+ typename std::enable_if<
+ std::is_trivially_copyable<typename std::iterator_traits<
+ ForwardIt>::value_type>::value>::type* = nullptr>
+ ForwardIt uninitialized_copy(InputIt first,
+ InputIt last,
+ ForwardIt d_first) noexcept
+ {
+ using value_type =
+ typename std::iterator_traits<ForwardIt>::value_type;
+ using pointer = typename std::iterator_traits<ForwardIt>::pointer;
+ auto ptr =
+ std::memcpy(std::addressof(*d_first), std::addressof(*first),
+ static_cast<size_t>(std::distance(first, last)) *
+ sizeof(value_type));
+ return ForwardIt{static_cast<pointer>(ptr)};
+ }
+
+ template <typename InputIt,
+ typename ForwardIt,
+ typename std::enable_if<
+ !std::is_trivially_copyable<typename std::iterator_traits<
+ ForwardIt>::value_type>::value>::type* = nullptr>
+ ForwardIt uninitialized_move(InputIt first,
+ InputIt last,
+ ForwardIt d_first) noexcept
+ {
+ using value_type =
+ typename std::iterator_traits<ForwardIt>::value_type;
+ ForwardIt current = d_first;
+ for (; first != last; ++first, (void)++current) {
+ ::new (static_cast<void*>(std::addressof(*current)))
+ value_type(std::move(*first));
+ }
+ return current;
+ }
+ template <typename InputIt,
+ typename ForwardIt,
+ typename std::enable_if<
+ std::is_trivially_copyable<typename std::iterator_traits<
+ ForwardIt>::value_type>::value>::type* = nullptr>
+ ForwardIt uninitialized_move(InputIt first,
+ InputIt last,
+ ForwardIt d_first) noexcept
+ {
+ using value_type =
+ typename std::iterator_traits<ForwardIt>::value_type;
+ using pointer = typename std::iterator_traits<ForwardIt>::pointer;
+ auto ptr =
+ std::memcpy(std::addressof(*d_first), std::addressof(*first),
+ static_cast<size_t>(std::distance(first, last)) *
+ sizeof(value_type));
+ return ForwardIt(static_cast<pointer>(ptr));
+ }
+
+ template <typename T>
+ class SCN_TRIVIAL_ABI erased_storage {
+ public:
+ using value_type = T;
+ using pointer = T*;
+ using storage_type = unsigned char[sizeof(T)];
+
+ constexpr erased_storage() noexcept = default;
+
+ erased_storage(T val) noexcept(
+ std::is_nothrow_move_constructible<T>::value)
+ : m_ptr(::new (static_cast<void*>(&m_data)) T(SCN_MOVE(val)))
+ {
+ }
+
+ erased_storage(const erased_storage& other)
+ : m_ptr(other ? ::new (static_cast<void*>(&m_data))
+ T(other.get())
+ : nullptr)
+ {
+ }
+ erased_storage& operator=(const erased_storage& other)
+ {
+ _destruct();
+ if (other) {
+ m_ptr = ::new (static_cast<void*>(&m_data)) T(other.get());
+ }
+ return *this;
+ }
+
+ erased_storage(erased_storage&& other) noexcept
+ : m_ptr(other ? ::new (static_cast<void*>(&m_data))
+ T(SCN_MOVE(other.get()))
+ : nullptr)
+ {
+ other.m_ptr = nullptr;
+ }
+ erased_storage& operator=(erased_storage&& other) noexcept
+ {
+ _destruct();
+ if (other) {
+ m_ptr = ::new (static_cast<void*>(&m_data))
+ T(SCN_MOVE(other.get()));
+ other.m_ptr = nullptr;
+ }
+ return *this;
+ }
+
+ ~erased_storage() noexcept
+ {
+ _destruct();
+ }
+
+ SCN_NODISCARD constexpr bool has_value() const noexcept
+ {
+ return m_ptr != nullptr;
+ }
+ constexpr explicit operator bool() const noexcept
+ {
+ return has_value();
+ }
+
+ SCN_CONSTEXPR14 T& get() noexcept
+ {
+ SCN_EXPECT(has_value());
+ return _get();
+ }
+ SCN_CONSTEXPR14 const T& get() const noexcept
+ {
+ SCN_EXPECT(has_value());
+ return _get();
+ }
+
+ SCN_CONSTEXPR14 T& operator*() noexcept
+ {
+ SCN_EXPECT(has_value());
+ return _get();
+ }
+ SCN_CONSTEXPR14 const T& operator*() const noexcept
+ {
+ SCN_EXPECT(has_value());
+ return _get();
+ }
+
+ SCN_CONSTEXPR14 T* operator->() noexcept
+ {
+ return m_ptr;
+ }
+ SCN_CONSTEXPR14 const T* operator->() const noexcept
+ {
+ return m_ptr;
+ }
+
+ private:
+ void _destruct()
+ {
+ if (m_ptr) {
+ _get().~T();
+ }
+ m_ptr = nullptr;
+ }
+ static pointer _toptr(storage_type& data)
+ {
+ return ::scn::detail::launder(
+ reinterpret_cast<T*>(reinterpret_cast<void*>(data.data())));
+ }
+ SCN_CONSTEXPR14 T& _get() noexcept
+ {
+ return *m_ptr;
+ }
+ SCN_CONSTEXPR14 const T& _get() const noexcept
+ {
+ return *m_ptr;
+ }
+
+ alignas(T) storage_type m_data{};
+ pointer m_ptr{nullptr};
+ };
+ } // namespace detail
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif
diff --git a/src/third-party/scnlib/include/scn/util/meta.h b/src/third-party/scnlib/include/scn/util/meta.h
new file mode 100644
index 0000000..83b738c
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/meta.h
@@ -0,0 +1,77 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_META_H
+#define SCN_UTIL_META_H
+
+#include "../detail/fwd.h"
+
+#include <type_traits>
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace detail {
+ template <typename... Ts>
+ struct make_void {
+ using type = void;
+ };
+ template <typename... Ts>
+ using void_t = typename make_void<Ts...>::type;
+
+ template <typename... T>
+ void valid_expr(T&&...);
+
+ template <typename T>
+ struct remove_cvref {
+ using type = typename std::remove_cv<
+ typename std::remove_reference<T>::type>::type;
+ };
+ template <typename T>
+ using remove_cvref_t = typename remove_cvref<T>::type;
+
+ // Stolen from range-v3
+ template <typename T>
+ struct static_const {
+ static constexpr T value{};
+ };
+ template <typename T>
+ constexpr T static_const<T>::value;
+
+ template <std::size_t I>
+ struct priority_tag : priority_tag<I - 1> {
+ };
+ template <>
+ struct priority_tag<0> {
+ };
+
+ struct dummy_type {
+ };
+
+ template <typename T>
+ struct dependent_false : std::false_type {
+ };
+
+ template <typename T>
+ using integer_type_for_char = typename std::
+ conditional<std::is_signed<T>::value, int, unsigned>::type;
+ } // namespace detail
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif
diff --git a/src/third-party/scnlib/include/scn/util/optional.h b/src/third-party/scnlib/include/scn/util/optional.h
new file mode 100644
index 0000000..9c0c808
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/optional.h
@@ -0,0 +1,105 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_OPTIONAL_H
+#define SCN_UTIL_OPTIONAL_H
+
+#include "memory.h"
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ struct nullopt_t {
+ };
+ namespace {
+ static constexpr auto& nullopt = detail::static_const<nullopt_t>::value;
+ }
+
+ /**
+ * A very lackluster optional implementation.
+ * Useful when scanning non-default-constructible types, especially with
+ * <tuple_return.h>:
+ *
+ * \code{.cpp}
+ * // implement scn::scanner for optional<mytype>
+ * optional<mytype> val;
+ * scn::scan(source, "{}", val);
+ *
+ * // with tuple_return:
+ * auto [result, val] = scn::scan_tuple<optional<mytype>>(source, "{}");
+ * \endcode
+ */
+ template <typename T>
+ class optional {
+ public:
+ using value_type = T;
+ using storage_type = detail::erased_storage<T>;
+
+ optional() = default;
+ optional(nullopt_t) : m_storage{} {}
+
+ optional(value_type val) : m_storage(SCN_MOVE(val)) {}
+ optional& operator=(value_type val)
+ {
+ m_storage = storage_type(SCN_MOVE(val));
+ return *this;
+ }
+
+ SCN_NODISCARD constexpr bool has_value() const noexcept
+ {
+ return m_storage.operator bool();
+ }
+ constexpr explicit operator bool() const noexcept
+ {
+ return has_value();
+ }
+
+ SCN_CONSTEXPR14 T& get() noexcept
+ {
+ return m_storage.get();
+ }
+ SCN_CONSTEXPR14 const T& get() const noexcept
+ {
+ return m_storage.get();
+ }
+
+ SCN_CONSTEXPR14 T& operator*() noexcept
+ {
+ return get();
+ }
+ SCN_CONSTEXPR14 const T& operator*() const noexcept
+ {
+ return get();
+ }
+
+ SCN_CONSTEXPR14 T* operator->() noexcept
+ {
+ return m_storage.operator->();
+ }
+ SCN_CONSTEXPR14 const T* operator->() const noexcept
+ {
+ return m_storage.operator->();
+ }
+
+ private:
+ storage_type m_storage;
+ };
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif
diff --git a/src/third-party/scnlib/include/scn/util/small_vector.h b/src/third-party/scnlib/include/scn/util/small_vector.h
new file mode 100644
index 0000000..93a5514
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/small_vector.h
@@ -0,0 +1,788 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_SMALL_VECTOR_H
+#define SCN_UTIL_SMALL_VECTOR_H
+
+#include "math.h"
+#include "memory.h"
+
+#include <cstdint>
+#include <cstring>
+
+SCN_GCC_PUSH
+SCN_GCC_IGNORE("-Wnoexcept")
+#include <iterator>
+SCN_GCC_POP
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace detail {
+ template <typename Iter>
+ std::reverse_iterator<Iter> make_reverse_iterator(Iter i)
+ {
+ return std::reverse_iterator<Iter>(i);
+ }
+
+ class small_vector_base {
+ static SCN_CONSTEXPR14 uint64_t _next_pow2_64(uint64_t x) noexcept
+ {
+ --x;
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+ x |= (x >> 32);
+ return x + 1;
+ }
+ static SCN_CONSTEXPR14 uint32_t _next_pow2_32(uint32_t x) noexcept
+ {
+ --x;
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+ return x + 1;
+ }
+
+ protected:
+ size_t next_pow2(size_t x)
+ {
+ SCN_MSVC_PUSH
+ SCN_MSVC_IGNORE(4127) // conditional expression is constant
+ if (sizeof(size_t) == sizeof(uint64_t)) {
+ return static_cast<size_t>(
+ _next_pow2_64(static_cast<uint64_t>(x)));
+ }
+ SCN_MSVC_POP
+ return static_cast<size_t>(
+ _next_pow2_32(static_cast<uint32_t>(x)));
+ }
+ };
+
+ SCN_CLANG_PUSH
+ SCN_CLANG_IGNORE("-Wpadded")
+
+ template <typename T, size_t N>
+ struct basic_stack_storage {
+ alignas(T) unsigned char data[N * sizeof(T)];
+
+ T* reinterpret_data()
+ {
+ return ::scn::detail::launder(reinterpret_unconstructed_data());
+ }
+ const T* reinterpret_data() const
+ {
+ return ::scn::detail::launder(reinterpret_unconstructed_data());
+ }
+
+ SCN_NODISCARD T* reinterpret_unconstructed_data()
+ {
+ return static_cast<T*>(static_cast<void*>(data));
+ }
+ SCN_NODISCARD const T* reinterpret_unconstructed_data() const
+ {
+ return static_cast<const T*>(static_cast<const void*>(data));
+ }
+
+ SCN_NODISCARD SCN_CONSTEXPR14 unsigned char*
+ get_unconstructed_data()
+ {
+ return data;
+ }
+ SCN_NODISCARD constexpr const unsigned char*
+ get_unconstructed_data() const
+ {
+ return data;
+ }
+ };
+
+ // -Wpadded
+ SCN_CLANG_POP
+
+ template <typename T>
+ constexpr T constexpr_max(T val)
+ {
+ return val;
+ }
+ template <typename T, typename... Ts>
+ constexpr T constexpr_max(T val, Ts... a)
+ {
+ return val > constexpr_max(a...) ? val : constexpr_max(a...);
+ }
+
+ template <typename T>
+ struct alignas(constexpr_max(alignof(T),
+ alignof(T*))) basic_stack_storage<T, 0> {
+ T* reinterpret_data()
+ {
+ return nullptr;
+ }
+ const T* reinterpret_data() const
+ {
+ return nullptr;
+ }
+
+ T* reinterpret_unconstructed_data()
+ {
+ return nullptr;
+ }
+ const T* reinterpret_unconstructed_data() const
+ {
+ return nullptr;
+ }
+
+ unsigned char* get_unconstructed_data()
+ {
+ return nullptr;
+ }
+ const unsigned char* get_unconstructed_data() const
+ {
+ return nullptr;
+ }
+ };
+
+ SCN_CLANG_PUSH
+ SCN_CLANG_IGNORE("-Wpadded")
+
+ /**
+ * A contiguous container, that stores its values in the stack, if
+ * `size() <= StackN`
+ */
+ template <typename T, size_t StackN>
+ class small_vector : protected small_vector_base {
+ public:
+ using value_type = T;
+ using size_type = size_t;
+ using difference_type = std::ptrdiff_t;
+ using reference = T&;
+ using const_reference = const T&;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<pointer>;
+ using const_reverse_iterator = std::reverse_iterator<const_pointer>;
+
+ struct stack_storage : basic_stack_storage<T, StackN> {
+ };
+ struct heap_storage {
+ size_type cap{0};
+ };
+
+ small_vector() noexcept
+ : m_ptr(_construct_stack_storage()
+ .reinterpret_unconstructed_data())
+ {
+ SCN_MSVC_PUSH
+ SCN_MSVC_IGNORE(4127) // conditional expression is constant
+
+ if (StackN == 0) {
+ _destruct_stack_storage();
+ _construct_heap_storage();
+ }
+
+ SCN_MSVC_POP
+
+ SCN_ENSURE(size() == 0);
+ }
+
+ explicit small_vector(size_type count, const T& value)
+ {
+ if (!can_be_small(count)) {
+ auto& heap = _construct_heap_storage();
+ auto cap = next_pow2(count);
+ auto storage_ptr = new unsigned char[count * sizeof(T)];
+ auto ptr =
+ static_cast<pointer>(static_cast<void*>(storage_ptr));
+ uninitialized_fill(ptr, ptr + count, value);
+
+ heap.cap = cap;
+ m_size = count;
+ m_ptr = ::scn::detail::launder(ptr);
+ }
+ else {
+ auto& stack = _construct_stack_storage();
+ uninitialized_fill(
+ stack.reinterpret_unconstructed_data(),
+ stack.reinterpret_unconstructed_data() + StackN, value);
+ m_size = count;
+ m_ptr = stack.reinterpret_data();
+ }
+
+ SCN_ENSURE(data());
+ SCN_ENSURE(size() == count);
+ SCN_ENSURE(capacity() >= size());
+ }
+
+ explicit small_vector(size_type count)
+ {
+ if (!can_be_small(count)) {
+ auto& heap = _construct_heap_storage();
+ auto cap = next_pow2(count);
+ auto storage_ptr = new unsigned char[count * sizeof(T)];
+ auto ptr =
+ static_cast<pointer>(static_cast<void*>(storage_ptr));
+ uninitialized_fill_value_init(ptr, ptr + count);
+ heap.cap = cap;
+ m_size = count;
+ m_ptr = ::scn::detail::launder(ptr);
+ }
+ else {
+ auto& stack = _construct_stack_storage();
+ uninitialized_fill_value_init(
+ stack.reinterpret_unconstructed_data(),
+ stack.reinterpret_unconstructed_data() + count);
+ m_size = count;
+ m_ptr = stack.reinterpret_data();
+ }
+
+ SCN_ENSURE(data());
+ SCN_ENSURE(size() == count);
+ SCN_ENSURE(capacity() >= size());
+ }
+
+ small_vector(const small_vector& other)
+ {
+ if (other.empty()) {
+ auto& stack = _construct_stack_storage();
+ m_ptr = stack.reinterpret_unconstructed_data();
+ return;
+ }
+
+ auto s = other.size();
+ if (!other.is_small()) {
+ auto& heap = _construct_heap_storage();
+ auto cap = other.capacity();
+ auto optr = other.data();
+
+ auto storage_ptr = new unsigned char[cap * sizeof(T)];
+ auto ptr =
+ static_cast<pointer>(static_cast<void*>(storage_ptr));
+ uninitialized_copy(optr, optr + s, ptr);
+
+ m_ptr = ::scn::detail::launder(ptr);
+ m_size = s;
+ heap.cap = cap;
+ }
+ else {
+ auto& stack = _construct_stack_storage();
+ auto optr = other.data();
+ uninitialized_copy(optr, optr + s,
+ stack.reinterpret_unconstructed_data());
+ m_size = s;
+ m_ptr = stack.reinterpret_data();
+ }
+
+ SCN_ENSURE(data());
+ SCN_ENSURE(other.data());
+ SCN_ENSURE(other.size() == size());
+ SCN_ENSURE(other.capacity() == capacity());
+ }
+ small_vector(small_vector&& other) noexcept
+ {
+ if (other.empty()) {
+ auto& stack = _construct_stack_storage();
+ m_ptr = stack.reinterpret_unconstructed_data();
+ return;
+ }
+
+ auto s = other.size();
+ if (!other.is_small()) {
+ auto& heap = _construct_heap_storage();
+ m_ptr = other.data();
+
+ m_size = s;
+ heap.cap = other.capacity();
+ }
+ else {
+ auto& stack = _construct_stack_storage();
+ auto optr = other.data();
+ uninitialized_move(optr, optr + s,
+ stack.reinterpret_unconstructed_data());
+
+ m_size = s;
+ other._destruct_elements();
+ }
+ other.m_ptr = nullptr;
+
+ SCN_ENSURE(data());
+ }
+
+ small_vector& operator=(const small_vector& other)
+ {
+ _destruct_elements();
+
+ if (other.empty()) {
+ return *this;
+ }
+
+ SCN_ASSERT(size() == 0, "");
+
+ // this other
+ // s s false || true
+ // s h false || false second
+ // h s true || true
+ // h h true || false
+ if (!is_small() || other.is_small()) {
+ uninitialized_copy(other.data(),
+ other.data() + other.size(), data());
+ m_ptr = ::scn::detail::launder(data());
+ m_size = other.size();
+ if (!other.is_small()) {
+ _get_heap().cap = other.capacity();
+ }
+ }
+ else {
+ _destruct_stack_storage();
+ auto& heap = _construct_heap_storage();
+
+ auto cap = next_pow2(other.size());
+ auto storage_ptr = new unsigned char[cap * sizeof(T)];
+ auto ptr =
+ static_cast<pointer>(static_cast<void*>(storage_ptr));
+ uninitialized_copy(other.data(),
+ other.data() + other.size(), ptr);
+ m_ptr = ::scn::detail::launder(ptr);
+ m_size = other.size();
+ heap.cap = cap;
+ }
+ return *this;
+ }
+
+ small_vector& operator=(small_vector&& other) noexcept
+ {
+ _destruct_elements();
+
+ if (other.empty()) {
+ return *this;
+ }
+
+ SCN_ASSERT(size() == 0, "");
+
+ if (!is_small() && !other.is_small()) {
+ if (!is_small()) {
+ if (capacity() != 0) {
+ delete[] ::scn::detail::launder(
+ static_cast<unsigned char*>(
+ static_cast<void*>(m_ptr)));
+ }
+ }
+
+ m_ptr = other.data();
+ m_size = other.size();
+ _get_heap().cap = other.capacity();
+ }
+ else if (!is_small() || other.is_small()) {
+ uninitialized_move(other.data(),
+ other.data() + other.size(), data());
+ m_size = other.size();
+ other._destruct_elements();
+ }
+ else {
+ _destruct_stack_storage();
+ auto& heap = _construct_heap_storage();
+
+ m_ptr = other.data();
+ m_size = other.size();
+ heap.cap = other.capacity();
+ }
+
+ other.m_ptr = nullptr;
+
+ return *this;
+ }
+
+ ~small_vector()
+ {
+ _destruct();
+ }
+
+ SCN_NODISCARD SCN_CONSTEXPR14 pointer data() noexcept
+ {
+ return m_ptr;
+ }
+ SCN_NODISCARD constexpr const_pointer data() const noexcept
+ {
+ return m_ptr;
+ }
+ SCN_NODISCARD constexpr size_type size() const noexcept
+ {
+ return m_size;
+ }
+ SCN_NODISCARD size_type capacity() const noexcept
+ {
+ if (SCN_LIKELY(is_small())) {
+ return StackN;
+ }
+ return _get_heap().cap;
+ }
+
+ SCN_NODISCARD constexpr bool empty() const noexcept
+ {
+ return size() == 0;
+ }
+
+ SCN_NODISCARD bool is_small() const noexcept
+ {
+ // oh so very ub
+ return m_ptr == reinterpret_cast<const_pointer>(
+ std::addressof(m_stack_storage));
+ }
+ constexpr static bool can_be_small(size_type n) noexcept
+ {
+ return n <= StackN;
+ }
+
+ SCN_CONSTEXPR14 reference operator[](size_type pos)
+ {
+ SCN_EXPECT(pos < size());
+ return *(begin() + pos);
+ }
+ SCN_CONSTEXPR14 const_reference operator[](size_type pos) const
+ {
+ SCN_EXPECT(pos < size());
+ return *(begin() + pos);
+ }
+
+ SCN_CONSTEXPR14 reference front()
+ {
+ SCN_EXPECT(!empty());
+ return *begin();
+ }
+ SCN_CONSTEXPR14 const_reference front() const
+ {
+ SCN_EXPECT(!empty());
+ return *begin();
+ }
+
+ SCN_CONSTEXPR14 reference back()
+ {
+ SCN_EXPECT(!empty());
+ return *(end() - 1);
+ }
+ SCN_CONSTEXPR14 const_reference back() const
+ {
+ SCN_EXPECT(!empty());
+ return *(end() - 1);
+ }
+
+ SCN_CONSTEXPR14 iterator begin() noexcept
+ {
+ return data();
+ }
+ constexpr const_iterator begin() const noexcept
+ {
+ return data();
+ }
+ constexpr const_iterator cbegin() const noexcept
+ {
+ return begin();
+ }
+
+ SCN_CONSTEXPR14 iterator end() noexcept
+ {
+ return begin() + size();
+ }
+ constexpr const_iterator end() const noexcept
+ {
+ return begin() + size();
+ }
+ constexpr const_iterator cend() const noexcept
+ {
+ return end();
+ }
+
+ SCN_CONSTEXPR14 reverse_iterator rbegin() noexcept
+ {
+ return make_reverse_iterator(end());
+ }
+ constexpr const_reverse_iterator rbegin() const noexcept
+ {
+ return make_reverse_iterator(end());
+ }
+ constexpr const_reverse_iterator crbegin() const noexcept
+ {
+ return rbegin();
+ }
+
+ SCN_CONSTEXPR14 reverse_iterator rend() noexcept
+ {
+ return make_reverse_iterator(begin());
+ }
+ constexpr const_reverse_iterator rend() const noexcept
+ {
+ return make_reverse_iterator(begin());
+ }
+ constexpr const_reverse_iterator crend() const noexcept
+ {
+ return rend();
+ }
+
+ SCN_NODISCARD
+ constexpr size_type max_size() const noexcept
+ {
+ return std::numeric_limits<size_type>::max();
+ }
+
+ void make_small() noexcept
+ {
+ if (is_small() || !can_be_small(size())) {
+ return;
+ }
+
+ stack_storage s;
+ uninitialized_move(begin(), end(),
+ s.reinterpret_unconstructed_data());
+ auto tmp_size = size();
+
+ _destruct();
+ auto& stack = _construct_stack_storage();
+ uninitialized_move(s.reinterpret_data(),
+ s.reinterpret_data() + tmp_size,
+ stack.reinterpret_unconstructed_data());
+ m_size = tmp_size;
+ }
+
+ void reserve(size_type new_cap)
+ {
+ if (new_cap <= capacity()) {
+ return;
+ }
+ _realloc(next_pow2(new_cap));
+ }
+
+ void shrink_to_fit()
+ {
+ if (is_small()) {
+ return;
+ }
+ if (!can_be_small(size())) {
+ _realloc(size());
+ }
+ else {
+ make_small();
+ }
+ }
+
+ void clear() noexcept
+ {
+ _destruct_elements();
+ }
+
+ iterator erase(iterator pos)
+ {
+ if (pos == end()) {
+ pos->~T();
+ m_size = size() - 1;
+ return end();
+ }
+ else {
+ for (auto it = pos; it != end(); ++it) {
+ it->~T();
+ ::new (static_cast<void*>(it)) T(std::move(*(it + 1)));
+ }
+ (end() - 1)->~T();
+ m_size = size() - 1;
+ return pos;
+ }
+ }
+
+ iterator erase(iterator b, iterator e)
+ {
+ if (begin() == end()) {
+ return b;
+ }
+ if (e == end()) {
+ auto n = static_cast<size_t>(std::distance(b, e));
+ for (auto it = b; it != e; ++it) {
+ it->~T();
+ }
+ m_size = size() - n;
+ return end();
+ }
+ SCN_ENSURE(false);
+ SCN_UNREACHABLE;
+ }
+
+ void push_back(const T& value)
+ {
+ ::new (_prepare_push_back()) T(value);
+ m_size = size() + 1;
+ }
+ void push_back(T&& value)
+ {
+ ::new (_prepare_push_back()) T(std::move(value));
+ m_size = size() + 1;
+ }
+
+ template <typename... Args>
+ reference emplace_back(Args&&... args)
+ {
+ ::new (_prepare_push_back()) T(SCN_FWD(args)...);
+ m_size = size() + 1;
+ return back();
+ }
+
+ void pop_back()
+ {
+ back().~T();
+ m_size = size() - 1;
+ }
+
+ void resize(size_type count)
+ {
+ if (count > size()) {
+ if (count > capacity()) {
+ _realloc(next_pow2(capacity()));
+ }
+ uninitialized_fill_value_init(begin() + size(),
+ begin() + count);
+ }
+ else {
+ for (auto it = begin() + count; it != end(); ++it) {
+ it->~T();
+ }
+ }
+ m_size = count;
+ }
+
+ SCN_CONSTEXPR14 void swap(small_vector& other) noexcept
+ {
+ small_vector tmp{SCN_MOVE(other)};
+ other = std::move(*this);
+ *this = std::move(tmp);
+ }
+
+ private:
+ stack_storage& _construct_stack_storage() noexcept
+ {
+ ::new (std::addressof(m_stack_storage)) stack_storage;
+ m_ptr = m_stack_storage.reinterpret_unconstructed_data();
+ return m_stack_storage;
+ }
+ heap_storage& _construct_heap_storage() noexcept
+ {
+ ::new (std::addressof(m_heap_storage)) heap_storage;
+ m_ptr = nullptr;
+ return m_heap_storage;
+ }
+
+ void _destruct_stack_storage() noexcept
+ {
+ _get_stack().~stack_storage();
+ }
+ void _destruct_heap_storage() noexcept
+ {
+ if (capacity() != 0) {
+ delete[] static_cast<unsigned char*>(
+ static_cast<void*>(m_ptr));
+ }
+ _get_heap().~heap_storage();
+ }
+
+ void _destruct_elements() noexcept
+ {
+ const auto s = size();
+ for (size_type i = 0; i != s; ++i) {
+ m_ptr[i].~T();
+ }
+ m_size = 0;
+ }
+
+ void _destruct() noexcept
+ {
+ _destruct_elements();
+ if (SCN_UNLIKELY(!is_small())) {
+ _destruct_heap_storage();
+ }
+ else {
+ _destruct_stack_storage();
+ }
+ }
+
+ void _realloc(size_type new_cap)
+ {
+ auto storage_ptr = new unsigned char[new_cap * sizeof(T)];
+ auto ptr =
+ static_cast<pointer>(static_cast<void*>(storage_ptr));
+ auto n = size();
+ uninitialized_move(begin(), end(), ptr);
+ _destruct();
+ auto& heap = [this]() -> heap_storage& {
+ if (is_small()) {
+ return _construct_heap_storage();
+ }
+ return _get_heap();
+ }();
+ m_ptr = ptr;
+ m_size = n;
+ heap.cap = new_cap;
+ }
+
+ void* _prepare_push_back()
+ {
+ if (SCN_UNLIKELY(size() == capacity())) {
+ _realloc(next_pow2(size() + 1));
+ }
+ return m_ptr + size();
+ }
+
+ stack_storage& _get_stack() noexcept
+ {
+ return m_stack_storage;
+ }
+ const stack_storage& _get_stack() const noexcept
+ {
+ return m_stack_storage;
+ }
+
+ heap_storage& _get_heap() noexcept
+ {
+ return m_heap_storage;
+ }
+ const heap_storage& _get_heap() const noexcept
+ {
+ return m_heap_storage;
+ }
+
+ pointer m_ptr{nullptr};
+ size_type m_size{0};
+ union {
+ stack_storage m_stack_storage;
+ heap_storage m_heap_storage;
+ };
+ };
+
+ template <typename T, size_t N>
+ SCN_CONSTEXPR14 void swap(
+ small_vector<T, N>& l,
+ small_vector<T, N>& r) noexcept(noexcept(l.swap(r)))
+ {
+ l.swap(r);
+ }
+
+ SCN_CLANG_POP // -Wpadded
+ } // namespace detail
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif // SCN_SMALL_VECTOR_H
diff --git a/src/third-party/scnlib/include/scn/util/span.h b/src/third-party/scnlib/include/scn/util/span.h
new file mode 100644
index 0000000..1abdd6c
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/span.h
@@ -0,0 +1,240 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_SPAN_H
+#define SCN_UTIL_SPAN_H
+
+#include "memory.h"
+
+SCN_GCC_PUSH
+SCN_GCC_IGNORE("-Wnoexcept")
+#include <iterator>
+SCN_GCC_POP
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace custom_ranges {
+ // iterator_category
+ using std::bidirectional_iterator_tag;
+ using std::forward_iterator_tag;
+ using std::input_iterator_tag;
+ using std::output_iterator_tag;
+ using std::random_access_iterator_tag;
+ struct contiguous_iterator_tag : random_access_iterator_tag {
+ };
+ } // namespace custom_ranges
+
+ /**
+ * A view over a contiguous range.
+ * Stripped-down version of `std::span`.
+ */
+ template <typename T>
+ class span {
+ public:
+ using element_type = T;
+ using value_type = typename std::remove_cv<T>::type;
+ using index_type = std::size_t;
+ using ssize_type = std::ptrdiff_t;
+ using difference_type = std::ptrdiff_t;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ constexpr span() noexcept = default;
+
+ template <typename I,
+ typename = decltype(detail::to_address(SCN_DECLVAL(I)))>
+ SCN_CONSTEXPR14 span(I begin, index_type count) noexcept
+ : m_ptr(detail::to_address(begin)),
+ m_end(detail::to_address(begin) + count)
+ {
+ }
+
+ template <typename I,
+ typename S,
+ typename = decltype(detail::to_address(SCN_DECLVAL(I)),
+ detail::to_address(SCN_DECLVAL(S)))>
+ SCN_CONSTEXPR14 span(I first, S last) noexcept
+ : m_ptr(detail::to_address(first)),
+ m_end(detail::to_address_safe(last, first, last))
+ {
+ }
+
+ template <typename U = typename std::add_const<T>::type,
+ typename E = element_type,
+ typename = typename std::enable_if<
+ std::is_same<E, value_type>::value>::type>
+ constexpr span(span<U> other) : m_ptr(other.m_ptr), m_end(other.m_end)
+ {
+ }
+
+ template <size_t N>
+ constexpr span(element_type (&arr)[N]) noexcept
+ : m_ptr(&arr), m_end(&arr + N)
+ {
+ }
+
+ SCN_CONSTEXPR14 iterator begin() noexcept
+ {
+ return m_ptr;
+ }
+ SCN_CONSTEXPR14 iterator end() noexcept
+ {
+ return m_end;
+ }
+ SCN_CONSTEXPR14 reverse_iterator rbegin() noexcept
+ {
+ return reverse_iterator{end()};
+ }
+ SCN_CONSTEXPR14 reverse_iterator rend() noexcept
+ {
+ return reverse_iterator{begin()};
+ }
+
+ constexpr const_iterator begin() const noexcept
+ {
+ return m_ptr;
+ }
+ constexpr const_iterator end() const noexcept
+ {
+ return m_end;
+ }
+ constexpr const_reverse_iterator rbegin() const noexcept
+ {
+ return reverse_iterator{end()};
+ }
+ constexpr const_reverse_iterator rend() const noexcept
+ {
+ return reverse_iterator{begin()};
+ }
+
+ constexpr const_iterator cbegin() const noexcept
+ {
+ return m_ptr;
+ }
+ constexpr const_iterator cend() const noexcept
+ {
+ return m_end;
+ }
+ constexpr const_reverse_iterator crbegin() const noexcept
+ {
+ return reverse_iterator{cend()};
+ }
+ constexpr const_reverse_iterator crend() const noexcept
+ {
+ return reverse_iterator{cbegin()};
+ }
+
+ SCN_CONSTEXPR14 reference operator[](index_type i) const noexcept
+ {
+ SCN_EXPECT(size() > i);
+ return *(m_ptr + i);
+ }
+
+ constexpr pointer data() const noexcept
+ {
+ return m_ptr;
+ }
+ SCN_NODISCARD constexpr index_type size() const noexcept
+ {
+ return static_cast<index_type>(m_end - m_ptr);
+ }
+ SCN_NODISCARD constexpr ssize_type ssize() const noexcept
+ {
+ return m_end - m_ptr;
+ }
+
+ SCN_CONSTEXPR14 span<T> first(index_type n) const
+ {
+ SCN_EXPECT(size() >= n);
+ return span<T>(data(), data() + n);
+ }
+ SCN_CONSTEXPR14 span<T> last(index_type n) const
+ {
+ SCN_EXPECT(size() >= n);
+ return span<T>(data() + size() - n, data() + size());
+ }
+ SCN_CONSTEXPR14 span<T> subspan(index_type off) const
+ {
+ SCN_EXPECT(size() >= off);
+ return span<T>(data() + off, size() - off);
+ }
+ SCN_CONSTEXPR14 span<T> subspan(index_type off,
+ difference_type count) const
+ {
+ SCN_EXPECT(size() > off + count);
+ SCN_EXPECT(count > 0);
+ return span<T>(data() + off, count);
+ }
+
+ constexpr operator span<typename std::add_const<T>::type>() const
+ {
+ return {m_ptr, m_end};
+ }
+ constexpr span<typename std::add_const<T>::type> as_const() const
+ {
+ return {m_ptr, m_end};
+ }
+
+ private:
+ pointer m_ptr{nullptr};
+ pointer m_end{nullptr};
+ };
+
+ template <typename I,
+ typename S,
+ typename Ptr = decltype(detail::to_address(SCN_DECLVAL(I))),
+ typename SPtr = decltype(detail::to_address(SCN_DECLVAL(S))),
+ typename ValueT = typename detail::remove_reference<
+ typename std::remove_pointer<Ptr>::type>::type>
+ SCN_CONSTEXPR14 auto make_span(I first, S last) noexcept -> span<ValueT>
+ {
+ return {first, last};
+ }
+ template <typename I,
+ typename Ptr = decltype(detail::to_address(SCN_DECLVAL(I))),
+ typename ValueT = typename detail::remove_reference<
+ typename std::remove_pointer<Ptr>::type>::type>
+ SCN_CONSTEXPR14 auto make_span(I first, std::size_t len) noexcept
+ -> span<ValueT>
+ {
+ return {first, len};
+ }
+
+ template <typename T>
+ SCN_CONSTEXPR14 span<typename T::value_type> make_span(
+ T& container) noexcept
+ {
+ using std::begin;
+ using std::end;
+ return span<typename T::value_type>(
+ detail::to_address(begin(container)),
+ detail::to_address_safe(end(container), begin(container),
+ end(container)));
+ }
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif // SCN_SPAN_H
diff --git a/src/third-party/scnlib/include/scn/util/string_view.h b/src/third-party/scnlib/include/scn/util/string_view.h
new file mode 100644
index 0000000..576b93e
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/string_view.h
@@ -0,0 +1,270 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_STRING_VIEW_H
+#define SCN_UTIL_STRING_VIEW_H
+
+#include "algorithm.h"
+#include "span.h"
+
+#include <cstdint>
+#include <cstring>
+#include <cwchar>
+
+#if SCN_HAS_STRING_VIEW
+#include <string_view>
+#endif
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace detail {
+ inline size_t strlen(const char* s) noexcept
+ {
+ return ::std::strlen(s);
+ }
+ inline size_t strlen(const wchar_t* s) noexcept
+ {
+ return ::std::wcslen(s);
+ }
+ inline size_t strlen(const char16_t* s) noexcept
+ {
+ SCN_EXPECT(s);
+ auto end = s;
+ for (; *end != u'\0'; ++end)
+ ;
+ return static_cast<size_t>(end - s);
+ }
+ inline size_t strlen(const char32_t* s) noexcept
+ {
+ SCN_EXPECT(s);
+ auto end = s;
+ for (; *end != U'\0'; ++end)
+ ;
+ return static_cast<size_t>(end - s);
+ }
+#if SCN_HAS_CHAR8
+ inline size_t strlen(const char8_t* s) noexcept
+ {
+ return std::strlen(reinterpret_cast<const char*>(s));
+ }
+#endif
+ } // namespace detail
+
+ /**
+ * A view over a (sub)string.
+ * Used even when std::string_view is available to avoid compatibility
+ * issues.
+ */
+ template <typename CharT>
+ class basic_string_view {
+ public:
+ using value_type = CharT;
+ using span_type = span<const value_type>;
+
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using iterator = typename span_type::const_iterator;
+ using const_iterator = iterator;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = reverse_iterator;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using span_index_type = typename span_type::index_type;
+
+ static constexpr const size_type npos = size_type(-1);
+
+ constexpr basic_string_view() noexcept = default;
+ constexpr basic_string_view(const_pointer s, size_type c)
+ : m_data(s, static_cast<span_index_type>(c))
+ {
+ }
+ constexpr basic_string_view(const_pointer s)
+ : m_data(s, static_cast<span_index_type>(detail::strlen(s)))
+ {
+ }
+ template <size_t N>
+ constexpr basic_string_view(const CharT (&s)[N]) : m_data(s, N)
+ {
+ }
+ constexpr basic_string_view(const_pointer first, const_pointer last)
+ : m_data(first, last)
+ {
+ }
+#if SCN_HAS_STRING_VIEW
+ constexpr basic_string_view(std::basic_string_view<value_type> str)
+ : m_data(str.data(), str.size())
+ {
+ }
+#endif
+
+ template <typename T = char16_t,
+ typename std::enable_if<std::is_same<T, char16_t>::value &&
+ std::is_same<CharT, wchar_t>::value &&
+ sizeof(char16_t) ==
+ sizeof(wchar_t)>::type* = nullptr>
+ constexpr basic_string_view(const T* s)
+ : basic_string_view(reinterpret_cast<const wchar_t*>(s))
+ {
+ }
+ template <typename T = char32_t,
+ typename std::enable_if<std::is_same<T, char32_t>::value &&
+ std::is_same<CharT, wchar_t>::value &&
+ sizeof(char32_t) ==
+ sizeof(wchar_t)>::type* = nullptr>
+ constexpr basic_string_view(const T* s)
+ : basic_string_view(reinterpret_cast<const wchar_t*>(s))
+ {
+ }
+#if SCN_HAS_CHAR8
+ template <typename T = char8_t,
+ typename std::enable_if<
+ std::is_same<T, char8_t>::value &&
+ std::is_same<CharT, char>::value>::type* = nullptr>
+ constexpr basic_string_view(const T* s)
+ : basic_string_view(reinterpret_cast<const char*>(s))
+ {
+ }
+#endif
+
+ constexpr const_iterator begin() const noexcept
+ {
+ return cbegin();
+ }
+ constexpr const_iterator cbegin() const noexcept
+ {
+ return m_data.cbegin();
+ }
+ constexpr const_iterator end() const noexcept
+ {
+ return cend();
+ }
+ constexpr const_iterator cend() const noexcept
+ {
+ return m_data.cend();
+ }
+
+ constexpr const_reverse_iterator rbegin() const noexcept
+ {
+ return crbegin();
+ }
+ constexpr const_reverse_iterator crbegin() const noexcept
+ {
+ return m_data.crbegin();
+ }
+ constexpr const_reverse_iterator rend() const noexcept
+ {
+ return crend();
+ }
+ constexpr const_reverse_iterator crend() const noexcept
+ {
+ return m_data.crend();
+ }
+
+ constexpr const_reference operator[](size_type pos) const
+ {
+ return m_data[static_cast<typename span_type::index_type>(pos)];
+ }
+ SCN_CONSTEXPR14 const_reference at(size_type pos) const
+ {
+ SCN_EXPECT(pos < size());
+ return m_data.at(static_cast<typename span_type::index_type>(pos));
+ }
+
+ constexpr const_reference front() const
+ {
+ return operator[](0);
+ }
+ constexpr const_reference back() const
+ {
+ return operator[](size() - 1);
+ }
+ constexpr const_pointer data() const noexcept
+ {
+ return m_data.data();
+ }
+
+ SCN_NODISCARD constexpr size_type size() const noexcept
+ {
+ return static_cast<size_type>(m_data.size());
+ }
+ SCN_NODISCARD constexpr size_type length() const noexcept
+ {
+ return size();
+ }
+ SCN_NODISCARD constexpr size_type max_size() const noexcept
+ {
+ return SIZE_MAX - 1;
+ }
+ SCN_NODISCARD constexpr bool empty() const noexcept
+ {
+ return size() == 0;
+ }
+
+ SCN_CONSTEXPR14 void remove_prefix(size_type n)
+ {
+ SCN_EXPECT(n <= size());
+ m_data = m_data.subspan(n);
+ }
+ SCN_CONSTEXPR14 void remove_suffix(size_type n)
+ {
+ SCN_EXPECT(n <= size());
+ m_data = m_data.first(size() - n);
+ }
+
+ SCN_CONSTEXPR14 void swap(basic_string_view& v) noexcept
+ {
+ using std::swap;
+ swap(m_data, v.m_data);
+ }
+
+ size_type copy(pointer dest, size_type count, size_type pos = 0) const
+ {
+ SCN_EXPECT(pos <= size());
+ auto n = detail::min(count, size() - pos);
+ /* std::copy(data() + pos, n, dest); */
+ std::memcpy(dest, begin() + pos, n * sizeof(value_type));
+ return n;
+ }
+ SCN_CONSTEXPR14 basic_string_view substr(size_type pos = 0,
+ size_type count = npos) const
+ {
+ SCN_EXPECT(pos <= size());
+ auto n = detail::min(count, size() - pos);
+ return m_data.subspan(pos, n);
+ }
+
+#if SCN_HAS_STRING_VIEW
+ operator std::basic_string_view<value_type>() const noexcept
+ {
+ return {m_data.data(), m_data.size()};
+ }
+#endif
+
+ private:
+ span_type m_data{};
+ };
+
+ using string_view = basic_string_view<char>;
+ using wstring_view = basic_string_view<wchar_t>;
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif // SCN_STRING_VIEW_H
diff --git a/src/third-party/scnlib/include/scn/util/unique_ptr.h b/src/third-party/scnlib/include/scn/util/unique_ptr.h
new file mode 100644
index 0000000..4723de8
--- /dev/null
+++ b/src/third-party/scnlib/include/scn/util/unique_ptr.h
@@ -0,0 +1,118 @@
+// Copyright 2017 Elias Kosunen
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file is a part of scnlib:
+// https://github.com/eliaskosunen/scnlib
+
+#ifndef SCN_UTIL_UNIQUE_PTR_H
+#define SCN_UTIL_UNIQUE_PTR_H
+
+#include "../detail/fwd.h"
+
+#include <type_traits>
+
+namespace scn {
+ SCN_BEGIN_NAMESPACE
+
+ namespace detail {
+ /**
+ * `std::unique_ptr` implementation with [[clang::trivial_abi]], without
+ * including `<memory>`
+ */
+ template <typename T>
+ class SCN_TRIVIAL_ABI unique_ptr {
+ public:
+ using element_type = T;
+ using pointer = T*;
+
+ constexpr unique_ptr() noexcept = default;
+ constexpr unique_ptr(std::nullptr_t) noexcept {}
+
+ constexpr explicit unique_ptr(pointer p) noexcept : m_ptr(p) {}
+
+ template <
+ typename U,
+ typename std::enable_if<
+ std::is_convertible<U*, pointer>::value>::type* = nullptr>
+ SCN_CONSTEXPR14 unique_ptr(unique_ptr<U>&& u) noexcept
+ : m_ptr(SCN_MOVE(u.get()))
+ {
+ u.reset();
+ }
+
+ unique_ptr(const unique_ptr&) = delete;
+ unique_ptr& operator=(const unique_ptr&) = delete;
+
+ SCN_CONSTEXPR14 unique_ptr(unique_ptr&& p) noexcept
+ : m_ptr(SCN_MOVE(p.m_ptr))
+ {
+ p.m_ptr = nullptr;
+ }
+ unique_ptr& operator=(unique_ptr&& p) noexcept
+ {
+ delete m_ptr;
+ m_ptr = p.m_ptr;
+ p.m_ptr = nullptr;
+ return *this;
+ }
+
+ ~unique_ptr() noexcept
+ {
+ SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE
+ delete m_ptr;
+ SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE
+ }
+
+ constexpr explicit operator bool() const noexcept
+ {
+ return get() != nullptr;
+ }
+
+ constexpr pointer get() const noexcept
+ {
+ return m_ptr;
+ }
+
+ constexpr pointer operator->() const noexcept
+ {
+ return m_ptr;
+ }
+ constexpr typename std::add_lvalue_reference<T>::type operator*()
+ const
+ {
+ return *m_ptr;
+ }
+
+ SCN_CONSTEXPR14 void reset()
+ {
+ m_ptr = nullptr;
+ }
+
+ private:
+ pointer m_ptr{nullptr};
+ };
+
+ template <typename T, typename... Args>
+ unique_ptr<T> make_unique(Args&&... a)
+ {
+ SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE
+ return unique_ptr<T>(new T(SCN_FWD(a)...));
+ SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE
+ }
+ } // namespace detail
+
+ SCN_END_NAMESPACE
+} // namespace scn
+
+#endif