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 #include <string> 26 #include <unordered_map> 27 #include <utility> 28 #include <vector> 29 30 #include "lang_id/common/lite_base/logging.h" 31 #include "lang_id/common/lite_base/macros.h" 32 33 namespace libtextclassifier3 { 34 namespace mobile { 35 36 // A base class for shared workspaces. Derived classes implement a static member 37 // function TypeName() which returns a human readable string name for the class. 38 class Workspace { 39 public: 40 // Polymorphic destructor. ~Workspace()41 virtual ~Workspace() {} 42 43 protected: 44 // Create an empty workspace. Workspace()45 Workspace() {} 46 47 private: 48 SAFTM_DISALLOW_COPY_AND_ASSIGN(Workspace); 49 }; 50 51 // Returns a new, strictly increasing int every time it is invoked. 52 int GetFreshTypeId(); 53 54 // Struct to simulate typeid, but without RTTI. 55 template <typename T> 56 struct TypeId { 57 static int type_id; 58 }; 59 60 template <typename T> 61 int TypeId<T>::type_id = GetFreshTypeId(); 62 63 // A registry that keeps track of workspaces. 64 class WorkspaceRegistry { 65 public: 66 // Create an empty registry. WorkspaceRegistry()67 WorkspaceRegistry() {} 68 69 // Returns the index of a named workspace, adding it to the registry first 70 // if necessary. 71 template <class W> Request(const string & name)72 int Request(const string &name) { 73 const int id = TypeId<W>::type_id; 74 max_workspace_id_ = std::max(id, max_workspace_id_); 75 workspace_types_[id] = W::TypeName(); 76 std::vector<string> &names = workspace_names_[id]; 77 for (int i = 0; i < names.size(); ++i) { 78 if (names[i] == name) return i; 79 } 80 names.push_back(name); 81 return names.size() - 1; 82 } 83 84 // Returns the maximum workspace id that has been registered. MaxId()85 int MaxId() const { 86 return max_workspace_id_; 87 } 88 WorkspaceNames()89 const std::unordered_map<int, std::vector<string> > &WorkspaceNames() 90 const { 91 return workspace_names_; 92 } 93 94 // Returns a string describing the registered workspaces. 95 string DebugString() const; 96 97 private: 98 // Workspace type names, indexed as workspace_types_[typeid]. 99 std::unordered_map<int, string> workspace_types_; 100 101 // Workspace names, indexed as workspace_names_[typeid][workspace]. 102 std::unordered_map<int, std::vector<string> > workspace_names_; 103 104 // The maximum workspace id that has been registered. 105 int max_workspace_id_ = 0; 106 107 SAFTM_DISALLOW_COPY_AND_ASSIGN(WorkspaceRegistry); 108 }; 109 110 // A typed collected of workspaces. The workspaces are indexed according to an 111 // external WorkspaceRegistry. If the WorkspaceSet is const, the contents are 112 // also immutable. 113 class WorkspaceSet { 114 public: ~WorkspaceSet()115 ~WorkspaceSet() { Reset(WorkspaceRegistry()); } 116 117 // Returns true if a workspace has been set. 118 template <class W> Has(int index)119 bool Has(int index) const { 120 const int id = TypeId<W>::type_id; 121 SAFTM_DCHECK_GE(id, 0); 122 SAFTM_DCHECK_LT(id, workspaces_.size()); 123 SAFTM_DCHECK_GE(index, 0); 124 SAFTM_DCHECK_LT(index, workspaces_[id].size()); 125 if (id >= workspaces_.size()) return false; 126 return workspaces_[id][index] != nullptr; 127 } 128 129 // Returns an indexed workspace; the workspace must have been set. 130 template <class W> Get(int index)131 const W &Get(int index) const { 132 SAFTM_DCHECK(Has<W>(index)); 133 const int id = TypeId<W>::type_id; 134 const Workspace *w = workspaces_[id][index]; 135 return reinterpret_cast<const W &>(*w); 136 } 137 138 // Sets an indexed workspace; this takes ownership of the workspace, which 139 // must have been new-allocated. It is an error to set a workspace twice. 140 template <class W> Set(int index,W * workspace)141 void Set(int index, W *workspace) { 142 const int id = TypeId<W>::type_id; 143 SAFTM_DCHECK_GE(id, 0); 144 SAFTM_DCHECK_LT(id, workspaces_.size()); 145 SAFTM_DCHECK_GE(index, 0); 146 SAFTM_DCHECK_LT(index, workspaces_[id].size()); 147 SAFTM_DCHECK(workspaces_[id][index] == nullptr); 148 SAFTM_DCHECK(workspace != nullptr); 149 workspaces_[id][index] = workspace; 150 } 151 Reset(const WorkspaceRegistry & registry)152 void Reset(const WorkspaceRegistry ®istry) { 153 // Deallocate current workspaces. 154 for (auto &it : workspaces_) { 155 for (size_t index = 0; index < it.size(); ++index) { 156 delete it[index]; 157 } 158 } 159 workspaces_.clear(); 160 workspaces_.resize(registry.MaxId() + 1, std::vector<Workspace *>()); 161 for (auto &it : registry.WorkspaceNames()) { 162 workspaces_[it.first].resize(it.second.size()); 163 } 164 } 165 166 private: 167 // The set of workspaces, indexed as workspaces_[typeid][index]. 168 std::vector<std::vector<Workspace *> > workspaces_; 169 }; 170 171 // A workspace that wraps around a vector of int. 172 class VectorIntWorkspace : public Workspace { 173 public: 174 // Creates a vector of the given size. 175 explicit VectorIntWorkspace(int size); 176 177 // Creates a vector initialized with the given array. 178 explicit VectorIntWorkspace(const std::vector<int> &elements); 179 180 // Creates a vector of the given size, with each element initialized to the 181 // given value. 182 VectorIntWorkspace(int size, int value); 183 184 // Returns the name of this type of workspace. 185 static string TypeName(); 186 187 // Returns the i'th element. element(int i)188 int element(int i) const { return elements_[i]; } 189 190 // Sets the i'th element. set_element(int i,int value)191 void set_element(int i, int value) { elements_[i] = value; } 192 193 // Returns the size of the underlying vector. size()194 int size() const { return elements_.size(); } 195 196 private: 197 // The enclosed vector. 198 std::vector<int> elements_; 199 }; 200 201 } // namespace mobile 202 } // namespace nlp_saft 203 204 #endif // NLP_SAFT_COMPONENTS_COMMON_MOBILE_FEL_WORKSPACE_H_ 205