aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/objects/identifiable.h
blob: b012fc2ee45b5661b2437dc83446b78e6385b561 (plain) (blame)
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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
/**
 * \class vespalib::Identifiable
 * \ingroup util
 *
 * \brief Superclass for objects adding some runtime type information.
 *
 * This class is a superclass used by many other classes to add some runtime
 * information.
 *
 * This can be used to verify type to be able to do cheap static casts
 * instead of dynamic casts. It can be used to identify type of object, and
 * it can also be used to generate an object of the given type (If it's not
 * an identifiable abstract type).
 *
 */

#define CID_Identifiable 1

#include "ids.h"
#include "nboserializer.h"
#include "objectvisitor.h"

#include <vespa/vespalib/util/memory.h>

#define IDENTIFIABLE_CLASSID(cclass) CID_##cclass
#define IDENTIFIABLE_CLASSID_NS(ns, cclass) CID_##ns##_##cclass
#define IDENTIFIABLE_CLASSID_NS2(ns1, ns2, cclass) CID_##ns1##_##ns2##_##cclass
#define IDENTIFIABLE_CLASSID_NS3(ns1, ns2, ns3, cclass) CID_##ns1##_##ns2##_##ns3##_##cclass

#define DECLARE_IDENTIFIABLE_STATIC_BASE_COMMON(cclass) \
  static  vespalib::Identifiable::RuntimeInfo  _RTInfo; \
  static  vespalib::Identifiable::RuntimeClass _RTClass; \
  static const std::type_info & typeId() { return typeid(cclass); } \
  static bool tryCast(const vespalib::Identifiable * v) { return dynamic_cast<const cclass *>(v) != NULL; } \
  static cclass *identifyClassAsIdentifiable() { return NULL; } /* no implementation */

#define DECLARE_IDENTIFIABLE_BASE_COMMON(cclass) \
  DECLARE_IDENTIFIABLE_STATIC_BASE_COMMON(cclass) \
  const vespalib::Identifiable::RuntimeClass & getClass() const override;

#define DECLARE_IDENTIFIABLE_BASE_COMMON_ROOT(cclass) \
  DECLARE_IDENTIFIABLE_STATIC_BASE_COMMON(cclass) \
  virtual const vespalib::Identifiable::RuntimeClass & getClass() const;

#define DECLARE_IDENTIFIABLE_BASE(cclass, classid) \
  public:                                          \
   enum { classId=classid };                       \
  DECLARE_IDENTIFIABLE_BASE_COMMON(cclass)

#define DECLARE_IDENTIFIABLE_BASE_ROOT(cclass, classid) \
  public:                                          \
   enum { classId=classid };                       \
  DECLARE_IDENTIFIABLE_BASE_COMMON_ROOT(cclass)

#define DECLARE_IDENTIFIABLE_ABSTRACT(cclass)               DECLARE_IDENTIFIABLE_BASE(cclass, IDENTIFIABLE_CLASSID(cclass))
#define DECLARE_IDENTIFIABLE_ABSTRACT_NS(ns, cclass)        DECLARE_IDENTIFIABLE_BASE(ns::cclass, IDENTIFIABLE_CLASSID_NS(ns, cclass))
#define DECLARE_IDENTIFIABLE_ABSTRACT_NS2(ns1, ns2, cclass) DECLARE_IDENTIFIABLE_BASE(ns1::ns2::cclass, IDENTIFIABLE_CLASSID_NS2(ns1, ns2, cclass))
#define DECLARE_IDENTIFIABLE_ABSTRACT_NS3(ns1, ns2, ns3, cclass) DECLARE_IDENTIFIABLE_BASE(ns1::ns2::ns3::cclass, IDENTIFIABLE_CLASSID_NS3(ns1, ns2, ns3, cclass))

#define DECLARE_IDENTIFIABLE_STATIC_COMMON(cclass)                               \
  static cclass *       create()               { return new cclass(); }          \
  static Identifiable * createAsIdentifiable() { return cclass::create(); }

#define DECLARE_IDENTIFIABLE_COMMON(cclass)                  \
  void assign(const vespalib::Identifiable & rhs) override;  \
  DECLARE_IDENTIFIABLE_STATIC_COMMON(cclass)

