1*8af74909SZhong Yang // Scintilla source code edit control
2*8af74909SZhong Yang /** @file CharacterSet.h
3*8af74909SZhong Yang ** Encapsulates a set of characters. Used to test if a character is within a set.
4*8af74909SZhong Yang **/
5*8af74909SZhong Yang // Copyright 2007 by Neil Hodgson <[email protected]>
6*8af74909SZhong Yang // The License.txt file describes the conditions under which this software may be distributed.
7*8af74909SZhong Yang
8*8af74909SZhong Yang #ifndef CHARACTERSET_H
9*8af74909SZhong Yang #define CHARACTERSET_H
10*8af74909SZhong Yang
11*8af74909SZhong Yang namespace Scintilla {
12*8af74909SZhong Yang
13*8af74909SZhong Yang class CharacterSet {
14*8af74909SZhong Yang int size;
15*8af74909SZhong Yang bool valueAfter;
16*8af74909SZhong Yang bool *bset;
17*8af74909SZhong Yang public:
18*8af74909SZhong Yang enum setBase {
19*8af74909SZhong Yang setNone=0,
20*8af74909SZhong Yang setLower=1,
21*8af74909SZhong Yang setUpper=2,
22*8af74909SZhong Yang setDigits=4,
23*8af74909SZhong Yang setAlpha=setLower|setUpper,
24*8af74909SZhong Yang setAlphaNum=setAlpha|setDigits
25*8af74909SZhong Yang };
26*8af74909SZhong Yang CharacterSet(setBase base=setNone, const char *initialSet="", int size_=0x80, bool valueAfter_=false) {
27*8af74909SZhong Yang size = size_;
28*8af74909SZhong Yang valueAfter = valueAfter_;
29*8af74909SZhong Yang bset = new bool[size];
30*8af74909SZhong Yang for (int i=0; i < size; i++) {
31*8af74909SZhong Yang bset[i] = false;
32*8af74909SZhong Yang }
33*8af74909SZhong Yang AddString(initialSet);
34*8af74909SZhong Yang if (base & setLower)
35*8af74909SZhong Yang AddString("abcdefghijklmnopqrstuvwxyz");
36*8af74909SZhong Yang if (base & setUpper)
37*8af74909SZhong Yang AddString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
38*8af74909SZhong Yang if (base & setDigits)
39*8af74909SZhong Yang AddString("0123456789");
40*8af74909SZhong Yang }
CharacterSet(const CharacterSet & other)41*8af74909SZhong Yang CharacterSet(const CharacterSet &other) {
42*8af74909SZhong Yang size = other.size;
43*8af74909SZhong Yang valueAfter = other.valueAfter;
44*8af74909SZhong Yang bset = new bool[size];
45*8af74909SZhong Yang for (int i=0; i < size; i++) {
46*8af74909SZhong Yang bset[i] = other.bset[i];
47*8af74909SZhong Yang }
48*8af74909SZhong Yang }
CharacterSet(CharacterSet && other)49*8af74909SZhong Yang CharacterSet(CharacterSet &&other) noexcept {
50*8af74909SZhong Yang size = other.size;
51*8af74909SZhong Yang valueAfter = other.valueAfter;
52*8af74909SZhong Yang bset = other.bset;
53*8af74909SZhong Yang other.size = 0;
54*8af74909SZhong Yang other.bset = nullptr;
55*8af74909SZhong Yang }
56*8af74909SZhong Yang CharacterSet &operator=(const CharacterSet &other) {
57*8af74909SZhong Yang if (this != &other) {
58*8af74909SZhong Yang bool *bsetNew = new bool[other.size];
59*8af74909SZhong Yang for (int i = 0; i < other.size; i++) {
60*8af74909SZhong Yang bsetNew[i] = other.bset[i];
61*8af74909SZhong Yang }
62*8af74909SZhong Yang delete[]bset;
63*8af74909SZhong Yang size = other.size;
64*8af74909SZhong Yang valueAfter = other.valueAfter;
65*8af74909SZhong Yang bset = bsetNew;
66*8af74909SZhong Yang }
67*8af74909SZhong Yang return *this;
68*8af74909SZhong Yang }
69*8af74909SZhong Yang CharacterSet &operator=(CharacterSet &&other) noexcept {
70*8af74909SZhong Yang if (this != &other) {
71*8af74909SZhong Yang delete []bset;
72*8af74909SZhong Yang size = other.size;
73*8af74909SZhong Yang valueAfter = other.valueAfter;
74*8af74909SZhong Yang bset = other.bset;
75*8af74909SZhong Yang other.size = 0;
76*8af74909SZhong Yang other.bset = nullptr;
77*8af74909SZhong Yang }
78*8af74909SZhong Yang return *this;
79*8af74909SZhong Yang }
~CharacterSet()80*8af74909SZhong Yang ~CharacterSet() {
81*8af74909SZhong Yang delete []bset;
82*8af74909SZhong Yang bset = nullptr;
83*8af74909SZhong Yang size = 0;
84*8af74909SZhong Yang }
Add(int val)85*8af74909SZhong Yang void Add(int val) {
86*8af74909SZhong Yang assert(val >= 0);
87*8af74909SZhong Yang assert(val < size);
88*8af74909SZhong Yang bset[val] = true;
89*8af74909SZhong Yang }
AddString(const char * setToAdd)90*8af74909SZhong Yang void AddString(const char *setToAdd) {
91*8af74909SZhong Yang for (const char *cp=setToAdd; *cp; cp++) {
92*8af74909SZhong Yang const unsigned char uch = *cp;
93*8af74909SZhong Yang assert(uch < size);
94*8af74909SZhong Yang bset[uch] = true;
95*8af74909SZhong Yang }
96*8af74909SZhong Yang }
Contains(int val)97*8af74909SZhong Yang bool Contains(int val) const noexcept {
98*8af74909SZhong Yang assert(val >= 0);
99*8af74909SZhong Yang if (val < 0) return false;
100*8af74909SZhong Yang return (val < size) ? bset[val] : valueAfter;
101*8af74909SZhong Yang }
Contains(char ch)102*8af74909SZhong Yang bool Contains(char ch) const noexcept {
103*8af74909SZhong Yang // Overload char as char may be signed
104*8af74909SZhong Yang const unsigned char uch = ch;
105*8af74909SZhong Yang return Contains(uch);
106*8af74909SZhong Yang }
107*8af74909SZhong Yang };
108*8af74909SZhong Yang
109*8af74909SZhong Yang // Functions for classifying characters
110*8af74909SZhong Yang
IsASpace(int ch)111*8af74909SZhong Yang constexpr bool IsASpace(int ch) noexcept {
112*8af74909SZhong Yang return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
113*8af74909SZhong Yang }
114*8af74909SZhong Yang
IsASpaceOrTab(int ch)115*8af74909SZhong Yang constexpr bool IsASpaceOrTab(int ch) noexcept {
116*8af74909SZhong Yang return (ch == ' ') || (ch == '\t');
117*8af74909SZhong Yang }
118*8af74909SZhong Yang
IsADigit(int ch)119*8af74909SZhong Yang constexpr bool IsADigit(int ch) noexcept {
120*8af74909SZhong Yang return (ch >= '0') && (ch <= '9');
121*8af74909SZhong Yang }
122*8af74909SZhong Yang
IsADigit(int ch,int base)123*8af74909SZhong Yang constexpr bool IsADigit(int ch, int base) noexcept {
124*8af74909SZhong Yang if (base <= 10) {
125*8af74909SZhong Yang return (ch >= '0') && (ch < '0' + base);
126*8af74909SZhong Yang } else {
127*8af74909SZhong Yang return ((ch >= '0') && (ch <= '9')) ||
128*8af74909SZhong Yang ((ch >= 'A') && (ch < 'A' + base - 10)) ||
129*8af74909SZhong Yang ((ch >= 'a') && (ch < 'a' + base - 10));
130*8af74909SZhong Yang }
131*8af74909SZhong Yang }
132*8af74909SZhong Yang
IsASCII(int ch)133*8af74909SZhong Yang constexpr bool IsASCII(int ch) noexcept {
134*8af74909SZhong Yang return (ch >= 0) && (ch < 0x80);
135*8af74909SZhong Yang }
136*8af74909SZhong Yang
IsLowerCase(int ch)137*8af74909SZhong Yang constexpr bool IsLowerCase(int ch) noexcept {
138*8af74909SZhong Yang return (ch >= 'a') && (ch <= 'z');
139*8af74909SZhong Yang }
140*8af74909SZhong Yang
IsUpperCase(int ch)141*8af74909SZhong Yang constexpr bool IsUpperCase(int ch) noexcept {
142*8af74909SZhong Yang return (ch >= 'A') && (ch <= 'Z');
143*8af74909SZhong Yang }
144*8af74909SZhong Yang
IsUpperOrLowerCase(int ch)145*8af74909SZhong Yang constexpr bool IsUpperOrLowerCase(int ch) noexcept {
146*8af74909SZhong Yang return IsUpperCase(ch) || IsLowerCase(ch);
147*8af74909SZhong Yang }
148*8af74909SZhong Yang
IsAlphaNumeric(int ch)149*8af74909SZhong Yang constexpr bool IsAlphaNumeric(int ch) noexcept {
150*8af74909SZhong Yang return
151*8af74909SZhong Yang ((ch >= '0') && (ch <= '9')) ||
152*8af74909SZhong Yang ((ch >= 'a') && (ch <= 'z')) ||
153*8af74909SZhong Yang ((ch >= 'A') && (ch <= 'Z'));
154*8af74909SZhong Yang }
155*8af74909SZhong Yang
156*8af74909SZhong Yang /**
157*8af74909SZhong Yang * Check if a character is a space.
158*8af74909SZhong Yang * This is ASCII specific but is safe with chars >= 0x80.
159*8af74909SZhong Yang */
isspacechar(int ch)160*8af74909SZhong Yang constexpr bool isspacechar(int ch) noexcept {
161*8af74909SZhong Yang return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
162*8af74909SZhong Yang }
163*8af74909SZhong Yang
iswordchar(int ch)164*8af74909SZhong Yang constexpr bool iswordchar(int ch) noexcept {
165*8af74909SZhong Yang return IsAlphaNumeric(ch) || ch == '.' || ch == '_';
166*8af74909SZhong Yang }
167*8af74909SZhong Yang
iswordstart(int ch)168*8af74909SZhong Yang constexpr bool iswordstart(int ch) noexcept {
169*8af74909SZhong Yang return IsAlphaNumeric(ch) || ch == '_';
170*8af74909SZhong Yang }
171*8af74909SZhong Yang
isoperator(int ch)172*8af74909SZhong Yang constexpr bool isoperator(int ch) noexcept {
173*8af74909SZhong Yang if (IsAlphaNumeric(ch))
174*8af74909SZhong Yang return false;
175*8af74909SZhong Yang if (ch == '%' || ch == '^' || ch == '&' || ch == '*' ||
176*8af74909SZhong Yang ch == '(' || ch == ')' || ch == '-' || ch == '+' ||
177*8af74909SZhong Yang ch == '=' || ch == '|' || ch == '{' || ch == '}' ||
178*8af74909SZhong Yang ch == '[' || ch == ']' || ch == ':' || ch == ';' ||
179*8af74909SZhong Yang ch == '<' || ch == '>' || ch == ',' || ch == '/' ||
180*8af74909SZhong Yang ch == '?' || ch == '!' || ch == '.' || ch == '~')
181*8af74909SZhong Yang return true;
182*8af74909SZhong Yang return false;
183*8af74909SZhong Yang }
184*8af74909SZhong Yang
185*8af74909SZhong Yang // Simple case functions for ASCII supersets.
186*8af74909SZhong Yang
187*8af74909SZhong Yang template <typename T>
MakeUpperCase(T ch)188*8af74909SZhong Yang constexpr T MakeUpperCase(T ch) noexcept {
189*8af74909SZhong Yang if (ch < 'a' || ch > 'z')
190*8af74909SZhong Yang return ch;
191*8af74909SZhong Yang else
192*8af74909SZhong Yang return ch - 'a' + 'A';
193*8af74909SZhong Yang }
194*8af74909SZhong Yang
195*8af74909SZhong Yang template <typename T>
MakeLowerCase(T ch)196*8af74909SZhong Yang constexpr T MakeLowerCase(T ch) noexcept {
197*8af74909SZhong Yang if (ch < 'A' || ch > 'Z')
198*8af74909SZhong Yang return ch;
199*8af74909SZhong Yang else
200*8af74909SZhong Yang return ch - 'A' + 'a';
201*8af74909SZhong Yang }
202*8af74909SZhong Yang
203*8af74909SZhong Yang int CompareCaseInsensitive(const char *a, const char *b) noexcept;
204*8af74909SZhong Yang int CompareNCaseInsensitive(const char *a, const char *b, size_t len) noexcept;
205*8af74909SZhong Yang
206*8af74909SZhong Yang }
207*8af74909SZhong Yang
208*8af74909SZhong Yang #endif
209