• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &registry) {
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