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