Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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
};