aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/extension_set.h
blob: 902ec7364f11fcc5c8865f6b41fec4edc4091b62 (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
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.
// http://code.google.com/p/protobuf/
//
// 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.

// Author: kenton@google.com (Kenton Varda)
//  Based on original Protocol Buffers design by
//  Sanjay Ghemawat, Jeff Dean, and others.
//
// This header is logically internal, but is made public because it is used
// from protocol-compiler-generated code, which may reside in other components.

#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__
#define GOOGLE_PROTOBUF_EXTENSION_SET_H__

#include <vector>
#include <stack>
#include <map>
#include <utility>
#include <string>

#include <google/protobuf/message.h>

namespace google {
namespace protobuf {
  class Descriptor;                                    // descriptor.h
  class FieldDescriptor;                               // descriptor.h
  class DescriptorPool;                                // descriptor.h
  class Message;                                       // message.h
  class MessageFactory;                                // message.h
  namespace io {
    class CodedInputStream;                              // coded_stream.h
    class CodedOutputStream;                             // coded_stream.h
  }
  template <typename Element> class RepeatedField;     // repeated_field.h
  template <typename Element> class RepeatedPtrField;  // repeated_field.h
}

namespace protobuf {
namespace internal {

// This is an internal helper class intended for use within the protocol buffer
// library and generated classes.  Clients should not use it directly.  Instead,
// use the generated accessors such as GetExtension() of the class being
// extended.
//
// This class manages extensions for a protocol message object.  The
// message's HasExtension(), GetExtension(), MutableExtension(), and
// ClearExtension() methods are just thin wrappers around the embedded
// ExtensionSet.  When parsing, if a tag number is encountered which is
// inside one of the message type's extension ranges, the tag is passed
// off to the ExtensionSet for parsing.  Etc.
class LIBPROTOBUF_EXPORT ExtensionSet {
 public:
  // Construct an ExtensionSet.
  //   extendee:  Descriptor for the type being extended.
  //   pool:      DescriptorPool to search for extension definitions.
  //   factory:   MessageFactory used to construct implementations of messages
  //              for extensions with message type.  This factory must be able
  //              to construct any message type found in "pool".
  // All three objects remain property of the caller and must outlive the
  // ExtensionSet.
  ExtensionSet(const Descriptor* extendee,
               const DescriptorPool* pool,
               MessageFactory* factory);

  ~ExtensionSet();

  // Search for a known (compiled-in) extension of this type by name or number.
  // Returns NULL if no extension is known.
  const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
  const FieldDescriptor* FindKnownExtensionByNumber(int number) const;

  // Add all fields which are currently present to the given vector.  This
  // is useful to implement Message::Reflection::ListFields().
  void AppendToList(vector<const FieldDescriptor*>* output) const;

  // =================================================================
  // Accessors
  //
  // Generated message classes include type-safe templated wrappers around
  // these methods.  Generally you should use those rather than call these
  // directly, unless you are doing low-level memory management.
  //
  // When calling any of these accessors, the extension number requested
  // MUST exist in the DescriptorPool provided to the constructor.  Otheriwse,
  // the method will fail an assert.  Normally, though, you would not call
  // these directly; you would either call the generated accessors of your
  // message class (e.g. GetExtension()) or you would call the accessors
  // of the reflection interface.  In both cases, it is impossible to
  // trigger this assert failure:  the generated accessors only accept
  // linked-in extension types as parameters, while the Reflection interface
  // requires you to provide the FieldDescriptor describing the extension.
  //
  // When calling any of these accessors, a protocol-compiler-generated
  // implementation of the extension corresponding to the number MUST
  // be linked in, and the FieldDescriptor used to refer to it MUST be
  // the one generated by that linked-in code.  Otherwise, the method will
  // die on an assert failure.  The message objects returned by the message
  // accessors are guaranteed to be of the correct linked-in type.
  //
  // These methods pretty much match Message::Reflection except that:
  // - They're not virtual.
  // - They identify fields by number rather than FieldDescriptors.
  // - They identify enum values using integers rather than descriptors.
  // - Strings provide Mutable() in addition to Set() accessors.

  bool Has(int number) const;
  int ExtensionSize(int number) const;   // Size of a repeated extension.
  void ClearExtension(int number);

  // singular fields -------------------------------------------------

  int32  GetInt32 (int number) const;
  int64  GetInt64 (int number) const;
  uint32 GetUInt32(int number) const;
  uint64 GetUInt64(int number) const;
  float  GetFloat (int number) const;
  double GetDouble(int number) const;
  bool   GetBool  (int number) const;
  int    GetEnum  (int number) const;
  const string & GetString (int number) const;
  const Message& GetMessage(int number) const;

  void SetInt32 (int number, int32  value);
  void SetInt64 (int number, int64  value);
  void SetUInt32(int number, uint32 value);
  void SetUInt64(int number, uint64 value);
  void SetFloat (int number, float  value);
  void SetDouble(int number, double value);
  void SetBool  (int number, bool   value);
  void SetEnum  (int number, int    value);
  void SetString(int number, const string& value);
  string * MutableString (int number);
  Message* MutableMessage(int number);

  // repeated fields -------------------------------------------------

  int32  GetRepeatedInt32 (int number, int index) const;
  int64  GetRepeatedInt64 (int number, int index) const;
  uint32 GetRepeatedUInt32(int number, int index) const;
  uint64 GetRepeatedUInt64(int number, int index) const;
  float  GetRepeatedFloat (int number, int index) const;
  double GetRepeatedDouble(int number, int index) const;
  bool   GetRepeatedBool  (int number, int index) const;
  int    GetRepeatedEnum  (int number, int index) const;
  const string & GetRepeatedString (int number, int index) const;
  const Message& GetRepeatedMessage(int number, int index) const;

  void SetRepeatedInt32 (int number, int index, int32  value);
  void SetRepeatedInt64 (int number, int index, int64  value);
  void SetRepeatedUInt32(int number, int index, uint32 value);
  void SetRepeatedUInt64(int number, int index, uint64 value);
  void SetRepeatedFloat (int number, int index, float  value);
  void SetRepeatedDouble(int number, int index, double value);
  void SetRepeatedBool  (int number, int index, bool   value);
  void SetRepeatedEnum  (int number, int index, int    value);
  void SetRepeatedString(int number, int index, const string& value);
  string * MutableRepeatedString (int number, int index);
  Message* MutableRepeatedMessage(int number, int index);

  void AddInt32 (int number, int32  value);
  void AddInt64 (int number, int64  value);
  void AddUInt32(int number, uint32 value);
  void AddUInt64(int number, uint64 value);
  void AddFloat (int number, float  value);
  void AddDouble(int number, double value);
  void AddBool  (int number, bool   value);
  void AddEnum  (int number, int    value);
  void AddString(int number, const string& value);
  string * AddString (int number);
  Message* AddMessage(int number);

  // -----------------------------------------------------------------
  // TODO(kenton):  Hardcore memory management accessors

  // =================================================================
  // convenience methods for implementing methods of Message
  //
  // These could all be implemented in terms of the other methods of this
  // class, but providing them here helps keep the generated code size down.

  void Clear();
  void MergeFrom(const ExtensionSet& other);
  bool IsInitialized() const;

  // These parsing and serialization functions all want a pointer to the
  // reflection interface because they hand off the actual work to WireFormat,
  // which works in terms of a reflection interface.  Yes, this means there
  // are some redundant virtual function calls that end up being made, but
  // it probably doesn't matter much in practice, and the alternative would
  // involve reproducing a lot of WireFormat's functionality.

  // Parses a single extension from the input.  The input should start out
  // positioned immediately after the tag.
  bool ParseField(uint32 tag, io::CodedInputStream* input,
                  Message::Reflection* reflection);

  // Write all extension fields with field numbers in the range
  //   [start_field_number, end_field_number)
  // to the output stream, using the cached sizes computed when ByteSize() was
  // last called.  Note that the range bounds are inclusive-exclusive.
  bool SerializeWithCachedSizes(int start_field_number,
                                int end_field_number,
                                const Message::Reflection* reflection,
                                io::CodedOutputStream* output) const;

  // Returns the total serialized size of all the extensions.
  int ByteSize(const Message::Reflection* reflection) const;

 private:
  // Like FindKnownExtension(), but GOOGLE_CHECK-fail if not found.
  const FieldDescriptor* FindKnownExtensionOrDie(int number) const;

  // Get the prototype for the message.
  const Message* GetPrototype(const Descriptor* message_type) const;

  struct Extension {
    union {
      int32    int32_value;
      int64    int64_value;
      uint32   uint32_value;
      uint64   uint64_value;
      float    float_value;
      double   double_value;
      bool     bool_value;
      int      enum_value;
      string*  string_value;
      Message* message_value;

      RepeatedField   <int32  >* repeated_int32_value;
      RepeatedField   <int64  >* repeated_int64_value;
      RepeatedField   <uint32 >* repeated_uint32_value;
      RepeatedField   <uint64 >* repeated_uint64_value;
      RepeatedField   <float  >* repeated_float_value;
      RepeatedField   <double >* repeated_double_value;
      RepeatedField   <bool   >* repeated_bool_value;
      RepeatedField   <int    >* repeated_enum_value;
      RepeatedPtrField<string >* repeated_string_value;
      RepeatedPtrField<Message>* repeated_message_value;
    };

    const FieldDescriptor* descriptor;

    // For singular types, indicates if the extension is "cleared".  This
    // happens when an extension is set and then later cleared by the caller.
    // We want to keep the Extension object around for reuse, so instead of
    // removing it from the map, we just set is_cleared = true.  This has no
    // meaning for repeated types; for those, the size of the RepeatedField
    // simply becomes zero when cleared.
    bool is_cleared;

    Extension(): descriptor(NULL), is_cleared(false) {}

    // Some helper methods for operations on a single Extension.
    bool SerializeFieldWithCachedSizes(
        const Message::Reflection* reflection,
        io::CodedOutputStream* output) const;
    int64 ByteSize(const Message::Reflection* reflection) const;
    void Clear();
    int GetSize() const;
    void Free();
  };

  // The Extension struct is small enough to be passed by value, so we use it
  // directly as the value type in the map rather than use pointers.  We use
  // a map rather than hash_map here because we expect most ExtensionSets will
  // only contain a small number of extensions whereas hash_map is optimized
  // for 100 elements or more.  Also, we want AppendToList() to order fields
  // by field number.
  map<int, Extension> extensions_;
  const Descriptor* extendee_;
  const DescriptorPool* descriptor_pool_;
  MessageFactory* message_factory_;

  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
};

// These are just for convenience...
inline void ExtensionSet::SetString(int number, const string& value) {
  MutableString(number)->assign(value);
}
inline void ExtensionSet::SetRepeatedString(int number, int index,
                                            const string& value) {
  MutableRepeatedString(number, index)->assign(value);
}
inline void ExtensionSet::AddString(int number, const string& value) {
  AddString(number)->assign(value);
}

// ===================================================================
// Implementation details
//
// DO NOT DEPEND ON ANYTHING BELOW THIS POINT.  This is for use from
// generated code only.

// -------------------------------------------------------------------
// Template magic

// First we have a set of classes representing "type traits" for different
// field types.  A type traits class knows how to implement basic accessors
// for extensions of a particular type given an ExtensionSet.  The signature
// for a type traits class looks like this:
//
//   class TypeTraits {
//    public:
//     typedef ? ConstType;
//     typedef ? MutableType;
//
//     static inline ConstType Get(int number, const ExtensionSet& set);
//     static inline void Set(int number, ConstType value, ExtensionSet* set);
//     static inline MutableType Mutable(int number, ExtensionSet* set);
//
//     // Variants for repeated fields.
//     static inline ConstType Get(int number, const ExtensionSet& set,
//                                 int index);
//     static inline void Set(int number, int index,
//                            ConstType value, ExtensionSet* set);
//     static inline MutableType Mutable(int number, int index,
//                                       ExtensionSet* set);
//     static inline void Add(int number, ConstType value, ExtensionSet* set);
//     static inline MutableType Add(int number, ExtensionSet* set);
//   };
//
// Not all of these methods make sense for all field types.  For example, the
// "Mutable" methods only make sense for strings and messages, and the
// repeated methods only make sense for repeated types.  So, each type
// traits class implements only the set of methods from this signature that it
// actually supports.  This will cause a compiler error if the user tries to
// access an extension using a method that doesn't make sense for its type.
// For example, if "foo" is an extension of type "optional int32", then if you
// try to write code like:
//   my_message.MutableExtension(foo)
// you will get a compile error because PrimitiveTypeTraits<int32> does not
// have a "Mutable()" method.

// -------------------------------------------------------------------
// PrimitiveTypeTraits

// Since the ExtensionSet has different methods for each primitive type,
// we must explicitly define the methods of the type traits class for each
// known type.
template <typename Type>
class PrimitiveTypeTraits {
 public:
  typedef Type ConstType;

  static inline ConstType Get(int number, const ExtensionSet& set);
  static inline void Set(int number, ConstType value, ExtensionSet* set);
};

template <typename Type>
class RepeatedPrimitiveTypeTraits {
 public:
  typedef Type ConstType;

  static inline Type Get(int number, const ExtensionSet& set, int index);
  static inline void Set(int number, int index, Type value, ExtensionSet* set);
  static inline void Add(int number, Type value, ExtensionSet* set);
};

#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD)                       \
template<> inline TYPE PrimitiveTypeTraits<TYPE>::Get(                     \
    int number, const ExtensionSet& set) {                                 \
  return set.Get##METHOD(number);                                          \
}                                                                          \
template<> inline void PrimitiveTypeTraits<TYPE>::Set(                     \
    int number, ConstType value, ExtensionSet* set) {                      \
  set->Set##METHOD(number, value);                                         \
}                                                                          \
                                                                           \
template<> inline TYPE RepeatedPrimitiveTypeTraits<TYPE>::Get(             \
    int number, const ExtensionSet& set, int index) {                      \
  return set.GetRepeated##METHOD(number, index);                           \
}                                                                          \
template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Set(             \
    int number, int index, ConstType value, ExtensionSet* set) {           \
  set->SetRepeated##METHOD(number, index, value);                          \
}                                                                          \
template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add(             \
    int number, ConstType value, ExtensionSet* set) {                      \
  set->Add##METHOD(number, value);                                         \
}

PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32,  Int32)
PROTOBUF_DEFINE_PRIMITIVE_TYPE( int64,  Int64)
PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32, UInt32)
PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64, UInt64)
PROTOBUF_DEFINE_PRIMITIVE_TYPE( float,  Float)
PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double)
PROTOBUF_DEFINE_PRIMITIVE_TYPE(  bool,   Bool)

