Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ned14/llfio.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'include/llfio/v2.0/path_view.hpp')
-rw-r--r--include/llfio/v2.0/path_view.hpp352
1 files changed, 229 insertions, 123 deletions
diff --git a/include/llfio/v2.0/path_view.hpp b/include/llfio/v2.0/path_view.hpp
index 48618e3d..f5ae2044 100644
--- a/include/llfio/v2.0/path_view.hpp
+++ b/include/llfio/v2.0/path_view.hpp
@@ -1,5 +1,5 @@
/* A view of a path to something
-(C) 2017-2020 Niall Douglas <http://www.nedproductions.biz/> (20 commits)
+(C) 2017-2021 Niall Douglas <http://www.nedproductions.biz/> (20 commits)
File Created: Jul 2017
@@ -215,7 +215,7 @@ public:
//! i.e. `is_source_chartype_acceptable`, or is `byte`
template <class Char> static constexpr bool is_source_acceptable = detail::is_source_acceptable<Char>::value;
- //! The default internal buffer size used by `c_str`.
+ //! The default internal buffer size used by `rendered_path`.
static constexpr size_t default_internal_buffer_size = 1024; // 2Kb for wchar_t, 1Kb for char
//! How to interpret separators
@@ -236,7 +236,7 @@ public:
};
//! The default deleter to use
- template <class T> using default_c_str_deleter = std::default_delete<T>;
+ template <class T> using default_rendered_path_deleter = std::default_delete<T>;
private:
static constexpr auto _npos = string_view::npos;
@@ -718,24 +718,24 @@ private:
{
return a.compare(b);
}
- // Disparate source encodings compare via c_str
+ // Disparate source encodings compare via rendered_path
template <class DestT, class Deleter, size_t _internal_buffer_size, class Char1T, class Char2T>
static int _compare(basic_string_view<Char1T> a, enum zero_termination a_zt, basic_string_view<Char2T> b, enum zero_termination b_zt,
const std::locale *loc) noexcept
{
path_view_component _a_(a.data(), a.size(), a_zt);
path_view_component _b_(b.data(), b.size(), b_zt);
- c_str<DestT, Deleter, _internal_buffer_size> _a(_a_, not_zero_terminated, loc);
- c_str<DestT, Deleter, _internal_buffer_size> _b(_b_, not_zero_terminated, loc);
- if(_a.length < _b.length)
+ rendered_path<zero_termination::not_zero_terminated, DestT, Deleter, _internal_buffer_size> _a(_a_, loc);
+ rendered_path<zero_termination::not_zero_terminated, DestT, Deleter, _internal_buffer_size> _b(_b_, loc);
+ if(_a.size() < _b.size())
{
return -1;
}
- if(_a.length > _b.length)
+ if(_a.size() > _b.size())
{
return 1;
}
- return _do_compare(_a.buffer, _b.buffer, _a.length);
+ return _do_compare(_a.data(), _b.data(), _a.size());
}
public:
@@ -772,17 +772,17 @@ public:
If the source encodings of the two path views are compatible, a
lexicographical comparison is performed. If they are incompatible,
either or both views are converted to the destination encoding
- using `c_str<T, Delete, _internal_buffer_size>`, and then a
+ using `rendered_path<T, Delete, _internal_buffer_size>`, and then a
lexicographical comparison is performed.
This can, for obvious reasons, be expensive. It can also throw
- exceptions, as `c_str` does.
+ exceptions, as `rendered_path` does.
If the destination encoding is `byte`, `memcmp()` is used,
- and `c_str` is never invoked as the two sources are byte
+ and `rendered_path` is never invoked as the two sources are byte
compared directly.
*/
- LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class Deleter = default_c_str_deleter<T[]>,
+ LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class Deleter = default_rendered_path_deleter<T[]>,
size_t _internal_buffer_size = default_internal_buffer_size)
LLFIO_TREQUIRES(LLFIO_TPRED(is_source_acceptable<T>))
constexpr int compare(path_view_component p, const std::locale &loc) const
@@ -793,7 +793,7 @@ public:
});
}
//! \overload
- LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class Deleter = default_c_str_deleter<T[]>,
+ LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class Deleter = default_rendered_path_deleter<T[]>,
size_t _internal_buffer_size = default_internal_buffer_size)
LLFIO_TREQUIRES(LLFIO_TPRED(is_source_acceptable<T>))
constexpr int compare(path_view_component p) const
@@ -804,6 +804,118 @@ public:
});
}
+private:
+ template <class T> struct _rendered_path_base_
+ {
+ protected:
+ using _view_type = span<const T>;
+ _view_type _ref;
+
+ constexpr basic_string_view<T> _as_string_view() const { return {_ref.data(), _ref.size()}; }
+
+ public:
+ //! Type of the value type
+ using value_type = T;
+ //! Type of the pointer type
+ using pointer = const T *;
+ //! Type of the const pointer type
+ using const_pointer = const T *;
+ //! Type of the reference type
+ using reference = const T &;
+ //! Type of the const reference type
+ using const_reference = const T &;
+ //! Type of the iterator type
+ using iterator = typename _view_type::iterator;
+ //! Type of the const iterator type
+ using const_iterator = typename _view_type::const_iterator;
+ //! Type of the reverse iterator type
+ using reverse_iterator = typename _view_type::reverse_iterator;
+ //! Type of the const reverse iterator type
+ using const_reverse_iterator = typename _view_type::const_reverse_iterator;
+ //! Type of the size type
+ using size_type = typename _view_type::size_type;
+ //! Type of the difference type
+ using difference_type = typename _view_type::difference_type;
+
+ _rendered_path_base_() = default;
+ _rendered_path_base_(const _rendered_path_base_ &) = default;
+ _rendered_path_base_ &operator=(const _rendered_path_base_ &) = default;
+ ~_rendered_path_base_() = default;
+
+ //! Begin iteration
+ constexpr iterator begin() { return _ref.begin(); }
+ //! Begin iteration
+ constexpr const_iterator begin() const { return _ref.begin(); }
+ //! Begin iteration
+ constexpr const_iterator cbegin() const { return _ref.cbegin(); }
+ //! End iteration
+ constexpr iterator end() { return _ref.end(); }
+ //! End iteration
+ constexpr const_iterator end() const { return _ref.end(); }
+ //! End iteration
+ constexpr const_iterator cend() const { return _ref.cend(); }
+ //! Begin reverse iteration
+ constexpr reverse_iterator rbegin() { return _ref.rbegin(); }
+ //! Begin reverse iteration
+ constexpr const_reverse_iterator rbegin() const { return _ref.rbegin(); }
+ //! Begin reverse iteration
+ constexpr const_reverse_iterator crbegin() const { return _ref.crbegin(); }
+ //! End reverse iteration
+ constexpr reverse_iterator rend() { return _ref.rend(); }
+ //! End reverse iteration
+ constexpr const_reverse_iterator rend() const { return _ref.rend(); }
+ //! End reverse iteration
+ constexpr const_reverse_iterator crend() const { return _ref.crend(); }
+
+ //! Access
+ constexpr reference operator[](size_type idx) { return _ref[idx]; }
+ //! Access
+ constexpr const_reference operator[](size_type idx) const { return _ref[idx]; }
+ //! Access
+ constexpr reference at(size_type idx) { return _ref.at(idx); }
+ //! Access
+ constexpr const_reference at(size_type idx) const { return _ref.at(idx); }
+ //! Access
+ constexpr reference front() { return _ref.front(); }
+ //! Access
+ constexpr const_reference front() const { return _ref.front(); }
+ //! Access
+ constexpr reference back() { return _ref.back(); }
+ //! Access
+ constexpr const_reference back() const { return _ref.back(); }
+ //! Access
+ constexpr pointer data() { return _ref.data(); }
+ //! Access
+ constexpr const_pointer data() const { return _ref.data(); }
+ //! Size
+ constexpr size_type size() const { return _ref.size(); }
+ //! Size
+ constexpr size_type length() const { return _ref.length(); }
+ //! Max size
+ constexpr size_type max_size() const { return _ref.max_size(); }
+ //! Empty
+ QUICKCPPLIB_NODISCARD constexpr bool empty() const { return _ref.empty(); }
+ //! As span
+ constexpr _view_type as_span() const { return _ref; }
+ };
+ template <enum path_view_component::zero_termination ZeroTermination, class T, bool = false> struct _rendered_path_base : public _rendered_path_base_<T>
+ {
+ //! As string view
+ constexpr basic_string_view<T> as_string_view() const { return {this->_ref.data(), this->_ref.size()}; }
+ };
+ template <class T> struct _rendered_path_base<zero_terminated, T> : public _rendered_path_base_<T>
+ {
+ //! Return a zero-terminated character array suitable for use as a C string
+ constexpr const T *c_str() const noexcept { return this->_ref.data(); }
+ };
+ template <bool _> struct _rendered_path_base<zero_terminated, byte, _> : public _rendered_path_base_<byte>
+ {
+ };
+ template <bool _> struct _rendered_path_base<not_zero_terminated, byte, _> : public _rendered_path_base_<byte>
+ {
+ };
+
+public:
/*! Instantiate from a `path_view_component` to get a path suitable for feeding to other code.
\tparam T The destination encoding required.
\tparam Deleter A custom deleter OR STL allocator for any temporary buffer.
@@ -820,34 +932,28 @@ public:
and the source is not zero terminated, a straight memory copy is performed
into the temporary buffer.
- `c_str` contains a temporary buffer sized according to the template parameter. Output
+ `rendered_path` contains a temporary buffer sized according to the template parameter. Output
below that amount involves no dynamic memory allocation. Output above that amount calls
`operator new[]`. You can use an externally supplied larger temporary buffer to avoid
dynamic memory allocation in all situations.
*/
- LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class AllocatorOrDeleter = default_c_str_deleter<T[]>,
- size_t _internal_buffer_size = default_internal_buffer_size)
+ LLFIO_TEMPLATE(enum path_view_component::zero_termination ZeroTermination, class T = typename filesystem::path::value_type,
+ class AllocatorOrDeleter = default_rendered_path_deleter<T[]>, size_t _internal_buffer_size = default_internal_buffer_size)
LLFIO_TREQUIRES(LLFIO_TPRED(is_source_acceptable<T>))
- struct c_str
+ class rendered_path : public _rendered_path_base<ZeroTermination, T>
{
- static_assert(is_source_acceptable<T>, "path_view_component::c_str<T> does not have a T which is one of byte, char, wchar_t, char8_t nor char16_t");
+ using _base = _rendered_path_base<ZeroTermination, T>;
+ static_assert(is_source_acceptable<T>, "path_view_component::rendered_path<T> does not have a T which is one of byte, char, wchar_t, char8_t nor char16_t");
template <class DestT, class _Deleter, size_t _internal_buffer_size_, class Char1T, class Char2T>
friend int path_view_component::_compare(basic_string_view<Char1T> a, enum zero_termination a_zt, basic_string_view<Char2T> b, enum zero_termination b_zt,
const std::locale *loc) noexcept;
- //! Type of the value type
- using value_type = T;
+ public:
+ using value_type = typename _base::value_type;
//! Type of the allocator, or `void` if that was not configured
using allocator_type = decltype(detail::is_allocator(std::declval<AllocatorOrDeleter>()));
//! Type of the deleter, or `void` if that was not configured
using deleter_type = decltype(detail::is_deleter<value_type>(std::declval<AllocatorOrDeleter>()));
- //! The size of the internal temporary buffer
- static constexpr size_t internal_buffer_size = (_internal_buffer_size == 0) ? 1 : _internal_buffer_size;
-
- //! Pointer to the possibly-converted path
- const value_type *buffer{nullptr};
- //! Number of characters, excluding zero terminating char, at buffer
- size_t length{0};
private:
template <class X = void> static constexpr bool _is_deleter_based = std::is_void<allocator_type>::value;
@@ -856,22 +962,21 @@ public:
LLFIO_TEMPLATE(class U, class source_type)
LLFIO_TREQUIRES(LLFIO_TPRED(!std::is_same<source_type, value_type>::value))
- void _make_passthrough(path_view_component /*unused*/, enum zero_termination /*unused*/, U & /*unused*/, const source_type * /*unused*/)
+ void _make_passthrough(path_view_component /*unused*/, U & /*unused*/, const source_type * /*unused*/)
{
LLFIO_LOG_FATAL(nullptr, "Passthrough to non-identity type ought to never be called!");
abort();
}
- template <class U> void _make_passthrough(path_view_component view, enum zero_termination output_zero_termination, U &allocate, const value_type *source)
+ template <class U> void _make_passthrough(path_view_component view, U &allocate, const value_type *source)
{
using LLFIO_V2_NAMESPACE::basic_string_view;
// If the consuming API is a NT kernel API, and we have / in the path, we shall need to do slash conversion
const bool needs_slash_translation = (filesystem::path::preferred_separator != '/') &&
(view.formatting() == format::auto_format || view.formatting() == format::generic_format) &&
view._invoke([](auto sv) { return sv.find('/') != _npos; });
- length = view._length;
- if(!needs_slash_translation && (output_zero_termination == not_zero_terminated || view._zero_terminated))
+ if(!needs_slash_translation && (this->zero_termination() == not_zero_terminated || view._zero_terminated))
{
- buffer = source;
+ _base::_ref = typename _base::_view_type(source, view._length);
}
else
{
@@ -891,30 +996,26 @@ public:
// Use the internal buffer
memcpy(_buffer, source, required_bytes);
_buffer[required_length] = 0;
- buffer = _buffer;
+ _base::_ref = typename _base::_view_type(_buffer, view._length);
}
else
{
auto *buffer_ = allocate(required_length);
- if(nullptr == buffer_)
- {
- length = 0;
- }
- else
+ if(nullptr != buffer_)
{
_bytes_to_delete = required_bytes;
memcpy(buffer_, source, required_bytes);
buffer_[required_length] = 0;
- buffer = buffer_;
+ _base::_ref = typename _base::_view_type(_buffer, view._length);
}
}
if(needs_slash_translation)
{
- basic_string_view<value_type> sv(buffer, required_length);
+ auto sv = _base::_as_string_view();
auto idx = sv.find('/');
while(idx != _npos)
{
- const_cast<value_type *>(buffer)[idx] = filesystem::path::preferred_separator;
+ const_cast<value_type *>(sv.data())[idx] = filesystem::path::preferred_separator;
idx = sv.find('/', idx);
}
}
@@ -922,59 +1023,57 @@ public:
}
public:
- constexpr c_str() {}
+ constexpr rendered_path() {}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant
#endif
private:
- template <class U> void _init(path_view_component view, enum zero_termination output_zero_termination, const std::locale *loc, U &&allocate)
+ template <class U> void _init(path_view_component view, const std::locale *loc, U &&allocate)
{
if(0 == view._length)
{
_buffer[0] = 0;
- buffer = _buffer;
- length = 0;
+ _base::_ref = typename _base::_view_type(_buffer, size_t(0));
return;
}
if(std::is_same<T, byte>::value || view._passthrough)
{
- length = view._length;
- buffer = (const value_type *) view._bytestr;
+ _base::_ref = typename _base::_view_type((value_type *) view._bytestr, view._length);
return;
}
if(std::is_same<T, char>::value && view._char)
{
- _make_passthrough(view, output_zero_termination, allocate, view._charstr);
+ _make_passthrough(view, allocate, view._charstr);
return;
}
if(std::is_same<T, wchar_t>::value && view._wchar)
{
- _make_passthrough(view, output_zero_termination, allocate, view._wcharstr);
+ _make_passthrough(view, allocate, view._wcharstr);
return;
}
if(std::is_same<T, char8_t>::value && view._utf8)
{
- _make_passthrough(view, output_zero_termination, allocate, view._char8str);
+ _make_passthrough(view, allocate, view._char8str);
return;
}
if(std::is_same<T, char16_t>::value && view._utf16)
{
- _make_passthrough(view, output_zero_termination, allocate, view._char16str);
+ _make_passthrough(view, allocate, view._char16str);
return;
}
#ifdef _WIN32
// On Windows, consider char16_t input equivalent to wchar_t
if(std::is_same<T, wchar_t>::value && view._utf16)
{
- _make_passthrough(view, output_zero_termination, allocate, view._wcharstr);
+ _make_passthrough(view, allocate, view._wcharstr);
return;
}
#else
// On POSIX, consider char8_t input equivalent to char
if(std::is_same<T, char>::value && view._utf8)
{
- _make_passthrough(view, output_zero_termination, allocate, view._charstr);
+ _make_passthrough(view, allocate, view._charstr);
return;
}
#endif
@@ -1010,15 +1109,13 @@ public:
if(0 == required_length)
{
// The internal buffer was sufficient.
- buffer = _buffer;
- length = end - _buffer;
+ _base::_ref = typename _base::_view_type(_buffer, end - _buffer);
return;
}
// The internal buffer is too small. Fall back to dynamic allocation. This may throw.
auto *allocated_buffer = allocate(required_length);
if(nullptr == allocated_buffer)
{
- length = 0;
return;
}
_bytes_to_delete = required_length * sizeof(value_type);
@@ -1027,31 +1124,30 @@ public:
end = allocated_buffer + (end - _buffer);
if(view._passthrough)
{
- end = detail::reencode_path_to(length, end, required_length, view._bytestr, view._length, loc);
+ end = detail::reencode_path_to(view._length, end, required_length, view._bytestr, view._length, loc);
}
else if(view._char)
{
- end = detail::reencode_path_to(length, end, required_length, view._charstr, view._length, loc);
+ end = detail::reencode_path_to(view._length, end, required_length, view._charstr, view._length, loc);
}
else if(view._wchar)
{
- end = detail::reencode_path_to(length, end, required_length, view._wcharstr, view._length, loc);
+ end = detail::reencode_path_to(view._length, end, required_length, view._wcharstr, view._length, loc);
}
else if(view._utf8)
{
- end = detail::reencode_path_to(length, end, required_length, view._char8str, view._length, loc);
+ end = detail::reencode_path_to(view._length, end, required_length, view._char8str, view._length, loc);
}
else if(view._utf16)
{
- end = detail::reencode_path_to(length, end, required_length, view._char16str, view._length, loc);
+ end = detail::reencode_path_to(view._length, end, required_length, view._char16str, view._length, loc);
}
else
{
LLFIO_LOG_FATAL(nullptr, "path_view_component::cstr somehow sees no state!");
abort();
}
- buffer = allocated_buffer;
- length = end - buffer;
+ _base::_ref = typename _base::_view_type(allocated_buffer, end - allocated_buffer);
}
#ifdef _MSC_VER
#pragma warning(pop)
@@ -1121,11 +1217,11 @@ public:
}
// used by compare()
- c_str(path_view_component view, enum zero_termination output_zero_termination, const std::locale *loc)
+ rendered_path(path_view_component view, const std::locale *loc)
: _deleter1(_default_deleter)
, _deleter1arg(&_deleter2)
{
- _init(view, output_zero_termination, loc, _default_allocate<AllocatorOrDeleter>(&_deleter2));
+ _init(view, loc, _default_allocate<AllocatorOrDeleter>(&_deleter2));
}
public:
@@ -1135,7 +1231,7 @@ public:
\param loc The locale to use to perform reencoding.
\param allocate Either a callable with prototype `value_type *(size_t length)` which
is defaulted to `return static_cast<value_type *>(::operator new[](length * sizeof(value_type)));`,
- or a `pmr::memory_resource *`. You can return `nullptr` if you wish, the consumer of `c_str` will
+ or a `pmr::memory_resource *`. You can return `nullptr` if you wish, the consumer of `rendered_path` will
see a `buffer` set to `nullptr`.
If `loc` is defaulted, and an error occurs during any conversion from UTF-8 or UTF-16, an exception of
@@ -1146,91 +1242,87 @@ public:
*/
LLFIO_TEMPLATE(class U, class V)
LLFIO_TREQUIRES(LLFIO_TPRED(_is_deleter_based<U>), LLFIO_TEXPR(std::declval<U>()((size_t) 1)), LLFIO_TEXPR(std::declval<V>()((value_type *) nullptr)))
- c_str(path_view_component view, enum zero_termination output_zero_termination, const std::locale &loc, U &&allocate, V &&deleter = AllocatorOrDeleter(),
- _custom_callable_deleter_tag = {})
+ rendered_path(path_view_component view, const std::locale &loc, U &&allocate, V &&deleter = AllocatorOrDeleter(), _custom_callable_deleter_tag = {})
: _deleter1(_invoke_deleter)
, _deleter1arg(&_deleter2)
, _deleter2(static_cast<V &&>(deleter))
{
- _init(view, output_zero_termination, loc, static_cast<U &&>(allocate));
+ _init(view, loc, static_cast<U &&>(allocate));
}
//! \overload
LLFIO_TEMPLATE(class U, class V)
LLFIO_TREQUIRES(LLFIO_TPRED(_is_deleter_based<U>), LLFIO_TEXPR(std::declval<U>()((size_t) 1)), LLFIO_TEXPR(std::declval<V>()((value_type *) nullptr)))
- c_str(path_view_component view, enum zero_termination output_zero_termination, U &&allocate, V &&deleter = AllocatorOrDeleter(),
- _custom_callable_deleter_tag = {})
+ rendered_path(path_view_component view, U &&allocate, V &&deleter = AllocatorOrDeleter(), _custom_callable_deleter_tag = {})
: _deleter1(_invoke_deleter)
, _deleter1arg(&_deleter2)
, _deleter2(static_cast<V &&>(deleter))
{
- _init(view, output_zero_termination, (const std::locale *) nullptr, static_cast<U &&>(allocate));
+ _init(view, (const std::locale *) nullptr, static_cast<U &&>(allocate));
}
//! \overload memory_resource
- c_str(path_view_component view, enum zero_termination output_zero_termination, const std::locale &loc, pmr::memory_resource &mr, _memory_resource_tag = {})
+ rendered_path(path_view_component view, const std::locale &loc, pmr::memory_resource &mr, _memory_resource_tag = {})
: _deleter1(_memory_resouce_deallocate)
, _deleter1arg(&mr)
{
- _init(view, output_zero_termination, &loc, _memory_resource_allocate{&mr});
+ _init(view, &loc, _memory_resource_allocate{&mr});
}
//! \overload memory_resource
- c_str(path_view_component view, enum zero_termination output_zero_termination, pmr::memory_resource &mr, _memory_resource_tag = {})
+ rendered_path(path_view_component view, pmr::memory_resource &mr, _memory_resource_tag = {})
: _deleter1(_memory_resouce_deallocate)
, _deleter1arg(&mr)
{
- _init(view, output_zero_termination, (const std::locale *) nullptr, _memory_resource_allocate{&mr});
+ _init(view, (const std::locale *) nullptr, _memory_resource_allocate{&mr});
}
//! \overload STL allocator
LLFIO_TEMPLATE(class U)
LLFIO_TREQUIRES(LLFIO_TPRED(_is_allocator_based<U>), LLFIO_TEXPR(std::declval<U>().allocate((size_t) 1)))
- c_str(path_view_component view, enum zero_termination output_zero_termination, const std::locale &loc, U &&allocate, _stl_allocator_tag = {})
+ rendered_path(path_view_component view, const std::locale &loc, U &&allocate, _stl_allocator_tag = {})
: _deleter1(_stl_allocator_deallocate<allocator_type>)
, _deleter1arg(&_deleter2)
, _deleter2(static_cast<U &&>(allocate))
{
- _init(view, output_zero_termination, &loc, _stl_allocator_allocate<std::decay_t<U>>(static_cast<std::decay_t<U> *>(&_deleter2)));
+ _init(view, &loc, _stl_allocator_allocate<std::decay_t<U>>(static_cast<std::decay_t<U> *>(&_deleter2)));
}
//! \overload STL allocator
LLFIO_TEMPLATE(class U)
LLFIO_TREQUIRES(LLFIO_TPRED(_is_allocator_based<U>), LLFIO_TEXPR(std::declval<U>().allocate((size_t) 1)))
- c_str(path_view_component view, enum zero_termination output_zero_termination, U &&allocate, _stl_allocator_tag = {})
+ rendered_path(path_view_component view, U &&allocate, _stl_allocator_tag = {})
: _deleter1(_stl_allocator_deallocate<allocator_type>)
, _deleter1arg(&_deleter2)
, _deleter2(static_cast<U &&>(allocate))
{
- _init(view, output_zero_termination, (const std::locale *) nullptr, _stl_allocator_allocate<std::decay_t<U>>(static_cast<std::decay_t<U> *>(&_deleter2)));
+ _init(view, (const std::locale *) nullptr, _stl_allocator_allocate<std::decay_t<U>>(static_cast<std::decay_t<U> *>(&_deleter2)));
}
//! \overload default allocation
- c_str(path_view_component view, enum zero_termination output_zero_termination, const std::locale &loc)
+ rendered_path(path_view_component view, const std::locale &loc)
: _deleter1(_default_deleter)
, _deleter1arg(&_deleter2)
{
- _init(view, output_zero_termination, &loc, _default_allocate<AllocatorOrDeleter>(&_deleter2));
+ _init(view, &loc, _default_allocate<AllocatorOrDeleter>(&_deleter2));
}
//! \overload
- c_str(path_view_component view, enum zero_termination output_zero_termination)
+ explicit rendered_path(path_view_component view)
: _deleter1(_default_deleter)
, _deleter1arg(&_deleter2)
{
- _init(view, output_zero_termination, nullptr, _default_allocate<AllocatorOrDeleter>(&_deleter2));
+ _init(view, nullptr, _default_allocate<AllocatorOrDeleter>(&_deleter2));
}
- //! Construct from a compatible `c_str`.
+ //! Construct from a compatible `rendered_path`.
LLFIO_TEMPLATE(class AllocatorOrDeleter2, size_t _internal_buffer_size2)
- LLFIO_TREQUIRES(LLFIO_TPRED(!std::is_same<c_str, c_str<T, AllocatorOrDeleter2, _internal_buffer_size2>>::value),
+ LLFIO_TREQUIRES(LLFIO_TPRED(!std::is_same<rendered_path, rendered_path<ZeroTermination, T, AllocatorOrDeleter2, _internal_buffer_size2>>::value),
LLFIO_TPRED(std::is_constructible<AllocatorOrDeleter, AllocatorOrDeleter2>::value))
- explicit c_str(c_str<T, AllocatorOrDeleter2, _internal_buffer_size2> &&o) noexcept
- : buffer(o.buffer)
- , length(o.length)
+ explicit rendered_path(rendered_path<ZeroTermination, T, AllocatorOrDeleter2, _internal_buffer_size2> &&o) noexcept
+ : _base(o)
, _bytes_to_delete(o._bytes_to_delete)
, _deleter1(o._deleter1)
, _deleter1arg(o._deleter1arg)
, _deleter2(std::move(o._deleter2))
{
}
- ~c_str() { reset(); }
- c_str(const c_str &) = delete;
- c_str(c_str &&o) noexcept
- : buffer(o.buffer)
- , length(o.length)
+ ~rendered_path() { reset(); }
+ rendered_path(const rendered_path &) = delete;
+ rendered_path(rendered_path &&o) noexcept
+ : _base(o)
, _bytes_to_delete(o._bytes_to_delete)
, _deleter1(o._deleter1)
, _deleter1arg(o._deleter1arg)
@@ -1238,30 +1330,30 @@ public:
{
if(this != &o)
{
- if(o.buffer == o._buffer)
+ if(o.data() == o._buffer)
{
- memcpy(_buffer, o._buffer, (o.length + 1) * sizeof(value_type));
- buffer = _buffer;
+ memcpy(_buffer, o._buffer, (o.size() + 1) * sizeof(value_type));
+ _base::_ref = typename _base::_view_type(_buffer, _base::_ref.size());
}
if(o._deleter1arg == &o._deleter2)
{
_deleter1arg = &_deleter2;
}
- o.buffer = nullptr;
+ o._ref = {};
o._bytes_to_delete = 0;
o._deleter1 = nullptr;
o._deleter1arg = nullptr;
}
}
- c_str &operator=(const c_str &) = delete;
- c_str &operator=(c_str &&o) noexcept
+ rendered_path &operator=(const rendered_path &) = delete;
+ rendered_path &operator=(rendered_path &&o) noexcept
{
if(this == &o)
{
return *this;
}
- this->~c_str();
- new(this) c_str(std::move(o));
+ this->~rendered_path();
+ new(this) rendered_path(std::move(o));
return *this;
}
@@ -1270,9 +1362,8 @@ public:
{
if(_bytes_to_delete > 0)
{
- _deleter1(_deleter1arg, const_cast<value_type *>(buffer), _bytes_to_delete);
- buffer = nullptr;
- length = 0;
+ _deleter1(_deleter1arg, const_cast<value_type *>(_base::_ref.data()), _bytes_to_delete);
+ _base::_ref = typename _base::_view_type{};
_bytes_to_delete = 0;
}
}
@@ -1281,15 +1372,21 @@ public:
{
if(_bytes_to_delete > 0)
{
- auto *ret = buffer;
- buffer = nullptr;
- length = 0;
+ auto *ret = _base::_ref.data();
+ _base::_ref = typename _base::_view_type{};
_bytes_to_delete = 0;
return ret;
}
return nullptr;
}
+ //! The zero termination of this rendered path
+ static constexpr enum zero_termination zero_termination() noexcept { return ZeroTermination; }
+ //! The size of the internal buffer
+ static constexpr size_t internal_buffer_size() noexcept { return (_internal_buffer_size > 0) ? _internal_buffer_size : 1; }
+ //! The storage capacity, which may be larger than `size()` if the internal buffer is in use
+ size_t capacity() noexcept { return (this->data() == _buffer) ? internal_buffer_size() : this->size(); }
+
//! Access the custom deleter instance passed to the constructor
const AllocatorOrDeleter &deleter() const noexcept { return _deleter2; }
//! Access the custom deleter instance passed to the constructor
@@ -1310,17 +1407,26 @@ public:
AllocatorOrDeleter _deleter2;
// MAKE SURE this is the final item in storage, the compiler will elide the storage
// under optimisation if it can prove it is never used.
- value_type _buffer[internal_buffer_size]{};
+ value_type _buffer[internal_buffer_size()]{};
};
+ //! Convenience type alias
+ template <class T = typename filesystem::path::value_type, class AllocatorOrDeleter = default_rendered_path_deleter<T[]>,
+ size_t _internal_buffer_size = default_internal_buffer_size>
+ using zero_terminated_rendered_path = rendered_path<zero_termination::zero_terminated, T, AllocatorOrDeleter, _internal_buffer_size>;
+ //! Convenience type alias
+ template <class T = typename filesystem::path::value_type, class AllocatorOrDeleter = default_rendered_path_deleter<T[]>,
+ size_t _internal_buffer_size = default_internal_buffer_size>
+ using not_zero_terminated_rendered_path = rendered_path<zero_termination::not_zero_terminated, T, AllocatorOrDeleter, _internal_buffer_size>;
#ifdef __cpp_concepts
- template <class T, class Deleter, size_t _internal_buffer_size>
+ template <enum path_view_component::zero_termination ZeroTermination, class T, class Deleter, size_t _internal_buffer_size>
requires(is_source_acceptable<T>)
#elif defined(_MSC_VER)
- template <class T, class Deleter, size_t _internal_buffer_size, class>
+ template <enum path_view_component::zero_termination ZeroTermination, class T, class Deleter, size_t _internal_buffer_size, class>
#else
- template <class T, class Deleter, size_t _internal_buffer_size, typename std::enable_if<(is_source_acceptable<T>), bool>::type>
+ template <enum path_view_component::zero_termination ZeroTermination, class T, class Deleter, size_t _internal_buffer_size,
+ typename std::enable_if<(is_source_acceptable<T>), bool>::type>
#endif
- friend struct c_str;
+ friend class rendered_path;
};
static_assert(std::is_trivially_copyable<path_view_component>::value, "path_view_component is not trivially copyable!");
static_assert(sizeof(path_view_component) == 3 * sizeof(void *), "path_view_component is not three pointers in size!");
@@ -2041,22 +2147,22 @@ public:
If the source encodings of the two path views are compatible, a
lexicographical comparison is performed. If they are incompatible,
either or both views are converted to the destination encoding
- using `c_str<T, Delete, _internal_buffer_size>`, and then a
+ using `rendered_path<T, Delete, _internal_buffer_size>`, and then a
lexicographical comparison is performed.
This can, for obvious reasons, be expensive. It can also throw
- exceptions, as `c_str` does.
+ exceptions, as `rendered_path` does.
If the destination encoding is `byte`, `memcmp()` is used,
- and `c_str` is never invoked as the two sources are byte
+ and `rendered_path` is never invoked as the two sources are byte
compared directly.
*/
- LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class Deleter = default_c_str_deleter<T[]>,
+ LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class Deleter = default_rendered_path_deleter<T[]>,
size_t _internal_buffer_size = default_internal_buffer_size)
LLFIO_TREQUIRES(LLFIO_TPRED(path_view::is_source_acceptable<T>))
constexpr inline int compare(path_view p, const std::locale &loc) const;
//! \overload
- LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class Deleter = default_c_str_deleter<T[]>,
+ LLFIO_TEMPLATE(class T = typename filesystem::path::value_type, class Deleter = default_rendered_path_deleter<T[]>,
size_t _internal_buffer_size = default_internal_buffer_size)
LLFIO_TREQUIRES(LLFIO_TPRED(path_view::is_source_acceptable<T>))
constexpr inline int compare(path_view p) const;
@@ -2385,16 +2491,16 @@ constexpr inline int path_view::compare(path_view o) const
//! Append a path view component to a path
inline filesystem::path &operator+=(filesystem::path &a, path_view_component b)
{
- path_view_component::c_str<> zpath(b, path_view_component::not_zero_terminated);
- basic_string_view<filesystem::path::value_type> _(zpath.buffer, zpath.length);
+ path_view_component::not_zero_terminated_rendered_path<> zpath(b);
+ basic_string_view<filesystem::path::value_type> _ = zpath.as_string_view();
a.concat(_.begin(), _.end());
return a;
}
//! Append a path view component to a path
inline filesystem::path &operator/=(filesystem::path &a, path_view_component b)
{
- path_view_component::c_str<> zpath(b, path_view_component::not_zero_terminated);
- basic_string_view<filesystem::path::value_type> _(zpath.buffer, zpath.length);
+ path_view_component::not_zero_terminated_rendered_path<> zpath(b);
+ basic_string_view<filesystem::path::value_type> _ = zpath.as_string_view();
a.append(_.begin(), _.end());
return a;
}