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