#undef PROTOBUF_DEFINE_PRIMITIVE_TYPE

// -------------------------------------------------------------------
// StringTypeTraits

// Strings support both Set() and Mutable().
class LIBPROTOBUF_EXPORT StringTypeTraits {
 public:
  typedef const string& ConstType;
  typedef string* MutableType;

  static inline const string& Get(int number, const ExtensionSet& set) {
    return set.GetString(number);
  }
  static inline void Set(int number, const string& value, ExtensionSet* set) {
    set->SetString(number, value);
  }
  static inline string* Mutable(int number, ExtensionSet* set) {
    return set->MutableString(number);
  }
};

class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
 public:
  typedef const string& ConstType;
  typedef string* MutableType;

  static inline const string& Get(int number, const ExtensionSet& set,
                                  int index) {
    return set.GetRepeatedString(number, index);
  }
  static inline void Set(int number, int index,
                         const string& value, ExtensionSet* set) {
    set->SetRepeatedString(number, index, value);
  }
  static inline string* Mutable(int number, int index, ExtensionSet* set) {
    return set->MutableRepeatedString(number, index);
  }
  static inline void Add(int number, const string& value, ExtensionSet* set) {
    set->AddString(number, value);
  }
  static inline string* Add(int number, ExtensionSet* set) {
    return set->AddString(number);
  }
};

