Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1702 - 1
// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2
//
3
// This is free software; you can redistribute it and/or modify it under
4
// the terms of the GNU Lesser General Public License as published by the
5
// Free Software Foundation; either version 2.1 of the License, or (at
6
// your option) any later version.
7
//
8
 
9
/// @file       AP_Meta_class.h
10
///     @brief  An abstract base class from which other classes can inherit.
11
///
12
/// This abstract base class declares and implements functions that are
13
/// useful to code that wants to know things about a class, or to operate
14
/// on the class without knowing precisely what it is.
15
///
16
/// All classes that inherit from this class can be assumed to have these
17
/// basic functions.
18
///
19
 
20
#ifndef AP_META_CLASS_H
21
#define AP_META_CLASS_H
22
 
23
#include <stddef.h>                     // for size_t
24
#include <inttypes.h>
25
 
26
#include <avr/io.h>                     // for RAMEND
27
///
28
/// Basic meta-class from which other AP_* classes can derive.
29
///
30
/// Functions that form the public API to the metaclass are prefixed meta_.
31
///
32
/// Note that classes inheriting from AP_Meta_class *must* have a default
33
/// constructor and destructor in order for meta_cast to work.
34
///
35
class AP_Meta_class
36
{
37
public:
38
    /// Default constructor does nothing.
39
    AP_Meta_class(void);
40
 
41
    /// Default destructor is virtual, to ensure that all subclasses'
42
    /// destructors are virtual.  This guarantees that all destructors
43
    /// in the inheritance chain are called at destruction time.
44
    ///
45
    virtual ~AP_Meta_class();
46
 
47
    /// Typedef for the ID unique to all instances of a class.
48
    ///
49
    /// See ::meta_type_id for a discussion of class type IDs.
50
    ///
51
    typedef uint16_t Type_id;
52
 
53
    /// Obtain a value unique to all instances of a specific subclass.
54
    ///
55
    /// The value can be used to determine whether two class pointers
56
    /// refer to the same exact class type.  The value can also be cached
57
    /// and then used to detect objects of a given type at a later point.
58
    ///
59
    /// This is similar to the basic functionality of the C++ typeid
60
    /// keyword, but does not depend on std::type_info or any compiler-
61
    /// generated RTTI.
62
    ///
63
    /// The value is derived from the vtable address, so it is guaranteed
64
    /// to be unique but cannot be known until the program has been compiled
65
    /// and linked.  Thus, the only way to know the type ID of a given
66
    /// type is to construct an object at runtime.  To cache the type ID
67
    /// of a class Foo, see the templated version below:
68
    ///
69
    /// @return                                 A type-unique value for this.
70
    ///
71
    Type_id meta_type_id(void) const {
72
        return *(Type_id *)this;
73
    }
74
 
75
    /// Obtain a value unique to all instances of a named subclass.
76
    ///
77
    /// This is similar to ::meta_type_id, but is a template taking a class name.
78
    /// Use this function to cache the Type_id for a class when you don't need
79
    /// or cannot afford the constructor cost associated with meta_cast.
80
    ///
81
    /// @tparam T               A subclass of AP_Meta_class.
82
    /// @return                 The Type_id value for T.
83
    ///
84
    template<typename T>
85
    static Type_id meta_type_id(void) {
86
        T tmp;
87
        return tmp.meta_type_id();
88
    }
89
 
90
    /// External handle for an instance of an AP_Meta_class subclass, contains
91
    /// enough information to construct and validate a pointer to the instance
92
    /// when passed back from an untrusted source.
93
    ///
94
    /// Handles are useful when passing a reference to an object to a client outside
95
    /// the system, as they can be validated by the system when the client hands
96
    /// them back.
97
    ///
98
    typedef uint32_t Meta_handle;
99
 
100
    /// Return a value that can be used as an external pointer to an instance
101
    /// of a subclass.
102
    ///
103
    /// The value can be passed to an untrusted agent, and validated on its return.
104
    ///
105
    /// The value contains the 16-bit type ID of the actual class and
106
    /// a pointer to the class instance.
107
    ///
108
    /// @return                                 An opaque handle
109
    ///
110
    Meta_handle meta_get_handle(void) const {
111
        return ((Meta_handle)meta_type_id() << 16) | (uintptr_t)this;
112
    }
113
 
114
    /// Validates an AP_Meta_class handle.
115
    ///
116
    /// The value of the handle is not required to be valid; in particular the
117
    /// pointer encoded in the handle is validated before being dereferenced.
118
    ///
119
    /// The handle is considered good if the pointer is valid and the object
120
    /// it points to has a type ID that matches the ID in the handle.
121
    ///
122
    /// @param  handle                  A possible AP_Meta_class handle
123
    /// @return                                 The instance pointer if the handle is good,
124
    ///                                                 or NULL if it is bad.
125
    ///
126
    static AP_Meta_class *meta_validate_handle(Meta_handle handle) {
127
        AP_Meta_class *candidate = (AP_Meta_class *)(handle & 0xffff); // extract object pointer
128
        uint16_t id = handle >> 16; // and claimed type
129
 
130
        // Sanity-check the pointer to ensure it lies within the device RAM, so that
131
        // a bad handle won't cause ::meta_type_id to read outside of SRAM.
132
        // Assume that RAM (or addressable storage of some sort, at least) starts at zero.
133
        //
134
        // Note that this implies that we cannot deal with objects in ROM or EEPROM,
135
        // but the constructor wouldn't be able to populate a vtable pointer there anyway...
136
        //
137
        if ((uintptr_t)candidate >= (RAMEND - 2)) { // -2 to account for the type_id
138
            return NULL;
139
        }
140
 
141
        // Compare the typeid of the object that candidate points to with the typeid
142
        // from the handle.  Note that it's safe to call meta_type_id() off the untrusted
143
        // candidate pointer because meta_type_id is non-virtual (and will in fact be
144
        // inlined here).
145
        //
146
        if (candidate->meta_type_id() == id) {
147
            return candidate;
148
        }
149
 
150
        return NULL;
151
    }
152
 
153
    /// Tests whether two objects are of precisely the same class.
154
    ///
155
    /// Note that in the case where p2 inherits from p1, or vice-versa, this will return
156
    /// false as we cannot detect these inheritance relationships at runtime.
157
    ///
158
    /// In the caller's context, p1 and p2 may be pointers to any type, but we require
159
    /// that they be passed as pointers to AP_Meta_class in order to make it clear that
160
    /// they should be pointers to classes derived from AP_Meta_class.
161
    ///
162
    /// No attempt is made to validate whether p1 and p2 are actually derived from
163
    /// AP_Meta_class.  If p1 and p2 are equal, or if they point to non-class objects with
164
    /// similar contents, or to non-AP_Meta_class derived classes with no virtual functions
165
    /// this function may return true.
166
    ///
167
    /// @param  p1                              The first object to be compared.
168
    /// @param  p2                              The second object to be compared.
169
    /// @return                                 True if the two objects are of the same class, false
170
    ///                                                 if they are not.
171
    ///
172
    static bool meta_type_equivalent(AP_Meta_class *p1, AP_Meta_class *p2) {
173
        return p1->meta_type_id() == p2->meta_type_id();
174
    }
175
 
176
    /// Cast a pointer to an expected class type.
177
    ///
178
    /// This function is used when a pointer is expected to be a pointer to a
179
    /// subclass of AP_Meta_class, but the caller is not certain.  It will return the pointer
180
    /// if it is, or NULL if it is not a pointer to the expected class.
181
    ///
182
    /// This should be used with caution, as T's default constructor and
183
    /// destructor will be run, possibly introducing undesired side-effects.
184
    ///
185
    /// @todo   Consider whether we should make it difficult to have a default constructor
186
    ///                 with appreciable side-effects.
187
    ///
188
    /// @param  p                               An AP_Meta_class subclass that may be of type T.
189
    /// @tparam T                       The name of a type to which p is to be cast.
190
    /// @return                                 NULL if p is not of precisely type T, otherwise p cast to T.
191
    ///
192
    template<typename T>
193
    static T *meta_cast(AP_Meta_class *p) {
194
        T tmp;
195
        if (meta_type_equivalent(p, &tmp)) {
196
            return (T *)p;
197
        }
198
        return NULL;
199
    }
200
 
201
    /// Cast this to an expected class type.
202
    ///
203
    /// This is equivalent to meta_cast<T>(this)
204
    ///
205
    /// @tparam T               The name of a type to which this is to be cast.
206
    /// @return                 NULL if this is not of precisely type T, otherwise this cast to T.
207
    ///
208
    template<typename T>
209
    T *meta_cast(void) {
210
        T tmp;
211
        if (meta_type_equivalent(this, &tmp)) {
212
            return (T*)this;
213
        }
214
        return NULL;
215
    }
216
 
217
    /// Serialize the class.
218
    ///
219
    /// Serialization stores the state of the class in an external buffer in such a
220
    /// fashion that it can later be restored by unserialization.
221
    ///
222
    /// AP_Meta_class subclasses should only implement these functions if saving and
223
    /// restoring their state makes sense.
224
    ///
225
    /// Serialization provides a mechanism for exporting the state of the class to an
226
    /// external consumer, either for external introspection or for subsequent restoration.
227
    ///
228
    /// Classes that wrap variables should define the format of their serialiaed data
229
    /// so that external consumers can reliably interpret it.
230
    ///
231
    /// @param  buf                             Buffer into which serialised data should be placed.
232
    /// @param  bufSize                 The size of the buffer provided.
233
    /// @return                                 The size of the serialised data, even if that data would
234
    ///                                                 have overflowed the buffer.  If the return value is zero,
235
    ///                                                 the class does not support serialization.
236
    ///
237
    virtual size_t serialize(void *buf, size_t bufSize) const;
238
 
239
    /// Unserialize the class.
240
    ///
241
    /// Unserializing a class from a buffer into which the class previously serialized
242
    /// itself restores the instance to an identical state, where "identical" is left
243
    /// up to the class itself to define.
244
    ///
245
    /// Classes that wrap variables should define the format of their serialized data so
246
    /// that external providers can reliably encode it.
247
    ///
248
    /// @param  buf                             Buffer containing serialized data.
249
    /// @param  bufSize                 The size of the buffer.
250
    /// @return                                 The number of bytes from the buffer that would be consumed
251
    ///                                                 unserializing the data.  If the value is less than or equal
252
    ///                                                 to bufSize, unserialization was successful.  If the return
253
    ///                                                 value is zero the class does not support unserialisation or
254
    ///                                                 the data in the buffer is invalid.
255
    ///
256
    virtual size_t unserialize(void *buf, size_t bufSize);
257
};
258
 
259
#endif // AP_Meta_class_H