#pragma once #include #include #include #include "dxxsconf.h" #include "pack.h" #include template class ntstring : public prohibit_void_ptr>, public std::array { static char terminator() { return 0; } public: using array_t = std::array; typedef char elements_t[L + 1]; using array_t::operator[]; typename array_t::reference operator[](int i) { return array_t::operator[](i); } typename array_t::reference operator[](unsigned i) { return array_t::operator[](i); } __attribute_nonnull() std::size_t _copy_n(std::size_t offset, const char *ib, std::size_t N) { if (offset >= this->size()) return 0; auto eb = ib; std::size_t r = (offset + N) <= L ? N : 0; if (r) eb += N; auto ob = std::next(this->begin(), offset); auto oc = std::copy(ib, eb, ob); std::fill(oc, this->end(), terminator()); return r; } template __attribute_nonnull() std::size_t _copy(std::size_t offset, const char *i) { static_assert(N <= L, "string too long"); return _copy_n(offset, i, N); } template std::size_t copy_if(I &&i) { return copy_if(static_cast(0), static_cast(i)); } template std::size_t copy_if(I &&i, std::size_t N) { return copy_if(static_cast(0), static_cast(i), N); } template std::size_t copy_if(std::size_t out_offset, I &&i) { return copy_if(out_offset, static_cast(i), this->size()); } template std::size_t copy_if(std::size_t out_offset, const std::array &i, std::size_t n = N) { #ifdef DXX_CONSTANT_TRUE if (DXX_CONSTANT_TRUE(n > N)) DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_overread, "read size exceeds array size"); #endif return copy_if(out_offset, i.data(), n); } template std::size_t copy_if(std::size_t out_offset, const char (&i)[N]) { static_assert(N <= L + 1, "string too long"); return copy_if(out_offset, i, N); } __attribute_nonnull() std::size_t copy_if(std::size_t offset, const char *i, std::size_t N) { const std::size_t d = #ifdef DXX_CONSTANT_TRUE (DXX_CONSTANT_TRUE(!i[N - 1])) ? N - 1 : #endif std::distance(i, std::find(i, i + N, terminator())); return _copy_n(offset, i, d); } __attribute_nonnull() std::size_t _copy_out(const std::size_t src_offset, char *const dst_base, const std::size_t dst_offset, const std::size_t max_copy) const { char *const dst = dst_base + dst_offset; if (L > max_copy || src_offset >= this->size()) { /* Some outputs might not fit or nothing to copy */ *dst = terminator(); return 1; } const auto ie = std::prev(this->end()); const auto ib = std::next(this->begin(), src_offset); auto ii = std::find(ib, ie, terminator()); if (ii != ie) /* Only copy null if string is short */ ++ ii; const std::size_t r = std::distance(ib, ii); if (r > max_copy) { /* This output does not fit */ *dst = terminator(); return 1; } std::copy(ib, ii, dst); return r; } __attribute_nonnull() std::size_t copy_out(std::size_t src_offset, char *dst, std::size_t dst_offset, std::size_t dst_size) const { if (dst_size <= dst_offset) return 0; return _copy_out(src_offset, dst, dst_offset, dst_size - dst_offset); } __attribute_nonnull() std::size_t copy_out(std::size_t src_offset, char *dst, std::size_t dst_size) const { return copy_out(src_offset, dst, 0, dst_size); } template std::size_t copy_out(std::size_t src_offset, std::array &dst, std::size_t dst_offset) const { return copy_out(src_offset, dst.data(), dst_offset, N); } template std::size_t copy_out(std::size_t src_offset, std::array &dst, std::size_t dst_offset) const { return copy_out(src_offset, reinterpret_cast(dst.data()), dst_offset, N); } operator bool() const = delete; operator char *() const = delete; operator elements_t &() const = delete; operator const elements_t &() const { return *reinterpret_cast(this->data()); } bool operator==(const ntstring &r) const __attribute_warn_unused_result { return static_cast(*this) == static_cast(r); } bool operator!=(const ntstring &r) const __attribute_warn_unused_result { return !(*this == r); } template ntstring &operator=(const char (&i)[N]) { copy_if(i); return *this; } };