// -------------------------------------------------------------------
// EnumTypeTraits

// ExtensionSet represents enums using integers internally, so we have to
// static_cast around.
template <typename Type>
class EnumTypeTraits {
 public:
  typedef Type ConstType;

  static inline ConstType Get(int number, const ExtensionSet& set) {
    return static_cast<Type>(set.GetEnum(number));
  }
  static inline void Set(int number, ConstType value, ExtensionSet* set) {
    set->SetEnum(number, value);
  }
};

template <typename Type>
class RepeatedEnumTypeTraits {
 public:
  typedef Type ConstType;

  static inline ConstType Get(int number, const ExtensionSet& set, int index) {
    return static_cast<Type>(set.GetRepeatedEnum(number, index));
  }
  static inline void Set(int number, int index,
                         ConstType value, ExtensionSet* set) {
    set->SetRepeatedEnum(number, index, value);
  }
  static inline void Add(int number, ConstType value, ExtensionSet* set) {
    set->AddEnum(number, value);
  }
};

// -------------------------------------------------------------------
// MessageTypeTraits

// ExtensionSet guarantees that when manipulating extensions with message
// types, the implementation used will be the compiled-in class representing
// that type.  So, we can static_cast down to the exact type we expect.
template <typename Type>
class MessageTypeTraits {
 public:
  typedef const Type& ConstType;
 typedef Type* MutableType;