#define DECLARE_IDENTIFIABLE_COMMON_ROOT(cclass)            \
  virtual void assign(const vespalib::Identifiable & rhs);  \
  DECLARE_IDENTIFIABLE_STATIC_COMMON(cclass)

#define DECLARE_IDENTIFIABLE(cclass)                                             \
  DECLARE_IDENTIFIABLE_BASE(cclass, IDENTIFIABLE_CLASSID(cclass))                \
  DECLARE_IDENTIFIABLE_COMMON(cclass)

#define DECLARE_IDENTIFIABLE_ROOT(cclass)                                             \
  DECLARE_IDENTIFIABLE_BASE_ROOT(cclass, IDENTIFIABLE_CLASSID(cclass))                \
  DECLARE_IDENTIFIABLE_COMMON_ROOT(cclass)

#define DECLARE_IDENTIFIABLE_NS(ns, cclass)                                      \
  DECLARE_IDENTIFIABLE_BASE(ns::cclass, IDENTIFIABLE_CLASSID_NS(ns, cclass))     \
  DECLARE_IDENTIFIABLE_COMMON(ns::cclass)

#define DECLARE_IDENTIFIABLE_NS2(ns1, ns2, cclass)                               \
  DECLARE_IDENTIFIABLE_BASE(ns1::ns2::cclass, IDENTIFIABLE_CLASSID_NS2(ns1, ns2, cclass))            \
  DECLARE_IDENTIFIABLE_COMMON(ns1::ns2::cclass)

#define DECLARE_IDENTIFIABLE_NS3(ns1, ns2, ns3, cclass)                          \
  DECLARE_IDENTIFIABLE_BASE(ns1::ns2::ns3::cclass, IDENTIFIABLE_CLASSID_NS3(ns1, ns2, ns3, cclass))   \
  DECLARE_IDENTIFIABLE_COMMON(ns1::ns2::ns3::cclass)

#define  IMPLEMENT_IDENTIFIABLE_COMMON(cclass) \
  vespalib::Identifiable::RuntimeClass cclass::_RTClass(&_RTInfo);                                                     \
  const vespalib::Identifiable::RuntimeClass & cclass::getClass() const { return _RTClass; }

#define  IMPLEMENT_IDENTIFIABLE_CONCRET(cclass)               \
  void cclass::assign(const vespalib::Identifiable & rhs) {   \
      if (rhs.inherits(classId)) {                            \
          *this = static_cast<const cclass &>(rhs);           \
      }                                                       \
   }

#define IMPLEMENT_IDENTIFIABLE_BASE(cclass, name, base, id, factory, ctypeInfo, tryCast, typeinfo)                                \
  vespalib::Identifiable::RuntimeInfo  cclass::_RTInfo = {name, typeinfo, id, factory, ctypeInfo, tryCast, &base::_RTInfo }; \
  IMPLEMENT_IDENTIFIABLE_COMMON(cclass)

#define IMPLEMENT_IDENTIFIABLE_ABSTRACT(cclass, base)  \
  IMPLEMENT_IDENTIFIABLE_BASE(cclass, #cclass, base, IDENTIFIABLE_CLASSID(cclass), \
                              NULL, cclass::typeId, cclass::tryCast, "")
#define IMPLEMENT_IDENTIFIABLE(cclass, base) \
  IMPLEMENT_IDENTIFIABLE_CONCRET(cclass)           \
  IMPLEMENT_IDENTIFIABLE_BASE(cclass, #cclass, base, IDENTIFIABLE_CLASSID(cclass), \
                              cclass::createAsIdentifiable, cclass::typeId, cclass::tryCast, "")
#define IMPLEMENT_IDENTIFIABLE_ABSTRACT_NS(ns, cclass, base) \
  IMPLEMENT_IDENTIFIABLE_BASE(ns::cclass, #ns"::"#cclass, base, IDENTIFIABLE_CLASSID_NS(ns, cclass), \
                              NULL, cclass::typeId, cclass::tryCast, "")
#define IMPLEMENT_IDENTIFIABLE_NS(ns, cclass, base) \
  IMPLEMENT_IDENTIFIABLE_CONCRET(ns::cclass)           \
  IMPLEMENT_IDENTIFIABLE_BASE(ns::cclass, #ns"::"#cclass, base, IDENTIFIABLE_CLASSID_NS(ns, cclass), \
                              cclass::createAsIdentifiable, cclass::typeId, cclass::tryCast, "")
