| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Notes on thread-safety: All of the classes here are thread-compatible. More |
| // specifically, the registry machinery is thread-safe, as long as each thread |
| // performs feature extraction on a different Sentence object. |
| |
| #ifndef LIBTEXTCLASSIFIER_COMMON_WORKSPACE_H_ |
| #define LIBTEXTCLASSIFIER_COMMON_WORKSPACE_H_ |
| |
| #include <stddef.h> |
| #include <string> |
| #include <unordered_map> |
| #include <utility> |
| #include <vector> |
| |
| #include "util/base/logging.h" |
| #include "util/base/macros.h" |
| |
| namespace libtextclassifier { |
| namespace nlp_core { |
| |
| // A base class for shared workspaces. Derived classes implement a static member |
| // function TypeName() which returns a human readable std::string name for the |
| // class. |
| class Workspace { |
| public: |
| // Polymorphic destructor. |
| virtual ~Workspace() {} |
| |
| protected: |
| // Create an empty workspace. |
| Workspace() {} |
| |
| private: |
| TC_DISALLOW_COPY_AND_ASSIGN(Workspace); |
| }; |
| |
| // Returns a new, strictly increasing int every time it is invoked. |
| int GetFreshTypeId(); |
| |
| // Struct to simulate typeid, but without RTTI. |
| template <typename T> |
| struct TypeId { |
| static int type_id; |
| }; |
| |
| template <typename T> |
| int TypeId<T>::type_id = GetFreshTypeId(); |
| |
| // A registry that keeps track of workspaces. |
| class WorkspaceRegistry { |
| public: |
| // Create an empty registry. |
| WorkspaceRegistry() {} |
| |
| // Returns the index of a named workspace, adding it to the registry first |
| // if necessary. |
| template <class W> |
| int Request(const std::string &name) { |
| const int id = TypeId<W>::type_id; |
| max_workspace_id_ = std::max(id, max_workspace_id_); |
| workspace_types_[id] = W::TypeName(); |
| std::vector<std::string> &names = workspace_names_[id]; |
| for (int i = 0; i < names.size(); ++i) { |
| if (names[i] == name) return i; |
| } |
| names.push_back(name); |
| return names.size() - 1; |
| } |
| |
| // Returns the maximum workspace id that has been registered. |
| int MaxId() const { |
| return max_workspace_id_; |
| } |
| |
| const std::unordered_map<int, std::vector<std::string> > &WorkspaceNames() |
| const { |
| return workspace_names_; |
| } |
| |
| // Returns a std::string describing the registered workspaces. |
| std::string DebugString() const; |
| |
| private: |
| // Workspace type names, indexed as workspace_types_[typeid]. |
| std::unordered_map<int, std::string> workspace_types_; |
| |
| // Workspace names, indexed as workspace_names_[typeid][workspace]. |
| std::unordered_map<int, std::vector<std::string> > workspace_names_; |
| |
| // The maximum workspace id that has been registered. |
| int max_workspace_id_ = 0; |
| |
| TC_DISALLOW_COPY_AND_ASSIGN(WorkspaceRegistry); |
| }; |
| |
| // A typed collected of workspaces. The workspaces are indexed according to an |
| // external WorkspaceRegistry. If the WorkspaceSet is const, the contents are |
| // also immutable. |
| class WorkspaceSet { |
| public: |
| ~WorkspaceSet() { Reset(WorkspaceRegistry()); } |
| |
| // Returns true if a workspace has been set. |
| template <class W> |
| bool Has(int index) const { |
| const int id = TypeId<W>::type_id; |
| TC_DCHECK_GE(id, 0); |
| TC_DCHECK_LT(id, workspaces_.size()); |
| TC_DCHECK_GE(index, 0); |
| TC_DCHECK_LT(index, workspaces_[id].size()); |
| if (id >= workspaces_.size()) return false; |
| return workspaces_[id][index] != nullptr; |
| } |
| |
| // Returns an indexed workspace; the workspace must have been set. |
| template <class W> |
| const W &Get(int index) const { |
| TC_DCHECK(Has<W>(index)); |
| const int id = TypeId<W>::type_id; |
| const Workspace *w = workspaces_[id][index]; |
| return reinterpret_cast<const W &>(*w); |
| } |
| |
| // Sets an indexed workspace; this takes ownership of the workspace, which |
| // must have been new-allocated. It is an error to set a workspace twice. |
| template <class W> |
| void Set(int index, W *workspace) { |
| const int id = TypeId<W>::type_id; |
| TC_DCHECK_GE(id, 0); |
| TC_DCHECK_LT(id, workspaces_.size()); |
| TC_DCHECK_GE(index, 0); |
| TC_DCHECK_LT(index, workspaces_[id].size()); |
| TC_DCHECK(workspaces_[id][index] == nullptr); |
| TC_DCHECK(workspace != nullptr); |
| workspaces_[id][index] = workspace; |
| } |
| |
| void Reset(const WorkspaceRegistry ®istry) { |
| // Deallocate current workspaces. |
| for (auto &it : workspaces_) { |
| for (size_t index = 0; index < it.size(); ++index) { |
| delete it[index]; |
| } |
| } |
| workspaces_.clear(); |
| workspaces_.resize(registry.MaxId() + 1, std::vector<Workspace *>()); |
| for (auto &it : registry.WorkspaceNames()) { |
| workspaces_[it.first].resize(it.second.size()); |
| } |
| } |
| |
| private: |
| // The set of workspaces, indexed as workspaces_[typeid][index]. |
| std::vector<std::vector<Workspace *> > workspaces_; |
| }; |
| |
| // A workspace that wraps around a single int. |
| class SingletonIntWorkspace : public Workspace { |
| public: |
| // Default-initializes the int value. |
| SingletonIntWorkspace() {} |
| |
| // Initializes the int with the given value. |
| explicit SingletonIntWorkspace(int value) : value_(value) {} |
| |
| // Returns the name of this type of workspace. |
| static std::string TypeName() { return "SingletonInt"; } |
| |
| // Returns the int value. |
| int get() const { return value_; } |
| |
| // Sets the int value. |
| void set(int value) { value_ = value; } |
| |
| private: |
| // The enclosed int. |
| int value_ = 0; |
| }; |
| |
| // A workspace that wraps around a vector of int. |
| class VectorIntWorkspace : public Workspace { |
| public: |
| // Creates a vector of the given size. |
| explicit VectorIntWorkspace(int size); |
| |
| // Creates a vector initialized with the given array. |
| explicit VectorIntWorkspace(const std::vector<int> &elements); |
| |
| // Creates a vector of the given size, with each element initialized to the |
| // given value. |
| VectorIntWorkspace(int size, int value); |
| |
| // Returns the name of this type of workspace. |
| static std::string TypeName(); |
| |
| // Returns the i'th element. |
| int element(int i) const { return elements_[i]; } |
| |
| // Sets the i'th element. |
| void set_element(int i, int value) { elements_[i] = value; } |
| |
| private: |
| // The enclosed vector. |
| std::vector<int> elements_; |
| }; |
| |
| // A workspace that wraps around a vector of vector of int. |
| class VectorVectorIntWorkspace : public Workspace { |
| public: |
| // Creates a vector of empty vectors of the given size. |
| explicit VectorVectorIntWorkspace(int size); |
| |
| // Returns the name of this type of workspace. |
| static std::string TypeName(); |
| |
| // Returns the i'th vector of elements. |
| const std::vector<int> &elements(int i) const { return elements_[i]; } |
| |
| // Mutable access to the i'th vector of elements. |
| std::vector<int> *mutable_elements(int i) { return &(elements_[i]); } |
| |
| private: |
| // The enclosed vector of vector of elements. |
| std::vector<std::vector<int> > elements_; |
| }; |
| |
| } // namespace nlp_core |
| } // namespace libtextclassifier |
| |
| #endif // LIBTEXTCLASSIFIER_COMMON_WORKSPACE_H_ |