  static inline ConstType Get(int number, const ExtensionSet& set) {
    return static_cast<const Type&>(set.GetMessage(number));
  }
  static inline MutableType Mutable(int number, ExtensionSet* set) {
    return static_cast<Type*>(set->MutableMessage(number));
  }
};

template <typename Type>
class RepeatedMessageTypeTraits {
 public:
  typedef const Type& ConstType;
  typedef Type* MutableType;

  static inline ConstType Get(int number, const ExtensionSet& set, int index) {
    return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
  }
  static inline MutableType Mutable(int number, int index, ExtensionSet* set) {
    return static_cast<Type*>(set->MutableRepeatedMessage(number, index));
  }
  static inline MutableType Add(int number, ExtensionSet* set) {
    return static_cast<Type*>(set->AddMessage(number));
  }
};

// -------------------------------------------------------------------
// ExtensionIdentifier

// This is the type of actual extension objects.  E.g. if you have:
//   extends Foo with optional int32 bar = 1234;
// then "bar" will be defined in C++ as:
//   ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32>> bar(1234);
//
// Note that we could, in theory, supply the field number as a template
// parameter, and thus make an instance of ExtensionIdentifier have no
// actual contents.  However, if we did that, then using at extension
// identifier would not necessarily cause the compiler to output any sort
// of reference to any simple defined in the extension's .pb.o file.  Some
// linkers will actually drop object files that are not explicitly referenced,
// but that would be bad because it would cause this extension to not be
// registered at static initialization, and therefore using it would crash.

template <typename ExtendeeType, typename TypeTraitsType>
class ExtensionIdentifier {
 public:
  typedef TypeTraitsType TypeTraits;
  typedef ExtendeeType Extendee;

  ExtensionIdentifier(int number): number_(number) {}
  inline int number() const { return number_; }
 private:
  const int number_;
};

}  // namespace internal
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_EXTENSION_SET_H__