#define IMPLEMENT_IDENTIFIABLE_ABSTRACT_NS2(ns1, ns2, cclass, base) \
  IMPLEMENT_IDENTIFIABLE_BASE(ns1::ns2::cclass, #ns1"::"#ns2"::"#cclass, base, IDENTIFIABLE_CLASSID_NS2(ns1, ns2, cclass), \
                              NULL, cclass::typeId, cclass::tryCast, "")
#define IMPLEMENT_IDENTIFIABLE_NS2(ns1, ns2, cclass, base) \
  IMPLEMENT_IDENTIFIABLE_CONCRET(ns1::ns2::cclass)           \
  IMPLEMENT_IDENTIFIABLE_BASE(ns1::ns2::cclass, #ns1"::"#ns2"::"#cclass, base, IDENTIFIABLE_CLASSID_NS2(ns1, ns2, cclass), \
                              cclass::createAsIdentifiable, cclass::typeId, cclass::tryCast, "")
#define IMPLEMENT_IDENTIFIABLE_ABSTRACT_NS3(ns1, ns2, ns3, cclass, base) \
  IMPLEMENT_IDENTIFIABLE_BASE(ns1::ns2::ns3::cclass, #ns1"::"#ns2"::"#ns3"::"#cclass, base, IDENTIFIABLE_CLASSID_NS3(ns1, ns2, ns3, cclass), \
                              NULL, cclass::typeId, cclass::tryCast, "")
#define IMPLEMENT_IDENTIFIABLE_NS3(ns1, ns2, ns3, cclass, base) \
  IMPLEMENT_IDENTIFIABLE_CONCRET(ns1::ns2::ns3::cclass)           \
  IMPLEMENT_IDENTIFIABLE_BASE(ns1::ns2::ns3::cclass, #ns1"::"#ns2"::"#ns3"::"#cclass, base, IDENTIFIABLE_CLASSID_NS3(ns1, ns2, ns3, cclass), \
                              cclass::createAsIdentifiable, cclass::typeId, cclass::tryCast, "")

#define DECLARE_NBO_SERIALIZE                            \
    vespalib::Serializer & onSerialize(vespalib::Serializer & os) const override; \
    vespalib::Deserializer & onDeserialize(vespalib::Deserializer & is) override;


namespace vespalib {

class ObjectPredicate;
class ObjectOperation;

class Identifiable {
 protected:
    struct  RuntimeInfo {
        const char              * _name;
        const char              * _info;
        unsigned                  _id;
        Identifiable         * (* _factory)();
        const std::type_info & (* _typeId)();
        bool                   (* _tryCast)(const Identifiable *);
      const RuntimeInfo       * _base;
    };
public:
    using UP = std::unique_ptr<Identifiable>;
    class ILoader
    {
    public:
        virtual ~ILoader() { }
        virtual bool hasClass(unsigned classId) const = 0;
        virtual bool hasClass(const char * className) const = 0;
        virtual void loadClass(unsigned classId) = 0;
        virtual void loadClass(const char * className) = 0;
    };
    struct RuntimeClass {
    public:
        RuntimeClass(RuntimeInfo * info);
        ~RuntimeClass();
        const char *         name()     const { return _rt->_name; }
        const char *         info()     const { return _rt->_info; }
        unsigned               id()     const { return _rt->_id; }
        Identifiable *     create()     const { return _rt->_factory ? _rt->_factory() : 0; }
        const std::type_info & typeId() const { return _rt->_typeId(); }
        bool tryCast(const Identifiable *o) const { return _rt->_tryCast(o); }
        const RuntimeInfo *  base()     const { return _rt->_base; }
        bool inherits(unsigned id) const;
        bool equal(unsigned cid) const { return id() == cid; }
        int compare(const RuntimeClass& other) const { return (id() - other.id()); }
    private:
        RuntimeInfo * _rt;
    };
    DECLARE_IDENTIFIABLE_ROOT(Identifiable);
    Identifiable() noexcept = default;
    Identifiable(Identifiable &&) noexcept = default;
    Identifiable & operator = (Identifiable &&) noexcept = default;
    Identifiable(const Identifiable &) = default;
    Identifiable & operator = (const Identifiable &) = default;
    virtual ~Identifiable() noexcept = default;

