1 /*
2  * Copyright 2020 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SKSL_DEHYDRATOR
9 #define SKSL_DEHYDRATOR
10 
11 #ifdef SKSL_STANDALONE
12 
13 #include "include/core/SkSpan.h"
14 #include "include/private/SkSLModifiers.h"
15 #include "include/private/SkSLSymbol.h"
16 #include "include/private/SkTHash.h"
17 #include "src/sksl/SkSLOutputStream.h"
18 #include "src/sksl/SkSLStringStream.h"
19 
20 #include <set>
21 #include <unordered_map>
22 #include <vector>
23 
24 namespace SkSL {
25 
26 class AnyConstructor;
27 class Expression;
28 class ProgramElement;
29 class Statement;
30 class Symbol;
31 class SymbolTable;
32 
33 // The file has the structure:
34 //
35 // uint16 total string length
36 // string data
37 // symboltable
38 // elements
39 class Dehydrator {
40 public:
Dehydrator()41     Dehydrator() {
42         fSymbolMap.emplace_back();
43     }
44 
~Dehydrator()45     ~Dehydrator() {
46         SkASSERT(fSymbolMap.size() == 1);
47     }
48 
49     void write(const SymbolTable& symbols);
50 
51     void write(const std::vector<std::unique_ptr<ProgramElement>>& elements);
52 
53     void finish(OutputStream& out);
54 
55     // Inserts line breaks at meaningful offsets.
56     const char* prefixAtOffset(size_t byte);
57 
58 private:
writeS8(int32_t i)59     void writeS8(int32_t i) {
60         SkASSERT(i >= -128 && i <= 127);
61         fBody.write8(i);
62     }
63 
writeCommand(int32_t c)64     void writeCommand(int32_t c) {
65         fCommandBreaks.add(fBody.bytesWritten());
66         fBody.write8(c);
67     }
68 
writeU8(int32_t i)69     void writeU8(int32_t i) {
70         SkASSERT(i >= 0 && i <= 255);
71         fBody.write8(i);
72     }
73 
writeS16(int32_t i)74     void writeS16(int32_t i) {
75         SkASSERT(i >= -32768 && i <= 32767);
76         fBody.write16(i);
77     }
78 
writeU16(int32_t i)79     void writeU16(int32_t i) {
80         SkASSERT(i >= 0 && i <= 65535);
81         fBody.write16(i);
82     }
83 
writeS32(int64_t i)84     void writeS32(int64_t i) {
85         SkASSERT(i >= -2147483648 && i <= 2147483647);
86         fBody.write32(i);
87     }
88 
writeId(const Symbol * s)89     void writeId(const Symbol* s) {
90         if (!symbolId(s, false)) {
91             fSymbolMap.back()[s] = fNextId++;
92         }
93         this->writeU16(symbolId(s));
94     }
95 
96     uint16_t symbolId(const Symbol* s, bool required = true) {
97         for (const auto& symbols : fSymbolMap) {
98             auto found = symbols.find(s);
99             if (found != symbols.end()) {
100                 return found->second;
101             }
102         }
103         SkASSERT(!required);
104         return 0;
105     }
106 
107     void write(Layout l);
108 
109     void write(Modifiers m);
110 
111     void write(StringFragment s);
112 
113     void write(String s);
114 
115     void write(const ProgramElement& e);
116 
117     void write(const Expression* e);
118 
119     void write(const Statement* s);
120 
121     void write(const Symbol& s);
122 
123     void writeExpressionSpan(const SkSpan<const std::unique_ptr<Expression>>& span);
124 
125     uint16_t fNextId = 1;
126 
127     StringStream fStringBuffer;
128 
129     StringStream fBody;
130 
131     std::unordered_map<String, int> fStrings;
132 
133     std::vector<std::unordered_map<const Symbol*, int>> fSymbolMap;
134     SkTHashSet<size_t> fStringBreaks;
135     SkTHashSet<size_t> fCommandBreaks;
136     size_t fStringBufferStart;
137     size_t fCommandStart;
138 
139     friend class AutoDehydratorSymbolTable;
140 };
141 
142 } // namespace
143 
144 #endif
145 
146 #endif
147