diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 17:44:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 17:44:55 +0000 |
commit | 5068d34c08f951a7ea6257d305a1627b09a95817 (patch) | |
tree | 08213e2be853396a3b07ce15dbe222644dcd9a89 /src/third-party/scnlib/include/scn/util | |
parent | Initial commit. (diff) | |
download | lnav-5068d34c08f951a7ea6257d305a1627b09a95817.tar.xz lnav-5068d34c08f951a7ea6257d305a1627b09a95817.zip |
Adding upstream version 0.11.1.upstream/0.11.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/third-party/scnlib/include/scn/util')
-rw-r--r-- | src/third-party/scnlib/include/scn/util/algorithm.h | 80 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/array.h | 105 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/expected.h | 158 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/math.h | 121 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/memory.h | 404 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/meta.h | 77 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/optional.h | 105 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/small_vector.h | 788 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/span.h | 240 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/string_view.h | 270 | ||||
-rw-r--r-- | src/third-party/scnlib/include/scn/util/unique_ptr.h | 118 |
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 |