    /**
     * Will produce the full demangled className
     */
    string getNativeClassName() const;

    /**
     * This returns the innermost class that you represent. Default is that that is yourself.
     * However when you are a vector containing other objects, it might be feasible
     * to let the world know about them too.
     * @return the class info for the innermost object.
     */
    virtual const RuntimeClass & getBaseClass() const { return getClass(); }
    /**
     * Checks if this object inherits from a class with the given id.
     * @param id The id of the class to check if is an anchestor.
     * @return true if the object does inherit from it. Significantly faster than using dynamic cast.
     */
    bool inherits(unsigned id) const { return getClass().inherits(id); }
    /**
     * Checks if this object inherits from a class with the given name.
     * @param name The name of the class to check if is an anchestor.
     * @return true if the object does inherit from it. Significantly faster than using dynamic cast.
     */
    bool inherits(const char * name) const;
    /**
     * Identifiable::cast<T> behaves like dynamic_cast<T> when trying
     * to cast between Identifiable objects, using the inherits()
     * function defined above to check if the cast should succeed.
     */
    template <typename T> struct BaseType { using type = T; };
    template <typename T> struct BaseType<T &> { using type = T; };
    template <typename T> struct BaseType<T *> { using type = T; };
    template <typename T> struct BaseType<const T &> { using type = T; };
    template <typename T> struct BaseType<const T *> { using type = T; };
    template <typename Type> static void ERROR_Type_is_not_Identifiable() {
        Type *(*foo)() = &Type::identifyClassAsIdentifiable;
        (void) foo;
    }
    template <typename T, typename Base>
    static T cast(Base &p) {
        using Type = typename BaseType<T>::type;
        ERROR_Type_is_not_Identifiable<Type>();  // Help diagnose errors.
        if (p.inherits(Type::classId)) { return static_cast<T>(p); }
        else { throw std::bad_cast(); }
    }
    template <typename T, typename Base>
    static T cast(Base *p) {
        using Type = typename BaseType<T>::type;
        ERROR_Type_is_not_Identifiable<Type>();  // Help diagnose errors.
        if (p && p->inherits(Type::classId)) { return static_cast<T>(p); }
        else { return 0; }
    }
    /**
     * Given the unique registered id of a class it will look up the object describing it.
     * @return object describing the class.
     */
    static const RuntimeClass * classFromId(unsigned id);
    /**
     * Given the unique registered name of a class it will look up the object describing it.
     * @return object describing the class.
     */
    static const RuntimeClass * classFromName(const char * name);
    /**
     * Here you can provide an optional classloader.
     */
    static void registerClassLoader(ILoader & loader) { _classLoader = &loader; }
    static void clearClassLoader() { _classLoader = NULL; }

    /**
     * Create a human-readable representation of this object. This
     * method will use object visitation internally to capture the
     * full structure of this object.
     *
     * @return structured human-readable representation of this object
     **/
    string asString() const;

    /**
     * Visit each of the members of this object. This method should be
     * overridden by subclasses and should present all appropriate
     * internal structure of this object to the given visitor. Note
     * that while each level of a class hierarchy may cooperate to
     * visit all object members (invoking superclass method within
     * method), this method, as implemented in the Identifiable class
     * should not be invoked, since its default implementation is
     * there to signal about the method not being overridden.
     *
     * @param visitor the visitor of this object
     **/
    virtual void visitMembers(ObjectVisitor &visitor) const;

    /**
     * Compares 2 objects. First tests classId, then lives it to the objects  and onCmp
     * if classes are the same.
     * @param b the object to compare with.
     * @return <0 if this comes before b, 0 for equality, and >0 fi b comes before *this.
     */
    int cmp(const Identifiable& b) const {
        int r(cmpClassId(b));
        return (r==0) ? onCmp(b) : r;
    }
    /**
     * Compares 2 objects. This is faster method that cmp as classId tests is not done.
     * onCmp is called directly.
     * @param b the object to compare with.
     * @return <0 if this comes before b, 0 for equality, and >0 fi b comes before *this.
     */
    int cmpFast(const Identifiable& b) const { return onCmp(b); }

