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
|
#ifndef SLANG_CORE_STRING_SLICE_POOL_H
#define SLANG_CORE_STRING_SLICE_POOL_H
#include "slang-string.h"
#include "slang-list.h"
#include "slang-memory-arena.h"
#include "slang-dictionary.h"
#include "slang-array-view.h"
namespace Slang {
/* Holds a unique set of slices.
Note that all slices (except kNullHandle) are stored with terminating zeros.
The default handles kNullHandle, kEmptyHandle can only be used on a StringSlicePool
initialized with the Style::Default. Not doing so will return an undefined result.
TODO(JS):
An argument could be made to make different classes, perhaps deriving from a base class
that exhibited the two behaviors. That doing so would make the default handles defined
for that class for example.
This is a little awkward in practice, because behavior of some methods need to change
(like adding a c string with nullptr, or clearing, as well as some other perhaps less necessary
optimizations). This could be achieved via virtual functions, but this all seems overkill.
*/
class StringSlicePool
{
public:
typedef StringSlicePool ThisType;
typedef uint32_t HandleIntegral;
enum class Style
{
Default, ///< Default style - has default handles (like kNullHandle and kEmptyHandle)
Empty, ///< Empty style - has no handles by default. Using default handles will likely produce the wrong result.
};
enum class Handle : HandleIntegral;
typedef UnownedStringSlice Slice;
/// The following default handles *only* apply if constructed with the Style::Default
/// Handle of 0 is null. If accessed will be returned as the empty string with nullptr the chars
static const Handle kNullHandle = Handle(0);
/// Handle of 1 is the empty string.
static const Handle kEmptyHandle = Handle(1);
static const Index kDefaultHandlesCount = 2;
/// Returns the index of a slice, if contained, or -1 if not found
Index findIndex(const Slice& slice) const;
/// True if has the slice
bool has(const Slice& slice) { return findIndex(slice) >= 0; }
/// Add a slice
Handle add(const Slice& slice);
/// Add from a string
Handle add(const char* chars);
/// Add a StringRepresentation
Handle add(StringRepresentation* string);
/// Add a string
Handle add(const String& string) { return add(string.getUnownedSlice()); }
/// Add and get the result as a slice
Slice addAndGetSlice(const Slice& slice) { return getSlice(add(slice)); }
Slice addAndGetSlice(const char* chars) { return getSlice(add(chars)); }
Slice addAndGetSlice(const String& string) { return getSlice(add(string)); }
/// Returns true if found
bool findOrAdd(const Slice& slice, Handle& outHandle);
/// Empty contents
void clear();
/// Get the slice from the handle
const UnownedStringSlice& getSlice(Handle handle) const { return m_slices[UInt(handle)]; }
/// Get all the slices
const List<UnownedStringSlice>& getSlices() const { return m_slices; }
/// Get the number of slices
Index getSlicesCount() const { return m_slices.getCount(); }
/// Returns true if the handle is a default one. Only meaningful on a Style::Default.
bool isDefaultHandle(Handle handle) const
{
SLANG_ASSERT(
m_style == Style::Default &&
// TODO(C++20), use bit_cast here
HandleIntegral(handle) <= HandleIntegral(std::numeric_limits<Index>::max()));
return Index(handle) < kDefaultHandlesCount;
}
/// Convert a handle to and index. (A handle is just an index!)
static Index asIndex(Handle handle) { return Index(handle); }
/// Get the style of the pool
Style getStyle() const { return m_style; }
/// Get all the added slices (does not have default slices, if there are any)
ConstArrayView<UnownedStringSlice> getAdded() const;
/// Get the index of the first added handle
Index getFirstAddedIndex() const { return m_style == Style::Default ? kDefaultHandlesCount : 0; }
/// Swap this with rhs
void swapWith(ThisType& rhs);
/// True if the pools are identical. Same style, same slices in the same order.
bool operator==(const ThisType& rhs) const;
/// Copy ctor
StringSlicePool(const ThisType& rhs);
/// Assignment
void operator=(const ThisType& rhs);
/// Ctor
explicit StringSlicePool(Style style);
protected:
void _set(const ThisType& rhs);
Style m_style;
List<UnownedStringSlice> m_slices;
Dictionary<UnownedStringSlice, Handle> m_map;
MemoryArena m_arena;
};
} // namespace Slang
#endif // SLANG_STRING_SLICE_POOL_H
|