--- /dev/null
+/*
+ * Copyright 2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#ifndef UTIL_FILESYSTEM_H_
+#define UTIL_FILESYSTEM_H_
+
+#include <string>
+#include <utility>
+#include <new>
+#include <memory>
+#include <cassert>
+#include <limits>
+#include "bit_intrinsics.h"
+#include "string_view.h"
+#include "void_t.h"
+#include <type_traits>
+#include <iterator>
+#include "optional.h"
+#include "text.h"
+#include <cstdint>
+
+#error finish
+
+namespace vulkan_cpu
+{
+namespace util
+{
+namespace filesystem
+{
+namespace detail
+{
+enum class Path_traits_kind
+{
+ posix,
+ windows,
+};
+
+#ifdef _WIN32
+constexpr Path_traits_kind default_path_traits_kind = Path_traits_kind::windows;
+#else
+constexpr Path_traits_kind default_path_traits_kind = Path_traits_kind::posix;
+#endif
+
+template <Path_traits_kind Kind>
+struct Path_traits
+{
+ typedef char value_type;
+ static constexpr value_type preferred_separator = '/';
+};
+
+template <>
+struct Path_traits<Path_traits_kind::windows>
+{
+ typedef wchar_t value_type;
+ static constexpr value_type preferred_separator = L'\\';
+};
+
+enum class Path_kind
+{
+ root_name,
+ root_dir,
+ file_name,
+ multiple_parts,
+};
+
+template <typename T>
+struct Path_is_convertable_char_type
+{
+ static constexpr bool value = false;
+};
+
+template <typename T>
+struct Path_is_convertable_char_type<const T> : public Path_is_convertable_char_type<T>
+{
+};
+
+template <>
+struct Path_is_convertable_char_type<char>
+{
+ static constexpr bool value = true;
+ typedef char Char_type;
+};
+
+template <>
+struct Path_is_convertable_char_type<wchar_t>
+{
+ static constexpr bool value = true;
+ typedef wchar_t Char_type;
+};
+
+template <>
+struct Path_is_convertable_char_type<char16_t>
+{
+ static constexpr bool value = true;
+ typedef char16_t Char_type;
+};
+
+template <>
+struct Path_is_convertable_char_type<char32_t>
+{
+ static constexpr bool value = true;
+ typedef char32_t Char_type;
+};
+
+template <typename T, typename = void>
+struct Path_is_convertable_iterator_type
+{
+ static constexpr bool value = false;
+};
+
+template <typename T>
+struct Path_is_convertable_iterator_type<T,
+ typename std::enable_if<Path_is_convertable_char_type<
+ typename std::iterator_traits<T>::value_type>::value>::
+ type>
+{
+ static constexpr bool value = true;
+ typedef typename Path_is_convertable_char_type<
+ typename std::iterator_traits<T>::value_type>::Char_type Char_type;
+};
+
+struct Path_iterator_sentinel
+{
+};
+
+template <typename Iterator>
+class Path_convert_single_iterator_adaptor
+{
+private:
+ typedef std::iterator_traits<Iterator> Traits;
+ optional<Iterator> base_iterator;
+
+public:
+ typedef typename Traits::value_type value_type;
+ typedef typename Traits::pointer pointer;
+ typedef typename Traits::reference reference;
+ typedef typename Traits::difference_type difference_type;
+ typedef std::input_iterator_tag iterator_category;
+ constexpr Path_convert_single_iterator_adaptor() noexcept : base_iterator()
+ {
+ }
+ constexpr explicit Path_convert_single_iterator_adaptor(Iterator iterator)
+ : base_iterator(std::move(iterator))
+ {
+ }
+ bool operator==(const Path_convert_single_iterator_adaptor &rt) const
+ {
+ if(base_iterator)
+ {
+ assert(!rt.base_iterator);
+ return *base_iterator == value_type();
+ }
+ if(rt.base_iterator)
+ return *rt.base_iterator == value_type();
+ return true;
+ }
+ bool operator!=(const Path_convert_single_iterator_adaptor &rt) const
+ {
+ return !operator==(rt);
+ }
+ bool operator==(Path_iterator_sentinel) const
+ {
+ if(base_iterator)
+ return *base_iterator == value_type();
+ return true;
+ }
+ bool operator!=(Path_iterator_sentinel) const
+ {
+ return !operator==(Path_iterator_sentinel());
+ }
+ Path_convert_single_iterator_adaptor &operator++()
+ {
+ if(base_iterator)
+ ++(*base_iterator);
+ return *this;
+ }
+ Path_convert_single_iterator_adaptor operator++(int)
+ {
+ if(base_iterator)
+ return Path_convert_single_iterator_adaptor((*base_iterator)++);
+ return {};
+ }
+ reference operator*() const
+ {
+ return **base_iterator;
+ }
+ pointer operator->() const
+ {
+ return std::addressof(operator*());
+ }
+};
+
+template <typename Iterator, typename Sentinel>
+struct Iterator_and_sentinel
+{
+ Iterator iterator;
+ Sentinel sentinel;
+ Iterator_and_sentinel(Iterator iterator, Sentinel sentinel)
+ : iterator(std::move(iterator)), sentinel(std::move(sentinel))
+ {
+ }
+};
+
+template <typename Dest_char_type,
+ typename Iterator,
+ typename Sentinel = Iterator,
+ typename Source_char_type =
+ typename Path_is_convertable_iterator_type<Iterator>::Char_type>
+class Path_convert_iterator
+{
+private:
+ typedef decltype(text::Decode_encode_functions<Dest_char_type>::encode(
+ char32_t(), text::Convert_options())) Encode_result;
+ static_assert(std::is_same<typename Encode_result::Char_type, Dest_char_type>::value, "");
+
+public:
+ typedef Dest_char_type value_type;
+ typedef const Dest_char_type *pointer;
+ typedef const Dest_char_type &reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::input_iterator_tag iterator_category;
+
+private:
+ Encode_result encode_result;
+ std::size_t encode_result_index;
+ util::optional<Iterator_and_sentinel<Iterator, Sentinel>> iterator_and_sentinel;
+ void convert_next()
+ {
+ std::char_traits<char32_t>::int_type ch =
+ text::Decode_encode_functions<Source_char_type>::decode(iterator_and_sentinel->iterator,
+ iterator_and_sentinel->sentinel,
+ text::Convert_options());
+ if(ch == std::char_traits<char32_t>::eof())
+ *this = Path_convert_iterator();
+ else
+ {
+ encode_result = text::Decode_encode_functions<Dest_char_type>::encode(ch);
+ encode_result_index = 0;
+ }
+ }
+
+public:
+ constexpr Path_convert_iterator() noexcept : encode_result(),
+ encode_result_index(),
+ iterator_and_sentinel()
+ {
+ }
+ Path_convert_iterator(Iterator iterator, Sentinel sentinel)
+ : encode_result(),
+ encode_result_index(),
+ iterator_and_sentinel(in_place, std::move(iterator), std::move(sentinel))
+ {
+ convert_next();
+ }
+ Path_convert_iterator &operator++()
+ {
+ if(++encode_result_index >= encode_result.size())
+ convert_next();
+ return *this;
+ }
+ Path_convert_iterator operator++(int)
+ {
+ auto retval = *this;
+ operator++();
+ return retval;
+ }
+ const char32_t &operator*() const noexcept
+ {
+ return encode_result[encode_result_index];
+ }
+ const char32_t *operator->() const noexcept
+ {
+ return &encode_result[encode_result_index];
+ }
+ bool operator==(const Path_convert_iterator &rt) const noexcept
+ {
+ return iterator_and_sentinel.has_value() == rt.iterator_and_sentinel.has_value();
+ }
+ bool operator!=(const Path_convert_iterator &rt) const noexcept
+ {
+ return !operator==(rt);
+ }
+ bool operator==(Path_iterator_sentinel) const noexcept
+ {
+ return !iterator_and_sentinel;
+ }
+ bool operator!=(Path_iterator_sentinel) const noexcept
+ {
+ return !operator==(Path_iterator_sentinel());
+ }
+};
+
+template <typename Path_char_type, typename Iterator, typename = void>
+struct Path_convert_range
+{
+ static constexpr bool is_convertible = false;
+};
+
+template <typename Path_char_type, typename Iterator>
+struct Path_convert_range<Path_char_type,
+ Iterator,
+ typename std::
+ enable_if<Path_is_convertable_iterator_type<Iterator>::value>::type>
+{
+ static constexpr bool is_convertible = true;
+ template <typename Sentinel>
+ static std::basic_string<Path_char_type> to_string(Iterator iterator, Sentinel sentinel)
+ {
+ typedef Path_convert_iterator<Path_char_type, Iterator, Sentinel> Convert_iterator;
+ return std::basic_string<Path_char_type>(Convert_iterator(iterator, sentinel),
+ Convert_iterator());
+ }
+};
+
+template <typename Iterator>
+struct Path_convert_range<typename Path_is_convertable_iterator_type<Iterator>::Char_type,
+ Iterator,
+ void>
+{
+ static constexpr bool is_convertible = true;
+ typedef typename Path_is_convertable_iterator_type<Iterator>::Char_type Char_type;
+ static std::basic_string<Char_type> to_string(Iterator iterator, Iterator sentinel)
+ {
+ return std::basic_string<Char_type>(iterator, sentinel);
+ }
+ template <typename Sentinel>
+ static std::basic_string<Char_type> to_string(Iterator iterator, Sentinel sentinel)
+ {
+ std::basic_string<Char_type> retval;
+ while(iterator != sentinel)
+ retval += *iterator++;
+ return retval;
+ }
+};
+
+template <typename Path_char_type, typename Source, typename = void>
+struct Path_convert_source
+{
+ static constexpr bool is_convertible = false;
+};
+
+template <typename Path_char_type, typename Source_char_type, typename Traits, typename Allocator>
+struct Path_convert_source<Path_char_type,
+ std::basic_string<Source_char_type, Traits, Allocator>,
+ typename std::
+ enable_if<Path_convert_range<Path_char_type,
+ typename std::
+ basic_string<Source_char_type,
+ Traits,
+ Allocator>::
+ const_iterator>::
+ is_convertible>::type>
+{
+ typedef Path_convert_range<Path_char_type,
+ typename std::basic_string<Source_char_type, Traits, Allocator>::
+ const_iterator> Convert_range;
+ static constexpr bool is_convertible = true;
+ static std::basic_string<Path_char_type> to_string(
+ const std::basic_string<Source_char_type, Traits, Allocator> &source)
+ {
+ return Convert_range::to_string(source.begin(), source.end());
+ }
+};
+
+template <typename Path_char_type, typename Source_char_type, typename Traits>
+struct
+ Path_convert_source<Path_char_type,
+ basic_string_view<Source_char_type, Traits>,
+ typename std::
+ enable_if<Path_convert_range<Path_char_type,
+ typename basic_string_view<Source_char_type,
+ Traits>::
+ const_iterator>::is_convertible>::type>
+{
+ typedef Path_convert_range<Path_char_type,
+ typename basic_string_view<Source_char_type, Traits>::const_iterator>
+ Convert_range;
+ static constexpr bool is_convertible = true;
+ static std::basic_string<Path_char_type> to_string(
+ const basic_string_view<Source_char_type, Traits> &source)
+ {
+ return Convert_range::to_string(source.begin(), source.end());
+ }
+};
+
+template <typename Char_type>
+struct Path_convert_source<Char_type,
+ std::basic_string<Char_type>,
+ typename std::
+ enable_if<Path_convert_range<Char_type,
+ typename std::basic_string<Char_type>::
+ const_iterator>::is_convertible>::
+ type>
+{
+ static constexpr bool is_convertible = true;
+ static std::basic_string<Char_type> to_string(const std::basic_string<Char_type> &source)
+ {
+ return source;
+ }
+};
+
+template <typename Char_type, typename Iterator>
+struct Path_convert_source<Char_type,
+ Iterator,
+ void_t<typename Path_is_convertable_iterator_type<Iterator>::Char_type>>
+{
+ static constexpr bool is_convertible = true;
+ typedef Path_convert_range<Char_type, Path_convert_single_iterator_adaptor<Iterator>>
+ Convert_range;
+ static std::basic_string<Char_type> to_string(Iterator iterator)
+ {
+ return Convert_range::to_string(Path_convert_single_iterator_adaptor<Iterator>(iterator),
+ Path_iterator_sentinel());
+ }
+};
+
+template <typename Char_type>
+struct Path_convert_source<Char_type, const Char_type *, void>
+{
+ static constexpr bool is_convertible = true;
+ static std::basic_string<Char_type> to_string(const Char_type *source)
+ {
+ return source;
+ }
+};
+
+#error finish
+
+template <Path_traits_kind Traits_kind = default_path_traits_kind,
+ typename Char_type = typename Path_traits<Traits_kind>::value_type,
+ Char_type Preferred_separator = Path_traits<Traits_kind>::preferred_separator>
+class basic_path
+{
+public:
+ typedef Char_type value_type;
+ typedef std::basic_string<Char_type> string_type;
+ enum format
+ {
+ native_format,
+ generic_format,
+ auto_format
+ };
+ static constexpr Char_type preferred_separator = Preferred_separator;
+
+private:
+ typedef basic_string_view<Char_type> string_view_type;
+ class Parts
+ {
+ private:
+ std::size_t allocated_count;
+ std::size_t used_count;
+ basic_path *values;
+
+ private:
+ static basic_path *allocate(std::size_t count);
+ template <typename... Args>
+ static void construct(basic_path &value, Args &&... args)
+ {
+ ::new(static_cast<void *>(&value)) basic_path(std::forward<Args>(args)...);
+ }
+ static void destruct(basic_path &value) noexcept
+ {
+ value.~basic_path();
+ }
+ static void deallocate(basic_path *values, std::size_t count) noexcept;
+ void reallocate(std::size_t new_allocated_count)
+ {
+ assert(new_allocated_count >= used_count);
+ if(used_count == 0)
+ {
+ deallocate(values, allocated_count);
+ values = nullptr;
+ allocated_count = 0; // set now in case allocate throws
+ values = allocate(new_allocated_count);
+ allocated_count = new_allocated_count;
+ }
+ else
+ {
+ Parts new_parts;
+ new_parts.reserve(new_allocated_count);
+ for(std::size_t i = 0; i < used_count; i++)
+ new_parts.push_back(std::move(values[i]));
+ swap(new_parts);
+ }
+ }
+ static constexpr std::uint64_t get_expanded_count_64(std::uint64_t count) noexcept
+ {
+ constexpr std::uint64_t high_bit = 1ULL << 63;
+ if(count == 0 || count >= high_bit)
+ return count;
+ return 1ULL << (64 - clz64(count - 1));
+ }
+ static constexpr std::uint32_t get_expanded_count_32(std::uint32_t count) noexcept
+ {
+ constexpr std::uint32_t high_bit = 1UL << 31;
+ if(count == 0 || count >= high_bit)
+ return count;
+ return 1UL << (32 - clz32(count - 1));
+ }
+ static constexpr std::size_t get_expanded_count(std::size_t count) noexcept
+ {
+ constexpr bool is_size_t_uint32_t = std::is_same<std::size_t, std::uint32_t>::value,
+ is_size_t_uint64_t = std::is_same<std::size_t, std::uint64_t>::value;
+ static_assert(is_size_t_uint32_t || is_size_t_uint64_t, "");
+ if(is_size_t_uint32_t)
+ return get_expanded_count_32(static_cast<std::uint32_t>(count));
+ return static_cast<std::size_t>(get_expanded_count_64(count));
+ }
+
+ public:
+ constexpr Parts() noexcept : allocated_count(0), used_count(0), values(nullptr)
+ {
+ }
+ Parts(const Parts &rt) : Parts()
+ {
+ Parts new_parts;
+ new_parts.reserve(rt.used_count);
+ for(std::size_t i = 0; i < rt.used_count; i++)
+ push_back(rt.values[i]);
+ swap(new_parts);
+ }
+ Parts(Parts &&rt) noexcept : Parts()
+ {
+ swap(rt);
+ }
+ Parts &operator=(Parts &&rt) noexcept
+ {
+ Parts(std::move(rt)).swap(*this);
+ return *this;
+ }
+ Parts &operator=(const Parts &rt)
+ {
+ if(this == &rt)
+ return *this;
+ if(allocated_count < rt.used_count)
+ {
+ Parts(rt).swap(*this);
+ return *this;
+ }
+ while(used_count > rt.used_count)
+ pop_back();
+ for(std::size_t i = 0; i < used_count; i++)
+ values[i] = rt[i];
+ while(used_count < rt.used_count)
+ push_back(rt[used_count]);
+ return *this;
+ }
+ ~Parts() noexcept
+ {
+ while(used_count > 0)
+ destruct(values[--used_count]);
+ deallocate(values, allocated_count);
+ }
+ void swap(Parts &rt) noexcept
+ {
+ using std::swap;
+ swap(allocated_count, rt.allocated_count);
+ swap(used_count, rt.used_count);
+ swap(values, rt.values);
+ }
+ void reserve(std::size_t new_allocated_count)
+ {
+ if(new_allocated_count > allocated_count)
+ reallocate(new_allocated_count);
+ }
+ bool empty() const noexcept
+ {
+ return used_count == 0;
+ }
+ std::size_t size() const noexcept
+ {
+ return used_count;
+ }
+ std::size_t capacity() const noexcept
+ {
+ return allocated_count;
+ }
+ typedef basic_path *iterator;
+ typedef const basic_path *const_iterator;
+ iterator begin() noexcept
+ {
+ return values;
+ }
+ iterator end() noexcept
+ {
+ return values + used_count;
+ }
+ const_iterator begin() const noexcept
+ {
+ return values;
+ }
+ const_iterator end() const noexcept
+ {
+ return values + used_count;
+ }
+ const_iterator cbegin() const noexcept
+ {
+ return values;
+ }
+ const_iterator cend() const noexcept
+ {
+ return values + used_count;
+ }
+ template <typename... Args>
+ void emplace_back(Args &&... args)
+ {
+ if(used_count >= allocated_count)
+ reallocate(get_expanded_count(used_count + 1));
+ construct(values[used_count], std::forward<Args>(args)...);
+ used_count++;
+ }
+ void push_back(const basic_path &v)
+ {
+ emplace_back(v);
+ }
+ void push_back(basic_path &&v)
+ {
+ emplace_back(v);
+ }
+ void pop_back() noexcept
+ {
+ assert(used_count > 0);
+ destruct(values[--used_count]);
+ }
+ void clear() noexcept
+ {
+ while(used_count > 0)
+ pop_back();
+ }
+ basic_path &operator[](std::size_t index) noexcept
+ {
+ assert(index < used_count);
+ return values[index];
+ }
+ const basic_path &operator[](std::size_t index) const noexcept
+ {
+ assert(index < used_count);
+ return values[index];
+ }
+ };
+
+private:
+ Parts parts;
+ string_type value;
+ Path_kind kind;
+
+private:
+ static constexpr bool is_ascii_letter(Char_type v) noexcept
+ {
+ auto ch = static_cast<unsigned char>(v);
+ if(static_cast<Char_type>(ch) != v)
+ return false;
+ if(ch >= 'a' && ch <= 'z')
+ return true;
+ if(ch >= 'A' && ch <= 'Z')
+ return true;
+ return false;
+ }
+ static constexpr bool is_separator(Char_type v) noexcept
+ {
+ return v == static_cast<Char_type>('/') || v == preferred_separator;
+ }
+ template <typename Fn>
+ static void parse(string_view_type value, Fn callback, format fmt = auto_format) noexcept(
+ noexcept(callback(typename string_view_type::iterator(),
+ typename string_view_type::iterator(),
+ Path_kind())))
+ {
+ constexpr Char_type dot = '.';
+ constexpr Char_type colon = ':';
+ typedef typename std::char_traits<Char_type>::int_type Int_type;
+ constexpr Int_type eof = std::char_traits<Char_type>::eof();
+ auto char_iter = value.begin();
+ auto peek = [&]() -> Int_type
+ {
+ if(char_iter == value.end())
+ return eof;
+ return std::char_traits<Char_type>::to_int_type(*char_iter);
+ };
+ auto get = [&]() -> Int_type
+ {
+ if(char_iter == value.end())
+ return eof;
+ return std::char_traits<Char_type>::to_int_type(*char_iter++);
+ };
+ if(value.empty())
+ return;
+ if(Traits_kind == Path_traits_kind::windows && value.size() >= 2
+ && is_ascii_letter(value[0])
+ && value[1] == colon)
+ {
+ char_iter += 2;
+ callback(value.begin(), char_iter, Path_kind::root_name);
+ }
+ else if(Traits_kind == Path_traits_kind::windows && value.size() >= 2
+ && is_separator(value[0])
+ && is_separator(value[1]))
+ {
+ while(peek() != eof && is_separator(peek()))
+ get();
+ while(peek() != eof && !is_separator(peek()))
+ get();
+ callback(value.begin(), char_iter, Path_kind::root_name);
+ }
+ if(peek() != eof && is_separator(peek()))
+ {
+ auto start_iter = char_iter;
+ do
+ {
+ get();
+ } while(peek() != eof && is_separator(peek()));
+ callback(start_iter, char_iter, Path_kind::root_dir);
+ }
+ if(peek() != eof && !is_separator(peek()))
+ {
+ auto start_iter = char_iter;
+ do
+ {
+ get();
+ } while(peek() != eof && !is_separator(peek()));
+ callback(start_iter, char_iter, Path_kind::file_name);
+ }
+ while(peek() != eof)
+ {
+ do
+ {
+ get();
+ } while(peek() != eof && is_separator(peek()));
+ auto start_iter = char_iter;
+ while(peek() != eof && !is_separator(peek()))
+ get();
+ callback(start_iter, char_iter, Path_kind::file_name);
+ }
+ }
+ void parse(format fmt = auto_format)
+ {
+ auto last_part_kind = Path_kind::multiple_parts;
+ std::size_t part_count = 0;
+ parse(value,
+ [&]([[gnu::unused]] typename string_view_type::iterator part_string_begin,
+ [[gnu::unused]] typename string_view_type::iterator part_string_end,
+ Path_kind part_kind) noexcept
+ {
+ last_part_kind = part_kind;
+ part_count++;
+ },
+ fmt);
+ if(part_count == 1)
+ {
+ kind = last_part_kind;
+ parts.clear();
+ return;
+ }
+ else
+ {
+ kind = Path_kind::multiple_parts;
+ }
+ while(parts.size() > part_count)
+ parts.pop_back();
+ parts.reserve(part_count);
+ std::size_t part_index = 0;
+ parse(value,
+ [&](typename string_view_type::iterator part_string_begin,
+ typename string_view_type::iterator part_string_end,
+ Path_kind part_kind) noexcept
+ {
+ if(part_index >= parts.size())
+ parts.emplace_back();
+ parts[part_index].value.assign(part_string_begin, part_string_end);
+ parts[part_index].kind = part_kind;
+ part_index++;
+ },
+ fmt);
+ }
+ static void convert_source(string_type &output_value, const string_type &source)
+ {
+ output_value = source;
+ }
+ template <typename Char_type2, typename Traits, typename Allocator>
+ static void convert_source(string_type &output_value,
+ const std::basic_string<Char_type2, Traits, Allocator> &source)
+ {
+ convert_source(output_value, source.begin(), source.end());
+ }
+ template <typename Char_type2, typename Traits>
+ static void convert_source(string_type &output_value,
+ const basic_string_view<Char_type2, Traits> &source)
+ {
+ convert_source(output_value, source.begin(), source.end());
+ }
+ template <typename Char_type2>
+ static void convert_source(string_type &output_value, const Char_type2 *source)
+ {
+ convert_source(output_value, basic_string_view<Char_type2>(source));
+ }
+ template <
+
+ public : basic_path() noexcept : parts(),
+ value(),
+ kind(Path_kind::multiple_parts)
+ {
+ }
+ basic_path(const basic_path &) = default;
+ basic_path(basic_path &&) noexcept = default;
+ basic_path(string_type &&source, format fmt = auto_format)
+ : parts(), value(std::move(source)), kind()
+ {
+ parse(fmt);
+ }
+ template <typename Source>
+ basic_path(const Source &source, format fmt = auto_format)
+ : basic_path()
+ {
+ convert_source(value, source);
+ parse(fmt);
+ }
+ template <typename Input_iterator>
+ basic_path(Input_iterator first, Input_iterator last, format fmt = auto_format)
+ : basic_path()
+ {
+ convert_source(value, first, last);
+ parse(fmt);
+ }
+};
+
+template <Path_traits_kind Traits_kind, typename Char_type, Char_type Preferred_separator>
+constexpr Char_type basic_path<Traits_kind, Char_type, Preferred_separator>::preferred_separator;
+
+template <Path_traits_kind Traits_kind, typename Char_type, Char_type Preferred_separator>
+basic_path<Traits_kind, Char_type, Preferred_separator>
+ *basic_path<Traits_kind, Char_type, Preferred_separator>::Parts::allocate(std::size_t count)
+{
+ if(count == 0)
+ return nullptr;
+ return std::allocator<basic_path>::allocate(count);
+}
+
+template <Path_traits_kind Traits_kind, typename Char_type, Char_type Preferred_separator>
+void basic_path<Traits_kind, Char_type, Preferred_separator>::Parts::deallocate(
+ basic_path *values, std::size_t count) noexcept
+{
+ if(count != 0)
+ std::allocator<basic_path>::deallocate(values, count);
+}
+}
+}
+}
+}
+
+#endif /* UTIL_FILESYSTEM_H_ */
--- /dev/null
+/*
+ * Copyright 2012-2017 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+/* translated from
+ * https://github.com/programmerjake/hashlife-voxels/blob/5dda3bc240e1e89f43606316d1c3202221e3b06b/util/text.h
+ */
+
+#ifndef UTIL_TEXT_H_
+#define UTIL_TEXT_H_
+
+#include <type_traits>
+#include <utility>
+#include <limits>
+#include <cstdint>
+#include <string>
+#include <ostream>
+#include <cassert>
+#include "string_view.h"
+
+namespace vulkan_cpu
+{
+namespace util
+{
+namespace text
+{
+constexpr char32_t replacement_character = U'\uFFFD';
+
+template <typename Input_iterator, typename Sentinel>
+typename std::char_traits<char32_t>::int_type decode_utf8(
+ Input_iterator &iter,
+ Sentinel sentinel,
+ bool allow_surrogate_code_points = true,
+ bool allow_2_byte_null = false,
+ typename std::char_traits<char32_t>::int_type error_value =
+ replacement_character) noexcept(noexcept(++iter) && noexcept(static_cast<char>(*iter))
+ && noexcept(iter == sentinel ? 0 : 0))
+{
+ if(iter == sentinel)
+ return error_value;
+ auto byte0 = static_cast<std::uint8_t>(static_cast<char>(*iter));
+ ++iter;
+ if(byte0 < 0x80)
+ return byte0;
+ if(allow_2_byte_null && byte0 == 0xC0)
+ {
+ if(iter == sentinel)
+ return error_value;
+ auto byte1 = static_cast<std::uint8_t>(static_cast<char>(*iter));
+ ++iter;
+ if(byte1 != 0x80)
+ return error_value;
+ return 0;
+ }
+ if(byte0 > 0xF4 || byte0 < 0xC2)
+ return error_value;
+ if(iter == sentinel)
+ return error_value;
+ auto byte1 = static_cast<std::uint8_t>(static_cast<char>(*iter));
+ if(byte1 < 0x80 || byte1 >= 0xC0)
+ return error_value;
+ if(byte0 < 0xE0)
+ {
+ ++iter;
+ return (static_cast<std::uint_fast32_t>(byte0 & 0x1F) << 6) | (byte1 & 0x3F);
+ }
+ if(byte0 == 0xE0 && byte1 < 0xA0)
+ return error_value;
+ if(byte0 == 0xF0 && byte1 < 0x90)
+ return error_value;
+ if(byte0 == 0xF4 && byte1 >= 0x90)
+ return error_value;
+ if(!allow_surrogate_code_points && byte0 == 0xED && byte1 >= 0xA0)
+ return error_value;
+ if(iter == sentinel)
+ return error_value;
+ ++iter;
+ auto byte2 = static_cast<std::uint8_t>(static_cast<char>(*iter));
+ ++iter;
+ if(byte2 < 0x80 || byte2 >= 0xC0)
+ return error_value;
+ if(byte0 < 0xF0)
+ return (static_cast<std::uint_fast32_t>(byte0 & 0xF) << 12)
+ | (static_cast<std::uint_fast32_t>(byte1 & 0x3F) << 6) | (byte2 & 0x3F);
+ if(iter == sentinel)
+ return error_value;
+ auto byte3 = static_cast<std::uint8_t>(static_cast<char>(*iter));
+ ++iter;
+ if(byte3 < 0x80 || byte3 >= 0xC0)
+ return error_value;
+ return (static_cast<std::uint_fast32_t>(byte0 & 0x7) << 18)
+ | (static_cast<std::uint_fast32_t>(byte1 & 0x3F) << 12)
+ | (static_cast<std::uint_fast32_t>(byte2 & 0x3F) << 6) | (byte3 & 0x3F);
+}
+
+template <typename T, std::size_t N>
+struct Encoded_character final
+{
+ static constexpr std::size_t max_Chars = N;
+ typedef T Char_type;
+ static_assert(max_Chars != 0, "");
+ Char_type chars[max_Chars];
+ std::size_t used;
+ Char_type &front()
+ {
+ return chars[0];
+ }
+ constexpr const Char_type &front() const
+ {
+ return chars[0];
+ }
+ Char_type &back()
+ {
+ return chars[0];
+ }
+ constexpr const Char_type &back() const
+ {
+ return chars[0];
+ }
+ typedef const Char_type *const_iterator;
+ typedef Char_type *iterator;
+ constexpr const_iterator begin() const
+ {
+ return &chars[0];
+ }
+ constexpr const_iterator end() const
+ {
+ return begin() + used;
+ }
+ constexpr const_iterator cbegin() const
+ {
+ return &chars[0];
+ }
+ constexpr const_iterator cend() const
+ {
+ return begin() + used;
+ }
+ iterator begin()
+ {
+ return &chars[0];
+ }
+ iterator end()
+ {
+ return begin() + used;
+ }
+ constexpr std::size_t capacity() const
+ {
+ return max_Chars;
+ }
+ constexpr std::size_t size() const
+ {
+ return used;
+ }
+ constexpr const Char_type &operator[](std::size_t index) const
+ {
+ return (assert(index < used), chars[index]);
+ }
+ Char_type &operator[](std::size_t index)
+ {
+ assert(index < used);
+ return chars[index];
+ }
+ constexpr Encoded_character() : chars(), used(0)
+ {
+ }
+
+private:
+ static constexpr Char_type implicit_conversion_helper(Char_type ch) noexcept
+ {
+ return ch;
+ }
+
+public:
+ template <typename... Args>
+ constexpr Encoded_character(Args &&... args)
+ : chars{implicit_conversion_helper(std::forward<Args>(args))...}, used(sizeof...(args))
+ {
+ static_assert(sizeof...(args) <= max_Chars, "");
+ }
+ template <typename Char_traits, typename Allocator>
+ operator std::basic_string<Char_type, Char_traits, Allocator>() const
+ {
+ return std::basic_string<Char_type, Char_traits, Allocator>(begin(), end());
+ }
+ template <typename Char_traits, typename Allocator>
+ friend std::basic_string<Char_type, Char_traits, Allocator> operator+(
+ std::basic_string<Char_type, Char_traits, Allocator> a, const Encoded_character &b)
+ {
+ a.append(b.begin(), b.end());
+ return a;
+ }
+ template <typename Char_traits, typename Allocator>
+ friend std::basic_string<Char_type, Char_traits, Allocator> operator+(
+ const Encoded_character &a, std::basic_string<Char_type, Char_traits, Allocator> b)
+ {
+ b.insert(b.begin(), a.begin(), a.end());
+ return b;
+ }
+ template <std::size_t N2>
+ friend std::basic_string<Char_type> operator+(const Encoded_character &a,
+ const Encoded_character<Char_type, N2> &b)
+ {
+ std::basic_string<Char_type> retval;
+ retval.reserve(a.size() + b.size());
+ retval.append(a.begin(), a.end());
+ retval.append(b.begin(), b.end());
+ return retval;
+ }
+ template <typename Traits>
+ friend std::basic_ostream<Char_type, Traits> &operator<<(
+ std::basic_ostream<Char_type, Traits> &os, const Encoded_character &a)
+ {
+ os << static_cast<std::basic_string<Char_type, Traits>>(a);
+ return os;
+ }
+};
+
+Encoded_character<char, 4> encode_utf8(char32_t ch, bool use_2_byte_null = false) noexcept
+{
+ assert(ch < 0x10FFFFUL && ch >= 0);
+ if(use_2_byte_null && ch == 0)
+ return Encoded_character<char, 4>(0xC0U, 0x80U);
+ if(ch < 0x80)
+ return Encoded_character<char, 4>(ch);
+ if(ch < 0x800)
+ return Encoded_character<char, 4>(0xC0 | (ch >> 6), 0x80 | (ch & 0x3F));
+ if(ch < 0x10000UL)
+ return Encoded_character<char, 4>(
+ 0xE0 | (ch >> 12), 0x80 | ((ch >> 6) & 0x3F), 0x80 | (ch & 0x3F));
+ return Encoded_character<char, 4>(0xF0 | (ch >> 18),
+ 0x80 | ((ch >> 12) & 0x3F),
+ 0x80 | ((ch >> 6) & 0x3F),
+ 0x80 | (ch & 0x3F));
+}
+
+template <typename Input_iterator, typename Sentinel>
+typename std::char_traits<char32_t>::int_type decode_utf16(
+ Input_iterator &iter,
+ Sentinel sentinel,
+ bool allow_unpaired_surrogate_code_units = true,
+ typename std::char_traits<char32_t>::int_type error_value =
+ replacement_character) noexcept(noexcept(++iter) && noexcept(static_cast<char16_t>(*iter))
+ && noexcept(iter == sentinel ? 0 : 0))
+{
+ if(iter == sentinel)
+ return error_value;
+ auto unit0 = static_cast<std::uint16_t>(static_cast<char16_t>(*iter));
+ ++iter;
+ if(unit0 >= 0xD800U && unit0 < 0xDC00U)
+ {
+ if(iter == sentinel)
+ return allow_unpaired_surrogate_code_units ? unit0 : error_value;
+ auto unit1 = static_cast<std::uint16_t>(static_cast<char16_t>(*iter));
+ if(unit1 < 0xDC00U || unit1 >= 0xE000U)
+ return allow_unpaired_surrogate_code_units ? unit0 : error_value;
+ ++iter;
+ return 0x10000UL + ((unit0 & 0x3FF) << 10) + (unit1 & 0x3FF);
+ }
+ return unit0;
+}
+
+Encoded_character<char16_t, 2> encode_utf16(char32_t ch) noexcept
+{
+ assert(ch < 0x10FFFFUL && ch >= 0);
+ if(ch < 0x10000UL)
+ return Encoded_character<char16_t, 2>(ch);
+ return Encoded_character<char16_t, 2>(0xD800U | ((ch - 0x10000UL) >> 10),
+ 0xDC00U | ((ch - 0x10000UL) & 0x3FF));
+}
+
+template <typename Input_iterator, typename Sentinel>
+typename std::char_traits<char32_t>::int_type decode_utf32(
+ Input_iterator &iter,
+ Sentinel sentinel,
+ bool allow_Surrogate_Code_Units = true,
+ typename std::char_traits<char32_t>::int_type error_value =
+ replacement_character) noexcept(noexcept(++iter) && noexcept(static_cast<char32_t>(*iter))
+ && noexcept(iter == sentinel ? 0 : 0))
+{
+ if(iter == sentinel)
+ return error_value;
+ auto retval = static_cast<std::uint32_t>(static_cast<char32_t>(*iter));
+ ++iter;
+ if(retval > 0x10FFFFUL)
+ return error_value;
+ if(!allow_Surrogate_Code_Units && retval >= 0xD800U && retval < 0xE000U)
+ return error_value;
+ return retval;
+}
+
+Encoded_character<char32_t, 1> encode_utf32(char32_t ch) noexcept
+{
+ return Encoded_character<char32_t, 1>(ch);
+}
+
+static_assert(std::numeric_limits<wchar_t>::radix == 2, "");
+static_assert(std::numeric_limits<wchar_t>::digits
+ + static_cast<std::size_t>(std::is_signed<wchar_t>::value)
+ >= 16,
+ "");
+
+constexpr bool is_wide_character_utf16 = std::numeric_limits<wchar_t>::digits <= 16;
+
+Encoded_character<wchar_t, 2> encode_wide(char32_t ch) noexcept
+{
+ if(is_wide_character_utf16)
+ {
+ auto result = encode_utf16(ch);
+ Encoded_character<wchar_t, 2> retval;
+ retval.used = result.used;
+ for(std::size_t i = 0; i < result.size(); i++)
+ {
+ retval[i] = static_cast<wchar_t>(result[i]);
+ }
+ return retval;
+ }
+ return Encoded_character<wchar_t, 2>(static_cast<wchar_t>(ch));
+}
+
+template <typename Input_iterator, typename Sentinel>
+typename std::char_traits<char32_t>::int_type decode_wide(
+ Input_iterator &iter,
+ Sentinel sentinel,
+ bool allow_unpaired_surrogate_code_units = true,
+ typename std::char_traits<char32_t>::int_type error_value =
+ replacement_character) noexcept(noexcept(++iter) && noexcept(static_cast<wchar_t>(*iter))
+ && noexcept(iter == sentinel ? 0 : 0))
+{
+ struct Iterator_wrapper
+ {
+ Input_iterator &iter;
+ Iterator_wrapper(Input_iterator &iter) : iter(iter)
+ {
+ }
+ void operator++()
+ {
+ ++iter;
+ }
+ wchar_t operator*()
+ {
+ return static_cast<wchar_t>(*iter);
+ }
+ bool operator==(Sentinel &sentinel)
+ {
+ return iter == sentinel;
+ }
+ };
+ Iterator_wrapper iterator_wrapper(iter);
+ if(is_wide_character_utf16)
+ return decode_utf16(iterator_wrapper,
+ std::move(sentinel),
+ allow_unpaired_surrogate_code_units,
+ error_value);
+ return decode_utf32(
+ iterator_wrapper, std::move(sentinel), allow_unpaired_surrogate_code_units, error_value);
+}
+
+struct Convert_options final
+{
+ typename std::char_traits<char32_t>::int_type error_value = replacement_character;
+ bool allow_unpaired_surrogate_code_points = true;
+ bool allow_2_byte_null = false;
+ bool use_2_byte_null = false;
+ constexpr Convert_options()
+ {
+ }
+ constexpr Convert_options(typename std::char_traits<char32_t>::int_type error_value,
+ bool allow_unpaired_surrogate_code_points,
+ bool allow_2_byte_null,
+ bool use_2_byte_null)
+ : error_value(error_value),
+ allow_unpaired_surrogate_code_points(allow_unpaired_surrogate_code_points),
+ allow_2_byte_null(allow_2_byte_null),
+ use_2_byte_null(use_2_byte_null)
+ {
+ }
+ static constexpr Convert_options strict(
+ typename std::char_traits<char32_t>::int_type error_value = replacement_character)
+ {
+ return Convert_options(error_value, false, false, false);
+ }
+ static constexpr Convert_options java(
+ typename std::char_traits<char32_t>::int_type error_value = replacement_character)
+ {
+ return Convert_options(error_value, true, true, true);
+ }
+};
+
+template <typename Char_type>
+struct Decode_encode_functions
+{
+ template <typename Input_iterator, typename Sentinel>
+ typename std::char_traits<char32_t>::int_type decode(
+ Input_iterator &iter, Sentinel sentinel, const Convert_options &convert_options) = delete;
+ Encoded_character<Char_type, 1> encode(
+ char32_t ch, const Convert_options &convert_options) noexcept = delete;
+};
+
+template <>
+struct Decode_encode_functions<char>
+{
+ template <typename Input_iterator, typename Sentinel>
+ typename std::char_traits<char32_t>::int_type decode(
+ Input_iterator &iter,
+ Sentinel sentinel,
+ const Convert_options
+ &convert_options) noexcept(noexcept(decode_utf8(std::declval<Input_iterator &>(),
+ std::declval<Sentinel &&>())))
+ {
+ return decode_utf8(iter,
+ std::move(sentinel),
+ convert_options.allow_unpaired_surrogate_code_points,
+ convert_options.allow_2_byte_null,
+ convert_options.error_value);
+ }
+ Encoded_character<char, 4> encode(char32_t ch, const Convert_options &convert_options) noexcept
+ {
+ return encode_utf8(ch, convert_options.use_2_byte_null);
+ }
+};
+
+template <>
+struct Decode_encode_functions<char16_t>
+{
+ template <typename Input_iterator, typename Sentinel>
+ typename std::char_traits<char32_t>::int_type decode(
+ Input_iterator &iter,
+ Sentinel sentinel,
+ const Convert_options
+ &convert_options) noexcept(noexcept(decode_utf16(std::declval<Input_iterator &>(),
+ std::declval<Sentinel &&>())))
+ {
+ return decode_utf16(iter,
+ std::move(sentinel),
+ convert_options.allow_unpaired_surrogate_code_points,
+ convert_options.error_value);
+ }
+ Encoded_character<char16_t, 2> encode(char32_t ch,
+ const Convert_options &convert_options) noexcept
+ {
+ return encode_utf16(ch);
+ }
+};
+
+template <>
+struct Decode_encode_functions<char32_t>
+{
+ template <typename Input_iterator, typename Sentinel>
+ typename std::char_traits<char32_t>::int_type decode(
+ Input_iterator &iter,
+ Sentinel sentinel,
+ const Convert_options
+ &convert_options) noexcept(noexcept(decode_utf32(std::declval<Input_iterator &>(),
+ std::declval<Sentinel &&>())))
+ {
+ return decode_utf32(iter,
+ std::move(sentinel),
+ convert_options.allow_unpaired_surrogate_code_points,
+ convert_options.error_value);
+ }
+ Encoded_character<char32_t, 1> encode(char32_t ch,
+ const Convert_options &convert_options) noexcept
+ {
+ return encode_utf32(ch);
+ }
+};
+
+template <>
+struct Decode_encode_functions<wchar_t>
+{
+ template <typename Input_iterator, typename Sentinel>
+ typename std::char_traits<char32_t>::int_type decode(
+ Input_iterator &iter,
+ Sentinel sentinel,
+ const Convert_options
+ &convert_options) noexcept(noexcept(decode_wide(std::declval<Input_iterator &>(),
+ std::declval<Sentinel &&>())))
+ {
+ return decode_wide(iter,
+ std::move(sentinel),
+ convert_options.allow_unpaired_surrogate_code_points,
+ convert_options.error_value);
+ }
+ Encoded_character<wchar_t, 2> encode(char32_t ch,
+ const Convert_options &convert_options) noexcept
+ {
+ return encode_wide(ch);
+ }
+};
+
+namespace detail
+{
+template <typename Target, typename Source>
+struct String_cast_helper;
+
+template <typename Target_Char_type,
+ typename Target_Traits,
+ typename Target_Allocator,
+ typename Source_Char_type,
+ typename Source_Traits>
+struct String_cast_helper<std::basic_string<Target_Char_type, Target_Traits, Target_Allocator>,
+ basic_string_view<Source_Char_type, Source_Traits>>
+{
+ static std::basic_string<Target_Char_type, Target_Traits, Target_Allocator> run(
+ basic_string_view<Source_Char_type, Source_Traits> source,
+ const Convert_options &convert_options)
+ {
+ std::basic_string<Target_Char_type, Target_Traits, Target_Allocator> retval;
+ for(auto iter = source.begin(); iter != source.end();)
+ {
+ retval = std::move(retval) + Decode_encode_functions<Target_Char_type>::encode(
+ Decode_encode_functions<Source_Char_type>::decode(
+ iter, source.end(), convert_options),
+ convert_options);
+ }
+ return retval;
+ }
+};
+
+template <typename Char_type,
+ typename Target_Traits,
+ typename Target_Allocator,
+ typename Source_Traits>
+struct String_cast_helper<std::basic_string<Char_type, Target_Traits, Target_Allocator>,
+ basic_string_view<Char_type, Source_Traits>>
+{
+ static std::basic_string<Char_type, Target_Traits, Target_Allocator> run(
+ basic_string_view<Char_type, Source_Traits> source, const Convert_options &)
+ {
+ return std::basic_string<Char_type, Target_Traits, Target_Allocator>(source.begin(),
+ source.end());
+ }
+};
+}
+
+template <typename Target, typename Source_Char_type, typename Source_Traits>
+Target string_cast(basic_string_view<Source_Char_type, Source_Traits> source,
+ const Convert_options &convert_options)
+{
+ return detail::String_cast_helper<Target, basic_string_view<Source_Char_type, Source_Traits>>::
+ run(source, convert_options);
+}
+
+template <typename Target, typename Source_Char_type, typename Source_Traits>
+Target string_cast(basic_string_view<Source_Char_type, Source_Traits> source)
+{
+ return detail::String_cast_helper<Target, basic_string_view<Source_Char_type, Source_Traits>>::
+ run(source, Convert_options());
+}
+}
+}
+}
+}
+
+#endif /* UTIL_TEXT_H_ */