CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
string_private.h
1#pragma once
2
3#include "cx/string.h"
4#include "cx/utils/compare.h"
5#include "cx/thread/atomic.h"
6
7typedef struct str_ref* _Nonnull string_v; // validated string
8typedef const struct str_ref* _Nonnull strref_v; // validated strref
9typedef string_v* _Nonnull strhandle_v; // handle to validated string
10
11// Flags field
12
13#define STR_LEN0 0x00 // no length field, 8-bit ref count if STR_ALLOC
14#define STR_LEN8 0x01 // 8-bit length, 8-bit ref count if STR_ALLOC
15#define STR_LEN16 0x02 // 16-bit length, 16-bit ref count if STR_ALLOC
16#define STR_LEN32 0x03 // 32-bit length, 16-bit ref count if STR_ALLOC
17#define STR_LEN_MASK 0x03
18
19#define STR_STACK 0x04 // string is allocated on the stack, ref count is buffer size
20#define STR_ROPE 0x08 // string is a rope node
21#define STR_ALLOC 0x10 // string allocated by us, ref count field present
22#define STR_UTF8 0x20 // string is UTF-8
23#define STR_ASCII 0x40 // string is 7-bit ASCII
24#define STR_CX 0x80 // string contains cx header, otherwise plain C string
25
26#define STR_ENCODING_MASK (STR_UTF8 | STR_ASCII)
27
28#define STR_HDRP(s) ((uint8*)(s))
29#define STR_HDR(s) (((*STR_HDRP(s) & STR_CX) && STR_HDRP(s)[1] == 0xc1) ? *STR_HDRP(s) : 0)
30#define STR_FIELD(s, off, typ) (*(typ*)(&STR_HDRP(s)[off]))
31
32#define STR_OT_LEN 0
33#define STR_OT_REF 1
34#define STR_OT_STR 2
35extern const uint8 _str_off[32];
36// dirty trick here, since STR_ALLOC is defined as 16, it can be used
37// as-is as a base index into the table without further masking or shifting
38#define STR_OFF_BASE(hdr) ((hdr & STR_ALLOC) | (hdr & STR_LEN_MASK) << 2)
39#define STR_OFF_LEN(hdr) (_str_off[STR_OFF_BASE(hdr)])
40#define STR_OFF_REF(hdr) (_str_off[STR_OFF_BASE(hdr) | STR_OT_REF])
41#define STR_OFF_STR(hdr) (hdr & STR_CX ? (_str_off[STR_OFF_BASE(hdr) | STR_OT_STR]) : 0)
42
43#define STR_LEN8_LEN(s) STR_FIELD(s, _strOffLen(_strHdr(s)), uint8)
44#define STR_LEN16_LEN(s) STR_FIELD(s, _strOffLen(_strHdr(s)), uint16)
45#define STR_LEN32_LEN(s) STR_FIELD(s, _strOffLen(_strHdr(s)), uint32)
46
47#define STR_LEN8_REF(s) STR_FIELD(s, _strOffRef(_strHdr(s)), uint8)
48#define STR_LEN16_REF(s) STR_FIELD(s, _strOffRef(_strHdr(s)), uint16)
49
50#define STR_BUFFER(s) (&STR_FIELD(s, _strOffStr(_strHdr(s)), uint8))
51#define STR_ROPEDATA(s) (&STR_FIELD(s, _strOffStr(_strHdr(s)), str_ropedata))
52
53_meta_inline uint8 _strOffLen(uint8 hdr)
54{
55 return STR_OFF_LEN(hdr);
56}
57
58_meta_inline uint8 _strOffRef(uint8 hdr)
59{
60 return STR_OFF_REF(hdr);
61}
62
63_meta_inline uint8 _strOffStr(uint8 hdr)
64{
65 return STR_OFF_STR(hdr);
66}
67
68_Ret_valid_
69_meta_inline uint8 * _Nonnull _strHdrP(_In_ strref_v s)
70{
71 return STR_HDRP(s);
72}
73
74_meta_inline uint8 _strHdr(_In_ strref_v s)
75{
76 return STR_HDR(s);
77}
78
79_Ret_valid_
80_meta_inline uint8 * _Nonnull _strBuffer(_In_ strref_v s)
81{
82 return STR_BUFFER(s);
83}
84
85#define STR_CHECK_VALID(s) (s && *(uint8*)s)
86#define STR_SAFE_DEREF(ps) ((ps && *ps) ? *ps : 0)
87
88_meta_inline uint32 _strFastLen(_In_ strref_v s)
89{
90 if (!(STR_HDR(s) & STR_CX))
91 return (uint32)cstrLen((const char*)s);
92 switch (STR_HDR(s) & STR_LEN_MASK) {
93 case STR_LEN8:
94 return STR_LEN8_LEN(s);
95 case STR_LEN16:
96 return STR_LEN16_LEN(s);
97 case STR_LEN32:
98 return STR_LEN32_LEN(s);
99 default: // STR_LEN0
100 return (uint32)cstrLen((const char*)_strBuffer(s));
101 }
102}
103
104// must only be used on STR_CX | STR_ALLOC strings!
105_meta_inline uint16 _strFastRef(_In_ strref_v s)
106{
107 int l = STR_HDR(s) & STR_LEN_MASK;
108
109 if (l <= STR_LEN8)
110 return atomicLoad(uint8, &STR_FIELD(s, STR_OFF_REF(STR_HDR(s)), atomic(uint8)), Acquire);
111 else
112 return atomicLoad(uint16, &STR_FIELD(s, STR_OFF_REF(STR_HDR(s)), atomic(uint16)), Acquire);
113}
114
115_meta_inline uint16 _strFastRefNoSync(_In_ strref_v s)
116{
117 int l = STR_HDR(s) & STR_LEN_MASK;
118
119 if (l <= STR_LEN8)
120 return STR_LEN8_REF(s);
121 else
122 return STR_LEN16_REF(s);
123}
124
125// Always round up allocations to avoid constant realloc
126#define STR_ALLOC_SIZE 16
127
128// rope tuning
129// try not to create a rope smaller than this
130#define ROPE_MIN_SIZE 64
131// use a rope if final join size exceeds this
132#define ROPE_JOIN_THRESH 128
133// use a rope if substring size exceeds this
134#define ROPE_SUBSTR_THRESH 96
135// maximum size to merge together on joins
136#define ROPE_MAX_MERGE 256
137
138#include "string_private_utf8.h"
139
140// dummy empty string used as input when NULL or invalid strings are passed in
141extern string_v _strEmpty;
142
143// resets the string internals, re-use memory if possible
144void _strReset(_Inout_ptr_opt_ strhandle s, uint32 minsz);
145
146// these change the structure internally and can result in inconsistent state
147// if not used with care
148void _strSetLen(_Inout_ string_v s, uint32 len);
149void _strInitRef(_Inout_ string_v s);
150void _strSetRef(_Inout_ string_v s, uint16 ref);
151
152// ensure that ps is allocated by us and has a single reference
153void _strMakeUnique(_Inout_ptr_ strhandle_v ps, uint32 minszforcopy);
154// like _strMakeUnique but also flattens ropes into plain strings
155void _strFlatten(_Inout_ptr_ strhandle_v ps, uint32 minszforcopy);
156// resize ps in place if possible, or copy if necessary (changing ps).
157// resizes buffer only, does NOT zero buffer or set length header
158void _strResize(_Inout_ptr_ strhandle_v ps, uint32 len, bool unique);
159// duplicates s and returns a copy, optionally with more reserved space allocated
160_Ret_valid_ string_v _strCopy(_In_ strref_v s, uint32 minsz);
161// direct copy of string buffer or rope internals, does not check destination size!
162uint32 _strFastCopy(_In_ strref_v s, uint32 off, _Out_writes_bytes_(bytes) uint8 *_Nonnull buf, uint32 bytes);
163
164// rope data comes directly after string header if STR_ROPE is set
165typedef struct str_roperef {
166 string str;
167 uint32 off;
168 uint32 len;
169} str_roperef;
170typedef struct str_ropedata {
171 str_roperef left;
172 str_roperef right;
173 int depth;
174} str_ropedata;
175
176_Ret_valid_
177_meta_inline str_ropedata *_strRopeData(_In_ strref_v s)
178{
179 return STR_ROPEDATA(s);
180}
181
182string_v _strCreateRope(_In_ strref_v left, uint32 left_off, uint32 left_len, _In_opt_ strref right, uint32 right_off, uint32 right_len, bool balance);
183string_v _strCreateRope1(_In_ strref_v s, uint32 off, uint32 len);
184string_v _strCloneRope(_In_ strref_v s);
185void _strDestroyRope(_Inout_ string_v s);
186uint32 _strRopeFastCopy(_In_ strref_v s, uint32 off, _Out_writes_bytes_(bytes) uint8 *_Nonnull buf, uint32 bytes);
187_Success_(return) bool _strRopeRealStr(_Inout_ strhandle_v s, uint32 off, _Out_ strhandle_v rs, _Out_ uint32 *_Nonnull rsoff, _Out_ uint32 *_Nonnull rslen, _Out_ uint32 *_Nonnull rsstart, bool writable);
188
189// Finds first occurrence of find in s at or after start
190int32 _strFindChar(_In_ strref_v s, int32 start, char find);
191// Finds last occurrence of find in s before end
192// end can be 0 to indicate end of the string
193int32 _strFindCharR(_In_ strref_v s, int32 end, char find);
194
195_meta_inline uint8 _strFastChar(_In_ strref s, uint32 i)
196{
197 if (!(STR_HDR(s) & STR_ROPE)) {
198 return _strBuffer(s)[i];
199 } else {
200 string realstr;
201 uint32 realoff, reallen, realstart;
202 if (_strRopeRealStr((string*)&s, i, &realstr, &realoff, &reallen, &realstart, false))
203 return _strBuffer(realstr)[realoff];
204 }
205 return 0;
206}
207
208extern char _strnum_udigits[];
209extern char _strnum_ldigits[];
Comparison and clamping macros.
size_t cstrLen(const char *s)
string * strhandle
Pointer to a string variable.
Definition strbase.h:45
Copy-on-write strings with automatic memory management and rope optimization.