yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
7.1 KiB247 linesraw
1#include "slang-char-encode.h"
2
3namespace Slang
4{
5
6class Utf8CharEncoding : public CharEncoding
7{
8public:
9    typedef CharEncoding Super;
10
11    virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override
12    {
13        ioBuffer.addRange((const Byte*)slice.begin(), slice.getLength());
14    }
15    virtual void decode(const Byte* bytes, int length, List<char>& ioChars) override
16    {
17        ioChars.addRange((const char*)bytes, length);
18    }
19    Utf8CharEncoding()
20        : Super(CharEncodeType::UTF8)
21    {
22    }
23};
24
25class Utf32CharEncoding : public CharEncoding
26{
27public:
28    typedef CharEncoding Super;
29
30    virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override
31    {
32        Index ptr = 0;
33        while (ptr < slice.getLength())
34        {
35            const Char32 codePoint = getUnicodePointFromUTF8(
36                [&]() -> Byte
37                {
38                    if (ptr < slice.getLength())
39                        return slice[ptr++];
40                    else
41                        return '\0';
42                });
43            // Note: Assumes byte order is same as arch byte order
44            ioBuffer.addRange((const Byte*)&codePoint, 4);
45        }
46    }
47    virtual void decode(const Byte* bytes, int length, List<char>& ioBuffer) override
48    {
49        // Note: Assumes bytes is Char32 aligned
50        SLANG_ASSERT((size_t(bytes) & 3) == 0);
51        const Char32* content = (const Char32*)bytes;
52        for (int i = 0; i < (length >> 2); i++)
53        {
54            char buf[5];
55            int count = encodeUnicodePointToUTF8(content[i], buf);
56            for (int j = 0; j < count; j++)
57                ioBuffer.addRange(buf, count);
58        }
59    }
60
61    Utf32CharEncoding()
62        : Super(CharEncodeType::UTF32)
63    {
64    }
65};
66
67class Utf16CharEncoding : public CharEncoding // UTF16
68{
69public:
70    typedef CharEncoding Super;
71    Utf16CharEncoding(bool reverseOrder)
72        : Super(reverseOrder ? CharEncodeType::UTF16Reversed : CharEncodeType::UTF16)
73        , m_reverseOrder(reverseOrder)
74    {
75    }
76    virtual void encode(const UnownedStringSlice& slice, List<Byte>& ioBuffer) override
77    {
78        Index index = 0;
79        while (index < slice.getLength())
80        {
81            const Char32 codePoint = getUnicodePointFromUTF8(
82                [&]() -> Byte
83                {
84                    if (index < slice.getLength())
85                        return slice[index++];
86                    else
87                        return '\0';
88                });
89
90            Char16 buffer[2];
91            int count;
92            if (!m_reverseOrder)
93                count = encodeUnicodePointToUTF16(codePoint, buffer);
94            else
95                count = encodeUnicodePointToUTF16Reversed(codePoint, buffer);
96            ioBuffer.addRange((const Byte*)buffer, count * 2);
97        }
98    }
99    virtual void decode(const Byte* bytes, int length, List<char>& ioBuffer) override
100    {
101        Index index = 0;
102        while (index < length)
103        {
104            auto readByte = [&]() -> Byte { return (index < length) ? bytes[index++] : Byte(0); };
105            const Char32 codePoint = m_reverseOrder ? getUnicodePointFromUTF16Reversed(readByte)
106                                                    : getUnicodePointFromUTF16(readByte);
107
108            char buf[5];
109            int count = encodeUnicodePointToUTF8(codePoint, buf);
110            ioBuffer.addRange((const char*)buf, count);
111        }
112    }
113
114private:
115    bool m_reverseOrder = false;
116};
117
118/* static */ CharEncodeType CharEncoding::determineEncoding(
119    const Byte* bytes,
120    size_t bytesCount,
121    size_t& outOffset)
122{
123    // TODO(JS): Assumes the bytes are suitably aligned
124
125    if (bytesCount >= 3 && bytes[0] == 0xef && bytes[1] == 0xbb && bytes[2] == 0xbf)
126    {
127        outOffset = 3;
128        return CharEncodeType::UTF8;
129    }
130    else if (bytesCount >= 2)
131    {
132        Char16 c;
133        ::memcpy(&c, bytes, 2);
134
135        if (c == kUTF16Header)
136        {
137            outOffset = 2;
138            return CharEncodeType::UTF16;
139        }
140        else if (c == kUTF16ReversedHeader)
141        {
142            outOffset = 2;
143            return CharEncodeType::UTF16Reversed;
144        }
145
146        // If we don't have a 'mark' byte then we are bit stumped. We'll look for
147        // null (non-terminator) bytes and assume they mean we have a 16-bit encoding
148        for (size_t i = 0; i < (bytesCount - 1); i += 2)
149        {
150#if SLANG_LITTLE_ENDIAN
151            const auto low = bytes[i];
152            const auto high = bytes[i + 1];
153#else
154            const auto low = bytes[i + 1];
155            const auto high = bytes[i];
156#endif
157            if ((low == 0) ^ (high == 0))
158            {
159                outOffset = 2;
160                return (high == 0) ? CharEncodeType::UTF16 : CharEncodeType::UTF16Reversed;
161            }
162        }
163    }
164
165    // Assume it's UTF8 or 7 bit ascii which UTF8 is a superset of
166    outOffset = 0;
167    return CharEncodeType::UTF8;
168}
169
170static Utf8CharEncoding _utf8Encoding;
171static Utf16CharEncoding _utf16Encoding(false);
172static Utf16CharEncoding _utf16EncodingReversed(true);
173static Utf32CharEncoding _utf32Encoding;
174
175/* static */ CharEncoding* const CharEncoding::g_encoding[Index(CharEncodeType::CountOf)]{
176    &_utf8Encoding,          // UTF8,
177    &_utf16Encoding,         // UTF16,
178    &_utf16EncodingReversed, // UTF16Reversed,
179    &_utf32Encoding,         // UTF32,
180};
181
182CharEncoding* CharEncoding::UTF8 = &_utf8Encoding;
183CharEncoding* CharEncoding::UTF16 = &_utf16Encoding;
184CharEncoding* CharEncoding::UTF16Reversed = &_utf16EncodingReversed;
185CharEncoding* CharEncoding::UTF32 = &_utf32Encoding;
186
187/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UTF8Util !!!!!!!!!!!!!!!!!!!!!!!!! */
188
189/* static */ Index UTF8Util::calcCodePointCount(const UnownedStringSlice& in)
190{
191    Index count = 0;
192
193    // Analyse with bytes...
194    const int8_t* cur = (const int8_t*)in.begin();
195    const int8_t* const end = (const int8_t*)in.end();
196
197    while (cur < end)
198    {
199        const auto c = *cur++;
200
201        count++;
202
203        // If c < 0 it means the top bit is set... which means we have multiple bytes
204        if (c < 0)
205        {
206            // https://en.wikipedia.org/wiki/UTF-8
207            // All continuation bytes contain exactly six bits from the code point.So the next six
208            // bits of the code point
209            /// are stored in the low order six bits of the next byte, and 10 is stored in the high
210            /// order two bits to
211            // mark it as a continuation byte(so 10000010).
212
213            while (cur < end && (*cur & 0xc0) == 0x80)
214            {
215                cur++;
216            }
217        }
218    }
219
220    return count;
221}
222
223Index UTF8Util::calcUTF16CharCount(const UnownedStringSlice& in)
224{
225    Index count = 0;
226    Index readPtr = 0;
227    for (;;)
228    {
229        int c = getUnicodePointFromUTF8(
230            [&]() -> Byte
231            {
232                if (readPtr < in.getLength())
233                    return in[readPtr++];
234                else
235                    return 0;
236            });
237        if (c == 0)
238            break;
239        Char16 buffer[2];
240        count += encodeUnicodePointToUTF16(c, buffer);
241        if (readPtr >= in.getLength())
242            break;
243    }
244    return count;
245}
246
247} // namespace Slang