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