• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
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_SYMBOLTABLE
9 #define SKSL_SYMBOLTABLE
10 
11 #include "include/core/SkTypes.h"
12 #include "include/private/SkOpts_spi.h"
13 #include "include/private/SkSLSymbol.h"
14 #include "src/core/SkTHash.h"
15 
16 #include <cstddef>
17 #include <cstdint>
18 #include <forward_list>
19 #include <memory>
20 #include <string>
21 #include <string_view>
22 #include <type_traits>
23 #include <utility>
24 #include <vector>
25 
26 namespace SkSL {
27 
28 class Type;
29 
30 /**
31  * Maps identifiers to symbols.
32  */
33 class SymbolTable {
34 public:
SymbolTable(bool builtin)35     explicit SymbolTable(bool builtin)
36             : fBuiltin(builtin) {}
37 
SymbolTable(std::shared_ptr<SymbolTable> parent,bool builtin)38     explicit SymbolTable(std::shared_ptr<SymbolTable> parent, bool builtin)
39             : fParent(parent)
40             , fBuiltin(builtin) {}
41 
42     /** Replaces the passed-in SymbolTable with a newly-created child symbol table. */
Push(std::shared_ptr<SymbolTable> * table)43     static void Push(std::shared_ptr<SymbolTable>* table) {
44         Push(table, (*table)->isBuiltin());
45     }
Push(std::shared_ptr<SymbolTable> * table,bool isBuiltin)46     static void Push(std::shared_ptr<SymbolTable>* table, bool isBuiltin) {
47         *table = std::make_shared<SymbolTable>(*table, isBuiltin);
48     }
49 
50     /**
51      * Replaces the passed-in SymbolTable with its parent. If the child symbol table is otherwise
52      * unreferenced, it will be deleted.
53      */
Pop(std::shared_ptr<SymbolTable> * table)54     static void Pop(std::shared_ptr<SymbolTable>* table) {
55         *table = (*table)->fParent;
56     }
57 
58     /**
59      * If the input is a built-in symbol table, returns a new empty symbol table as a child of the
60      * input table. If the input is not a built-in symbol table, returns it as-is. Built-in symbol
61      * tables must not be mutated after creation, so they must be wrapped if mutation is necessary.
62      */
WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable)63     static std::shared_ptr<SymbolTable> WrapIfBuiltin(std::shared_ptr<SymbolTable> symbolTable) {
64         if (!symbolTable) {
65             return nullptr;
66         }
67         if (!symbolTable->isBuiltin()) {
68             return symbolTable;
69         }
70         return std::make_shared<SymbolTable>(std::move(symbolTable), /*builtin=*/false);
71     }
72 
73     /**
74      * Looks up the requested symbol and returns a const pointer.
75      */
find(std::string_view name)76     const Symbol* find(std::string_view name) const {
77         return this->lookup(MakeSymbolKey(name));
78     }
79 
80     /**
81      * Looks up the requested symbol, only searching the built-in symbol tables. Always const.
82      */
83     const Symbol* findBuiltinSymbol(std::string_view name) const;
84 
85     /**
86      * Looks up the requested symbol and returns a mutable pointer. Use caution--mutating a symbol
87      * will have program-wide impact, and built-in symbol tables must never be mutated.
88      */
findMutable(std::string_view name)89     Symbol* findMutable(std::string_view name) const {
90         return this->lookup(MakeSymbolKey(name));
91     }
92 
93     /**
94      * Assigns a new name to the passed-in symbol. The old name will continue to exist in the symbol
95      * table and point to the symbol.
96      */
97     void renameSymbol(Symbol* symbol, std::string_view newName);
98 
99     /**
100      * Returns true if the name refers to a type (user or built-in) in the current symbol table.
101      */
102     bool isType(std::string_view name) const;
103 
104     /**
105      * Returns true if the name refers to a builtin type.
106      */
107     bool isBuiltinType(std::string_view name) const;
108 
109     /**
110      * Adds a symbol to this symbol table, without conferring ownership. The caller is responsible
111      * for keeping the Symbol alive throughout the lifetime of the program/module.
112      */
113     void addWithoutOwnership(Symbol* symbol);
114 
115     /**
116      * Adds a symbol to this symbol table, conferring ownership.
117      */
118     template <typename T>
add(std::unique_ptr<T> symbol)119     T* add(std::unique_ptr<T> symbol) {
120         T* ptr = symbol.get();
121         this->addWithoutOwnership(this->takeOwnershipOfSymbol(std::move(symbol)));
122         return ptr;
123     }
124 
125     /**
126      * Forces a symbol into this symbol table, without conferring ownership. Replaces any existing
127      * symbol with the same name, if one exists.
128      */
129     void injectWithoutOwnership(Symbol* symbol);
130 
131     /**
132      * Forces a symbol into this symbol table, conferring ownership. Replaces any existing symbol
133      * with the same name, if one exists.
134      */
135     template <typename T>
inject(std::unique_ptr<T> symbol)136     T* inject(std::unique_ptr<T> symbol) {
137         T* ptr = symbol.get();
138         this->injectWithoutOwnership(this->takeOwnershipOfSymbol(std::move(symbol)));
139         return ptr;
140     }
141 
142     /**
143      * Confers ownership of a symbol without adding its name to the lookup table.
144      */
145     template <typename T>
takeOwnershipOfSymbol(std::unique_ptr<T> symbol)146     T* takeOwnershipOfSymbol(std::unique_ptr<T> symbol) {
147         T* ptr = symbol.get();
148         fOwnedSymbols.push_back(std::move(symbol));
149         return ptr;
150     }
151 
152     /**
153      * Given type = `float` and arraySize = 5, creates the array type `float[5]` in the symbol
154      * table. The created array type is returned. If zero is passed, the base type is returned
155      * unchanged.
156      */
157     const Type* addArrayDimension(const Type* type, int arraySize);
158 
159     // Call fn for every symbol in the table.  You may not mutate anything.
160     template <typename Fn>
foreach(Fn && fn)161     void foreach(Fn&& fn) const {
162         fSymbols.foreach(
163                 [&fn](const SymbolKey& key, const Symbol* symbol) { fn(key.fName, symbol); });
164     }
165 
count()166     size_t count() {
167         return fSymbols.count();
168     }
169 
170     /** Returns true if this is a built-in SymbolTable. */
isBuiltin()171     bool isBuiltin() const {
172         return fBuiltin;
173     }
174 
175     const std::string* takeOwnershipOfString(std::string n);
176 
177     /**
178      * Indicates that this symbol table's parent is in a different module than this one.
179      */
markModuleBoundary()180     void markModuleBoundary() {
181         fAtModuleBoundary = true;
182     }
183 
184     std::shared_ptr<SymbolTable> fParent;
185 
186     std::vector<std::unique_ptr<const Symbol>> fOwnedSymbols;
187 
188 private:
189     struct SymbolKey {
190         std::string_view fName;
191         uint32_t         fHash;
192 
193         bool operator==(const SymbolKey& that) const { return fName == that.fName; }
194         bool operator!=(const SymbolKey& that) const { return fName != that.fName; }
195         struct Hash {
operatorSymbolKey::Hash196             uint32_t operator()(const SymbolKey& key) const { return key.fHash; }
197         };
198     };
199 
MakeSymbolKey(std::string_view name)200     static SymbolKey MakeSymbolKey(std::string_view name) {
201         return SymbolKey{name, SkOpts::hash_fn(name.data(), name.size(), 0)};
202     }
203 
204     Symbol* lookup(const SymbolKey& key) const;
205 
206     bool fBuiltin = false;
207     bool fAtModuleBoundary = false;
208     std::forward_list<std::string> fOwnedStrings;
209     SkTHashMap<SymbolKey, Symbol*, SymbolKey::Hash> fSymbols;
210 };
211 
212 }  // namespace SkSL
213 
214 #endif
215