-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathnull_term.hh
161 lines (122 loc) · 4 KB
/
null_term.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright (c) 2022 Mikael Simonsson <https://mikaelsimonsson.com>.
// SPDX-License-Identifier: BSL-1.0
// # Null-terminated non-null pointer wrapper
// Null-terminated version of `not_null<Ptr>`.
#pragma once
#include "snn-core/strcore.fwd.hh"
#include "snn-core/string/size.hh"
namespace snn
{
// ## Classes
// ### null_term
template <pointer Ptr>
class null_term final
{
public:
// #### Explicit constructors
// Construct with the implicit promise that the pointer is null-terminated.
constexpr explicit null_term(const snn::not_null<Ptr> ptr) noexcept
: ptr_{ptr}
{
if constexpr (SNN_ADDRESS_SANITIZER_BOOL)
{
snn_should(count_() < constant::limit<usize>::max);
}
}
// Construct with the explicit promise that the pointer is null-terminated.
constexpr explicit null_term(const snn::not_null<Ptr> ptr,
promise::null_terminated_t) noexcept
: null_term{ptr}
{
}
// #### get
[[nodiscard]] constexpr Ptr get() const noexcept
{
return ptr_.get();
}
// #### not_null
[[nodiscard]] constexpr snn::not_null<Ptr> not_null() const noexcept
{
return ptr_;
}
// #### Conversion
template <typename Other>
[[nodiscard]] constexpr Other to() const
noexcept(noexcept(Other{ptr_, promise::null_terminated}))
{
return Other{ptr_, promise::null_terminated};
}
private:
snn::not_null<Ptr> ptr_;
constexpr usize count_() const noexcept
{
usize i = 0;
Ptr raw = ptr_.get();
while (raw[i] != 0)
{
++i;
}
return i;
}
};
// ### null_term<const char*> specialization
template <>
class null_term<const char*> final
{
public:
// #### Explicit constructors
// Construct with the implicit promise that the pointer is null-terminated.
constexpr explicit null_term(const snn::not_null<const char*> s) noexcept
: s_{s}
{
if constexpr (SNN_ADDRESS_SANITIZER_BOOL)
{
snn_should(string::size(s, promise::null_terminated) < constant::limit<usize>::max);
}
}
// Construct with the explicit promise that the pointer is null-terminated.
constexpr explicit null_term(const snn::not_null<const char*> s,
promise::null_terminated_t) noexcept
: null_term{s}
{
}
// #### Converting constructors
template <same_as<const char> ConstChar, usize N>
constexpr null_term(ConstChar (&s)[N]) noexcept
: s_{snn::not_null{s}}
{
}
template <typename Buf>
requires(strcore<Buf>::is_null_terminated())
null_term(const strcore<Buf>& s)
: s_{s.null_terminated().not_null()}
{
}
template <typename Buf>
requires(strcore<Buf>::is_null_terminated())
null_term(const strcore<Buf>&&) = delete; // Temporary, use null_terminated() if safe.
// #### get
[[nodiscard]] constexpr const char* get() const noexcept
{
return s_.get();
}
// #### not_null
[[nodiscard]] constexpr snn::not_null<const char*> not_null() const noexcept
{
return s_;
}
// #### Conversion
template <typename String>
[[nodiscard]] constexpr String to() const
noexcept(noexcept(String{s_, promise::null_terminated}))
{
return String{s_, promise::null_terminated};
}
private:
snn::not_null<const char*> s_;
};
// ## Deduction guides
// ### null_term
template <usize N>
null_term(const char (&)[N]) -> null_term<const char*>;
}