lin
2025-08-01 633231e833e21d5b8b1c00cb15aedb62b3b78e8f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/*
 * Copyright (C) 2018 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.
 */
 
// Mechanism to instantiate classes by name.
//
// This mechanism is useful if the concrete classes to be instantiated are not
// statically known (e.g., if their names are read from a dynamically-provided
// config).
//
// In that case, the first step is to define the API implemented by the
// instantiated classes.  E.g.,
//
//  // In a header file function.h:
//
//  // Abstract function that takes a double and returns a double.
//  class Function : public RegisterableClass<Function> {
//   public:
//    virtual ~Function() {}
//    virtual double Evaluate(double x) = 0;
//  };
//
//  // Should be inside namespace libtextclassifier3::mobile.
//  SAFTM_DECLARE_CLASS_REGISTRY_NAME(Function);
//
// Notice the inheritance from RegisterableClass<Function>.  RegisterableClass
// is defined by this file (registry.h).  Under the hood, this inheritanace
// defines a "registry" that maps names (zero-terminated arrays of chars) to
// factory methods that create Functions.  You should give a human-readable name
// to this registry.  To do that, use the following macro in a .cc file (it has
// to be a .cc file, as it defines some static data):
//
//  // Inside function.cc
//  // Should be inside namespace libtextclassifier3::mobile.
//  SAFTM_DEFINE_CLASS_REGISTRY_NAME("function", Function);
//
// Now, let's define a few concrete Functions: e.g.,
//
//   class Cos : public Function {
//    public:
//     double Evaluate(double x) override { return cos(x); }
//     SAFTM_DEFINE_REGISTRATION_METHOD("cos", Cos);
//   };
//
//   class Exp : public Function {
//    public:
//     double Evaluate(double x) override { return exp(x); }
//     SAFTM_DEFINE_REGISTRATION_METHOD("sin", Sin);
//   };
//
// Each concrete Function implementation should have (in the public section) the
// macro
//
//   SAFTM_DEFINE_REGISTRATION_METHOD("name", implementation_class);
//
// This defines a RegisterClass static method that, when invoked, associates
// "name" with a factory method that creates instances of implementation_class.
//
// Before instantiating Functions by name, we need to tell our system which
// Functions we may be interested in.  This is done by calling the
// Foo::RegisterClass() for each relevant Foo implementation of Function.  It is
// ok to call Foo::RegisterClass() multiple times (even in parallel): only the
// first call will perform something, the others will return immediately.
//
//   Cos::RegisterClass();
//   Exp::RegisterClass();
//
// Now, let's instantiate a Function based on its name.  This get a lot more
// interesting if the Function name is not statically known (i.e.,
// read from an input proto:
//
//   std::unique_ptr<Function> f(Function::Create("cos"));
//   double result = f->Evaluate(arg);
//
// NOTE: the same binary can use this mechanism for different APIs.  E.g., one
// can also have (in the binary with Function, Sin, Cos, etc):
//
// class IntFunction : public RegisterableClass<IntFunction> {
//  public:
//   virtual ~IntFunction() {}
//   virtual int Evaluate(int k) = 0;
// };
//
// SAFTM_DECLARE_CLASS_REGISTRY_NAME(IntFunction);
//
// SAFTM_DEFINE_CLASS_REGISTRY_NAME("int function", IntFunction);
//
// class Inc : public IntFunction {
//  public:
//   int Evaluate(int k) override { return k + 1; }
//   SAFTM_DEFINE_REGISTRATION_METHOD("inc", Inc);
// };
//
// RegisterableClass<Function> and RegisterableClass<IntFunction> define their
// own registries: each maps string names to implementation of the corresponding
// API.
//
// NOTE: the mechanism described above requires you to explicitly call
// RegisterClass() for all relevant classes before instantiating them.  You can
// do this in the main() function or in any other function that is guaranteed to
// run before the code that instantiates those classes.  Alternatively, you can
// use the macro SAFTM_STATIC_REGISTRATION to perform this registration in a
// decentralized fashion.  Just use that macro in a .cc file, outside any
// function / class, e.g.,
//
// SAFTM_STATIC_REGISTRATION(Cos);
//
// and make sure you link in all symbols from that .cc file; e.g., in bazel, use
// alwayslink = 1 for the corresponding cc_library.  Still, please be aware that
// using alwayslink = 1 limits the ability of the linker to perform dead code
// elimination.
 
#ifndef NLP_SAFT_COMPONENTS_COMMON_MOBILE_REGISTRY_H_
#define NLP_SAFT_COMPONENTS_COMMON_MOBILE_REGISTRY_H_
 
#include <stdlib.h>
#include <string.h>
 
#include <string>
#include <vector>
 
#include "lang_id/common/lite_base/logging.h"
#include "lang_id/common/lite_base/macros.h"
 
namespace libtextclassifier3 {
namespace mobile {
 
namespace internal {
// Registry that associates keys (zero-terminated array of chars) with values.
// Values are pointers to type T (the template parameter).  This is used to
// store the association between component names and factory methods that
// produce those components; the error messages are focused on that case.
//
// Internally, this registry uses a linked list of (key, value) pairs.  We do
// not use an STL map, list, etc because we aim for small code size.
template <class T>
class ComponentRegistry {
 public:
  explicit ComponentRegistry(const char *name) : name_(name), head_(nullptr) {}
 
  // Adds a the (key, value) pair to this registry (if the key does not already
  // exists in this registry) and returns true.  If the registry already has a
  // mapping for key, returns false and does not modify the registry.  NOTE: the
  // error (false) case happens even if the existing value for key is equal with
  // the new one.
  //
  // This method does not take ownership of key, nor of value.
  bool Add(const char *key, T *value) {
    const Cell *old_cell = FindCell(key);
    if (old_cell != nullptr) {
      SAFTM_LOG(ERROR) << "Duplicate component: " << key;
      return false;
    }
    Cell *new_cell = new Cell(key, value, head_);
    head_ = new_cell;
    return true;
  }
 