    /**
     * Apply the predicate to this object. If the predicate returns
     * true, pass this object to the operation, otherwise invoke the
     * @ref selectMemebers method to locate sub-elements that might
     * trigger the predicate.
     *
     * @param predicate component used to select (sub-)objects
     * @param operation component performing some operation
     *                  on the selected (sub-)objects
     **/
    void select(const ObjectPredicate &predicate, ObjectOperation &operation);

    /**
     * Invoke @ref select on any member objects this object wants to
     * expose through the selection mechanism. Overriding this method
     * is optional, and which objects to expose is determined by the
     * application logic of the object itself.
     *
     * @param predicate component used to select (sub-)objects
     * @param operation component performing some operation
     *                  on the selected (sub-)objects
     **/
    virtual void selectMembers(const ObjectPredicate &predicate,
                               ObjectOperation &operation);

    /**
     * This will serialize the object by calling the virtual onSerialize.
     * The id of the object is not serialized.
     * @param os The nbostream used for output.
     * @return The nbostream after serialization.
     */
    Serializer & serialize(Serializer & os) const;
    /**
     * This will deserialize the object by calling the virtual onDeserialize.
     * It is symetric with serialize.
     * @param is The nbostream used for input.
     * @return The nbostream after deserialization.
     */
    Deserializer & deserialize(Deserializer & is);
    /**
     * This will read the first 4 bytes containing the classid. It will then create the
     * correct object based on that class, and then call deserialize with the rest.
     * It is symetric with the << operator, and does the same as >>, except instead of checking the id
     * it uses it to construct an object.
     * @param is The nbostream used for input.
     * @return The object created and constructed by deserialize. NULL if there are any errors.
     */
    static UP create(Deserializer & is);
    static UP create(nbostream & is) { NBOSerializer nis(is); return create(nis); }
    /**
     * This will serialize the object by first serializing the 4 byte classid.
     * Then the rest is serialized by calling serialize.
     * @param os The nbostream used for output.
     * @param obj The object to serialize.
     * @return The nbostream after serialization.
     */
    friend Serializer & operator << (Serializer & os, const Identifiable & obj);
    friend nbostream & operator << (nbostream & os, const Identifiable & obj);
    /**
     * This will read the first 4 bytes containing the classid. It will then check if it matches its own.
     * if not it will mark the nbostream as bad. Then it will deserialize he content.
     * It is symetric with the << operator
     * @param is The nbostream used for input.
     * @param obj The object that the stream will be deserialized into.
     * @return The object created and constructed by deserialize. NULL if there are any errors.
     */
    friend Deserializer & operator >> (Deserializer & os, Identifiable & obj);
    friend nbostream & operator >> (nbostream & os, Identifiable & obj);

    /**
     * This will serialize a 4 byte num element before it will serialize all elements.
     * This is used when you have a vector of objects of known class.
     * It is symetric with deserialize template below
     * @param v is vector of non polymorf Identifiable.
     * @param os is output stream
     * @return outputstream
     */
    template <typename T>
    static Serializer & serialize(const T & v, Serializer & os);

    /**
     * This will serialize a 4 byte num element before it will serialize all elements.
     * This is used when you have a vector of objects of known class.
     * It is symetric with deserialize template below
     * @param v is vector of non polymorf Identifiable.
     * @param os is output stream
     * @return outputstream
     */
    template <typename T>
    static Deserializer & deserialize(T & v, Deserializer & is);

    Serializer & serializeDirect(Serializer & os) const { return onSerialize(os); }
    Deserializer & deserializeDirect(Deserializer & is)  { return onDeserialize(is); }
protected:
    /**
     * Returns the diff of the classid. Used for comparing classes.
     * @param b the object to compare with.
     * @return getClass().id() - b.getClass().id()
     */
    int cmpClassId(const Identifiable& b) const
    { return getClass().id() - b.getClass().id(); }

private:
    /**
     * Interface for comparing objects to each other. Default implementation
     * is to serialise the two objects and use memcmp to verify equality.
     * Classes should overide this method if they have special needs.
     * It might also be an idea to override for speed, as serialize is 'expensive'.
     * @param b the object to compare with.
     * @return <0 if this comes before b, 0 for equality, and >0 fi b comes before *this.
     */
    virtual int onCmp(const Identifiable& b) const;
    virtual Serializer & onSerialize(Serializer & os) const;
    virtual Deserializer & onDeserialize(Deserializer & is);

    static ILoader  * _classLoader;
};

}