1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Notes on thread-safety: All of the classes here are thread-compatible. More 18 // specifically, the registry machinery is thread-safe, as long as each thread 19 // performs feature extraction on a different Sentence object. 20 21 #ifndef NLP_SAFT_COMPONENTS_COMMON_MOBILE_FEL_WORKSPACE_H_ 22 #define NLP_SAFT_COMPONENTS_COMMON_MOBILE_FEL_WORKSPACE_H_ 23 24 #include <stddef.h> 25 26 #include <string> 27 #include <unordered_map> 28 #include <utility> 29 #include <vector> 30 31 #include "lang_id/common/lite_base/logging.h" 32 #include "lang_id/common/lite_base/macros.h" 33 34 namespace libtextclassifier3 { 35 namespace mobile { 36 37 // A base class for shared workspaces. Derived classes implement a static member 38 // function TypeName() which returns a human readable string name for the class. 39 class Workspace { 40 public: 41 // Polymorphic destructor. ~Workspace()42 virtual ~Workspace() {} 43 44 protected: 45 // Create an empty workspace. Workspace()46 Workspace() {} 47 48 private: 49 SAFTM_DISALLOW_COPY_AND_ASSIGN(Workspace); 50 }; 51 52 // Returns a new, strictly increasing int every time it is invoked. 53 int GetFreshTypeId(); 54 55 // Struct to simulate typeid, but without RTTI. 56 template <typename T> 57 struct TypeId { 58 static int type_id; 59 }; 60 61 template <typename T> 62 int TypeId<T>::type_id = GetFreshTypeId(); 63 64 // A registry that keeps track of workspaces. 65 class WorkspaceRegistry { 66 public: 67 // Create an empty registry. WorkspaceRegistry()68 WorkspaceRegistry() {} 69 70 // Returns the index of a named workspace, adding it to the registry first 71 // if necessary. 72 template <class W> Request(const std::string & name)73 int Request(const std::string &name) { 74 const int id = TypeId<W>::type_id; 75 max_workspace_id_ = std::max(id, max_workspace_id_); 76 workspace_types_[id] = W::TypeName(); 77 std::vector<std::string> &names = workspace_names_[id]; 78 for (int i = 0; i < names.size(); ++i) { 79 if (names[i] == name) return i; 80 } 81 names.push_back(name); 82 return names.size() - 1; 83 } 84 85 // Returns the maximum workspace id that has been registered. MaxId()86 int MaxId() const { 87 return max_workspace_id_; 88 } 89 WorkspaceNames()90 const std::unordered_map<int, std::vector<std::string> > &WorkspaceNames() 91 const { 92 return workspace_names_; 93 } 94 95 // Returns a string describing the registered workspaces. 96 std::string DebugString() const; 97 98 private: 99 // Workspace type names, indexed as workspace_types_[typeid]. 100 std::unordered_map<int, std::string> workspace_types_; 101 102 // Workspace names, indexed as workspace_names_[typeid][workspace]. 103 std::unordered_map<int, std::vector<std::string> > workspace_names_; 104 105 // The maximum workspace id that has been registered. 106 int max_workspace_id_ = 0; 107 108 SAFTM_DISALLOW_COPY_AND_ASSIGN(WorkspaceRegistry); 109 }; 110 111 // A typed collected of workspaces. The workspaces are indexed according to an 112 // external WorkspaceRegistry. If the WorkspaceSet is const, the contents are 113 // also immutable. 114 class WorkspaceSet { 115 public: ~WorkspaceSet()116 ~WorkspaceSet() { Reset(WorkspaceRegistry()); } 117 118 // Returns true if a workspace has been set. 119 template <class W> Has(int index)120 bool Has(int index) const { 121 const int id = TypeId<W>::type_id; 122 SAFTM_DCHECK_GE(id, 0); 123 SAFTM_DCHECK_LT(id, workspaces_.size()); 124 SAFTM_DCHECK_GE(index, 0); 125 SAFTM_DCHECK_LT(index, workspaces_[id].size()); 126 if (id >= workspaces_.size()) return false; 127 return workspaces_[id][index] != nullptr; 128 } 129 130 // Returns an indexed workspace; the workspace must have been set. 131 template <class W> Get(int index)132 const W &Get(int index) const { 133 SAFTM_DCHECK(Has<W>(index)); 134 const int id = TypeId<W>::type_id; 135 const Workspace *w = workspaces_[id][index]; 136 return reinterpret_cast<const W &>(*w); 137 } 138 139 // Sets an indexed workspace; this takes ownership of the workspace, which 140 // must have been new-allocated. It is an error to set a workspace twice. 141 template <class W> Set(int index,W * workspace)142 void Set(int index, W *workspace) { 143 const int id = TypeId<W>::type_id; 144 SAFTM_DCHECK_GE(id, 0); 145 SAFTM_DCHECK_LT(id, workspaces_.size()); 146 SAFTM_DCHECK_GE(index, 0); 147 SAFTM_DCHECK_LT(index, workspaces_[id].size()); 148 SAFTM_DCHECK(workspaces_[id][index] == nullptr); 149 SAFTM_DCHECK(workspace != nullptr); 150 workspaces_[id][index] = workspace; 151 } 152 Reset(const WorkspaceRegistry & registry)153 void Reset(const WorkspaceRegistry ®istry) { 154 // Deallocate current workspaces. 155 for (auto &it : workspaces_) { 156 for (size_t index = 0; index < it.size(); ++index) { 157 delete it[index]; 158 } 159 } 160 workspaces_.clear(); 161 workspaces_.resize(registry.MaxId() + 1, std::vector<Workspace *>()); 162 for (auto &it : registry.WorkspaceNames()) { 163 workspaces_[it.first].resize(it.second.size()); 164 } 165 } 166 167 private: 168 // The set of workspaces, indexed as workspaces_[typeid][index]. 169 std::vector<std::vector<Workspace *> > workspaces_; 170 }; 171 172 // A workspace that wraps around a vector of int. 173 class VectorIntWorkspace : public Workspace { 174 public: 175 // Creates a vector of the given size. 176 explicit VectorIntWorkspace(int size); 177 178 // Creates a vector initialized with the given array. 179 explicit VectorIntWorkspace(const std::vector<int> &elements); 180 181 // Creates a vector of the given size, with each element initialized to the 182 // given value. 183 VectorIntWorkspace(int size, int value); 184 185 // Returns the name of this type of workspace. 186 static std::string TypeName(); 187 188 // Returns the i'th element. element(int i)189 int element(int i) const { return elements_[i]; } 190 191 // Sets the i'th element. set_element(int i,int value)192 void set_element(int i, int value) { elements_[i] = value; } 193 194 // Returns the size of the underlying vector. size()195 int size() const { return elements_.size(); } 196 197 private: 198 // The enclosed vector. 199 std::vector<int> elements_; 200 }; 201 202 } // namespace mobile 203 } // namespace nlp_saft 204 205 #endif // NLP_SAFT_COMPONENTS_COMMON_MOBILE_FEL_WORKSPACE_H_ 206