  // Returns the value attached to a key in this registry.  Returns nullptr on
  // error (e.g., unknown key).
  T *Lookup(const char *key) const {
    const Cell *cell = FindCell(key);
    if (cell == nullptr) {
      SAFTM_LOG(ERROR) << "Unknown " << name() << " component: " << key;
    }
    return (cell == nullptr) ? nullptr : cell->value();
  }
 
  T *Lookup(const string &key) const { return Lookup(key.c_str()); }
 
  // Returns name of this ComponentRegistry.
  const char *name() const { return name_; }
 
  // Fills *names with names of all components registered in this
  // ComponentRegistry.  Previous content of *names is cleared out.
  void GetComponentNames(std::vector<string> *names) {
    names->clear();
    for (const Cell *c = head_; c!= nullptr; c = c->next()) {
      names->emplace_back(c->key());
    }
  }
 
 private:
  // Cell for the singly-linked list underlying this ComponentRegistry.  Each
  // cell contains a key, the value for that key, as well as a pointer to the
  // next Cell from the list.
  class Cell {
   public:
    // Constructs a new Cell.
    Cell(const char *key, T *value, Cell *next)
        : key_(key), value_(value), next_(next) {}
 
    const char *key() const { return key_; }
    T *value() const { return value_; }
    Cell *next() const { return next_; }
 
   private:
    const char *const key_;
    T *const value_;
    Cell *const next_;
  };
 
  // Finds Cell for indicated key in the singly-linked list pointed to by head_.
  // Returns pointer to that first Cell with that key, or nullptr if no such
  // Cell (i.e., unknown key).
  //
  // Caller does NOT own the returned pointer.
  const Cell *FindCell(const char *key) const {
    const Cell *c = head_;
    while (c != nullptr && strcmp(key, c->key()) != 0) {
      c = c->next();
    }
    return c;
  }
 
  // Human-readable description for this ComponentRegistry.  For debug purposes.
  const char *const name_;
 
  // Pointer to the first Cell from the underlying list of (key, value) pairs.
  Cell *head_;
};
}  // namespace internal
 
// Base class for registerable classes.
template <class T>
class RegisterableClass {
 public:
  // Factory function type.
  typedef T *(Factory)();
 
  // Registry type.
  typedef internal::ComponentRegistry<Factory> Registry;
 
  // Creates a new instance of T.  Returns pointer to new instance or nullptr in
  // case of errors (e.g., unknown component).
  //
  // Passes ownership of the returned pointer to the caller.
  static T *Create(const string &name) {  // NOLINT
    auto *factory = registry()->Lookup(name);
    if (factory == nullptr) {
      SAFTM_LOG(ERROR) << "Unknown RegisterableClass " << name;
      return nullptr;
    }
    return factory();
  }
 
  // Returns registry for class.
  static Registry *registry() {
    static Registry *registry_for_type_t = new Registry(kRegistryName);
    return registry_for_type_t;
  }
 
 protected:
  // Factory method for subclass ComponentClass.  Used internally by the static
  // method RegisterClass() defined by SAFTM_DEFINE_REGISTRATION_METHOD.
  template <class ComponentClass>
  static T *_internal_component_factory() {
    return new ComponentClass();
  }
 
 private:
  // Human-readable name for the registry for this class.
  static const char kRegistryName[];
};
 
// Defines the static method component_class::RegisterClass() that should be
// called before trying to instantiate component_class by name.  Should be used
// inside the public section of the declaration of component_class.  See
// comments at the top-level of this file.
#define SAFTM_DEFINE_REGISTRATION_METHOD(component_name, component_class) \
  static void RegisterClass() {                                         \
    static bool once = registry()->Add(                                 \
        component_name, &_internal_component_factory<component_class>); \
    if (!once) {                                                        \
      SAFTM_LOG(ERROR) << "Problem registering " << component_name;     \
    }                                                                   \
    SAFTM_DCHECK(once);                                                 \
  }
 
// Defines the human-readable name of the registry associated with base_class.
#define SAFTM_DECLARE_CLASS_REGISTRY_NAME(base_class)                   \
  template <>                                                           \
  const char ::libtextclassifier3::mobile::RegisterableClass<base_class>::kRegistryName[]
 
// Defines the human-readable name of the registry associated with base_class.
#define SAFTM_DEFINE_CLASS_REGISTRY_NAME(registry_name, base_class)     \
  template <>                                                           \
  const char                                                            \
  ::libtextclassifier3::mobile::RegisterableClass<base_class>::kRegistryName[]    \
      = registry_name
 
// Register component_name, by calling component_class::RegisterClass() on
// program start-up, before main.  NOTE: this macro should be used in
// conjunction with something like alwayslink = 1 from bazel.  That is
// discouraged, as it prevents the linker from doing dead code elimination, so
// please use this macro only in special cases.  Instead, if you care about code
// size, then you should aim to explicitly call RegisterClass from your code
// (e.g., from the main method, or from the constructor of the class that may
// need those registered components).
#define SAFTM_STATIC_REGISTRATION(component_class)                  \
  static bool SAFTM_UNIQUE_ID(_kRegistrationDummy) = [] {           \
    component_class::RegisterClass();                               \
    return true;                                                    \
  }()
 
}  // namespace mobile
}  // namespace nlp_saft
 
#endif  // NLP_SAFT_COMPONENTS_COMMON_MOBILE_REGISTRY_H_