Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #pragma once
  2.  
  3. #include <algorithm>
  4. #include <cstddef>
  5. #include <cstdint>
  6. #include "dxxsconf.h"
  7. #include "pack.h"
  8. #include <array>
  9.  
  10. template <std::size_t L>
  11. class ntstring :
  12.         public prohibit_void_ptr<ntstring<L>>,
  13.         public std::array<char, L + 1>
  14. {
  15.         static char terminator() { return 0; }
  16. public:
  17.         using array_t = std::array<char, L + 1>;
  18.         typedef char elements_t[L + 1];
  19.         using array_t::operator[];
  20.         typename array_t::reference operator[](int i) { return array_t::operator[](i); }
  21.         typename array_t::reference operator[](unsigned i) { return array_t::operator[](i); }
  22.         __attribute_nonnull()
  23.         std::size_t _copy_n(std::size_t offset, const char *ib, std::size_t N)
  24.         {
  25.                 if (offset >= this->size())
  26.                         return 0;
  27.                 auto eb = ib;
  28.                 std::size_t r = (offset + N) <= L ? N : 0;
  29.                 if (r)
  30.                         eb += N;
  31.                 auto ob = std::next(this->begin(), offset);
  32.                 auto oc = std::copy(ib, eb, ob);
  33.                 std::fill(oc, this->end(), terminator());
  34.                 return r;
  35.         }
  36.         template <std::size_t N>
  37.                 __attribute_nonnull()
  38.                 std::size_t _copy(std::size_t offset, const char *i)
  39.                 {
  40.                         static_assert(N <= L, "string too long");
  41.                         return _copy_n(offset, i, N);
  42.                 }
  43.         template <typename I>
  44.                 std::size_t copy_if(I &&i)
  45.                 {
  46.                         return copy_if(static_cast<std::size_t>(0), static_cast<I &&>(i));
  47.                 }
  48.         template <typename I>
  49.                 std::size_t copy_if(I &&i, std::size_t N)
  50.                 {
  51.                         return copy_if(static_cast<std::size_t>(0), static_cast<I &&>(i), N);
  52.                 }
  53.         template <typename I>
  54.                 std::size_t copy_if(std::size_t out_offset, I &&i)
  55.                 {
  56.                         return copy_if(out_offset, static_cast<I &&>(i), this->size());
  57.                 }
  58.         template <std::size_t N>
  59.                 std::size_t copy_if(std::size_t out_offset, const std::array<char, N> &i, std::size_t n = N)
  60.                 {
  61. #ifdef DXX_CONSTANT_TRUE
  62.                         if (DXX_CONSTANT_TRUE(n > N))
  63.                                 DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_overread, "read size exceeds array size");
  64. #endif
  65.                         return copy_if(out_offset, i.data(), n);
  66.                 }
  67.         template <std::size_t N>
  68.                 std::size_t copy_if(std::size_t out_offset, const char (&i)[N])
  69.                 {
  70.                         static_assert(N <= L + 1, "string too long");
  71.                         return copy_if(out_offset, i, N);
  72.                 }
  73.         __attribute_nonnull()
  74.         std::size_t copy_if(std::size_t offset, const char *i, std::size_t N)
  75.         {
  76.                 const std::size_t d =
  77. #ifdef DXX_CONSTANT_TRUE
  78.                         (DXX_CONSTANT_TRUE(!i[N - 1])) ? N - 1 :
  79. #endif
  80.                         std::distance(i, std::find(i, i + N, terminator()));
  81.                 return _copy_n(offset, i, d);
  82.         }
  83.         __attribute_nonnull()
  84.         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
  85.         {
  86.                 char *const dst = dst_base + dst_offset;
  87.                 if (L > max_copy || src_offset >= this->size())
  88.                 {
  89.                         /* Some outputs might not fit or nothing to copy */
  90.                         *dst = terminator();
  91.                         return 1;
  92.                 }
  93.                 const auto ie = std::prev(this->end());
  94.                 const auto ib = std::next(this->begin(), src_offset);
  95.                 auto ii = std::find(ib, ie, terminator());
  96.                 if (ii != ie)
  97.                         /* Only copy null if string is short  */
  98.                         ++ ii;
  99.                 const std::size_t r = std::distance(ib, ii);
  100.                 if (r > max_copy)
  101.                 {
  102.                         /* This output does not fit */
  103.                         *dst = terminator();
  104.                         return 1;
  105.                 }
  106.                 std::copy(ib, ii, dst);
  107.                 return r;
  108.         }
  109.         __attribute_nonnull()
  110.         std::size_t copy_out(std::size_t src_offset, char *dst, std::size_t dst_offset, std::size_t dst_size) const
  111.         {
  112.                 if (dst_size <= dst_offset)
  113.                         return 0;
  114.                 return _copy_out(src_offset, dst, dst_offset, dst_size - dst_offset);
  115.         }
  116.         __attribute_nonnull()
  117.         std::size_t copy_out(std::size_t src_offset, char *dst, std::size_t dst_size) const
  118.         {
  119.                 return copy_out(src_offset, dst, 0, dst_size);
  120.         }
  121.         template <std::size_t N>
  122.                 std::size_t copy_out(std::size_t src_offset, std::array<char, N> &dst, std::size_t dst_offset) const
  123.                 {
  124.                         return copy_out(src_offset, dst.data(), dst_offset, N);
  125.                 }
  126.         template <std::size_t N>
  127.                 std::size_t copy_out(std::size_t src_offset, std::array<uint8_t, N> &dst, std::size_t dst_offset) const
  128.                 {
  129.                         return copy_out(src_offset, reinterpret_cast<char *>(dst.data()), dst_offset, N);
  130.                 }
  131.         operator bool() const = delete;
  132.         operator char *() const = delete;
  133.         operator elements_t &() const = delete;
  134.         operator const elements_t &() const
  135.         {
  136.                 return *reinterpret_cast<const elements_t *>(this->data());
  137.         }
  138.         bool operator==(const ntstring &r) const __attribute_warn_unused_result
  139.         {
  140.                 return static_cast<const array_t &>(*this) == static_cast<const array_t &>(r);
  141.         }
  142.         bool operator!=(const ntstring &r) const __attribute_warn_unused_result
  143.         {
  144.                 return !(*this == r);
  145.         }
  146.         template <std::size_t N>
  147.                 ntstring &operator=(const char (&i)[N])
  148.                 {
  149.                         copy_if(i);
  150.                         return *this;
  151.                 }
  152. };
  153.