Home | History | Annotate | Download | only in fel
      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.
     41   virtual ~Workspace() {}
     42 
     43  protected:
     44   // Create an empty 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.
     67   WorkspaceRegistry() {}
     68 
     69   // Returns the index of a named workspace, adding it to the registry first
     70   // if necessary.
     71   template <class W>
     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.
     85   int MaxId() const {
     86     return max_workspace_id_;
     87   }
     88 
     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:
    115   ~WorkspaceSet() { Reset(WorkspaceRegistry()); }
    116 
    117   // Returns true if a workspace has been set.
    118   template <class W>
    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>
    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>
    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 
    152   void Reset(const WorkspaceRegistry &registry) {
    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.
    188   int element(int i) const { return elements_[i]; }
    189 
    190   // Sets the i'th element.
    191   void set_element(int i, int value) { elements_[i] = value; }
    192 
    193   // Returns the size of the underlying vector.
    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