Coverage Report

Created: 2026-07-03 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/mcpack2pb/serializer.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
// mcpack2pb - Make protobuf be front-end of mcpack/compack
19
20
// Date: Mon Oct 19 17:17:36 CST 2015
21
22
#ifndef MCPACK2PB_MCPACK_SERIALIZER_H
23
#define MCPACK2PB_MCPACK_SERIALIZER_H
24
25
#include <limits>
26
#include <vector>
27
#include <google/protobuf/io/zero_copy_stream.h>
28
#include "butil/logging.h"
29
#include "butil/strings/string_piece.h"
30
#include "mcpack2pb/field_type.h"
31
32
// CAUTION: Methods in this header is not intended to be public to users of
33
// brpc, and subject to change at any future time.
34
35
namespace mcpack2pb {
36
37
// Send bytes into ZeroCopyOutputStream
38
class OutputStream {
39
public:
40
    class Area {
41
    public:
42
0
        Area() : _addr1(NULL)
43
0
               , _addr2(NULL)
44
0
               , _size1(0)
45
0
               , _size2(0)
46
0
               , _addional_area(NULL) {}
47
2
        Area(const butil::LinkerInitialized&) {}
48
        Area(const Area& rhs);
49
        Area& operator=(const Area& rhs);
50
        ~Area();
51
        void add(void* data, size_t n);
52
        void assign(const void* data) const;
53
    private:
54
        void* _addr1;
55
        void* _addr2;
56
        unsigned _size1;
57
        unsigned _size2;
58
        std::vector<butil::StringPiece>* _addional_area;
59
    };
60
61
    // TODO(gejun): The zero-copy stream MUST return permanent memory blocks
62
    // to support reserve(). E.g. StringOutputStream can't be used because
63
    // the string inside invalidates previous memory blocks after resizing.
64
    OutputStream(google::protobuf::io::ZeroCopyOutputStream* stream)
65
0
        : _good(true)
66
0
        , _fullsize(0)
67
0
        , _size(0)
68
0
        , _data(NULL)
69
0
        , _zc_stream(stream)
70
0
        , _pushed_bytes(0)
71
0
    {}
72
73
0
    ~OutputStream() { done(); }
74
75
    // Append n bytes.
76
    void append(const void* data, int n);
77
78
    // Append a pod.
79
    template <typename T> void append_packed_pod(const T& packed_pod);
80
81
    template <typename T> T* append_packed_pod();
82
83
    // Append a byte.
84
    void push_back(char c);
85
86
    // If next n bytes in the zero-copy stream is continuous, consume it
87
    // and return the begining address. NULL otherwise.
88
    void* skip_continuous(int n);
89
90
    // Consume n bytes from the stream and return an object representing the
91
    // consumed area.
92
    Area reserve(int n);
93
94
    // Change data at the area. `data' must be as long as the reserved area.
95
    void assign(const Area&, const void* data);
96
97
    // Go back for n bytes.
98
    void backup(int n);
99
    
100
    // Returns bytes pushed and cut since creation of this stream.
101
0
    size_t pushed_bytes() const { return _pushed_bytes; }
102
103
    // Returns false if error occurred during serialization.
104
0
    bool good() { return _good; }
105
106
0
    void set_bad() { _good = false; }
107
108
    // Optionally called to backup buffered bytes to zero-copy stream.
109
    void done();
110
    
111
private:
112
    bool _good;
113
    int _fullsize;
114
    int _size;
115
    void* _data;
116
    google::protobuf::io::ZeroCopyOutputStream* _zc_stream;
117
    size_t _pushed_bytes;
118
};
119
120
// This class is different from butil::StringPiece that it only can be
121
// constructed from std::string or const char* which are both ended with
122
// zero, so that in later serialization of the name, we can simply copy one
123
// extra byte to end the name with zero(required by compack) rather than
124
// appending the zero in a separate function call which is less efficient.
125
class StringWrapper {
126
public:
127
    StringWrapper(const std::string& str)
128
0
        : _data(str.c_str()), _size(str.size()) {}
129
0
    StringWrapper(const char* str) {
130
0
        if (str) {
131
0
            _data = str;
132
0
            _size = strlen(str);
133
0
        } else {
134
0
            _data = "";
135
0
            _size = 0;
136
0
        }
137
0
    }
138
0
    ~StringWrapper() { }
139
0
    const char* data() const { return _data; }
140
0
    size_t size() const { return _size; }
141
0
    bool empty() const { return !_size; }
142
private:
143
    const char* _data;
144
    size_t _size;
145
};
146
0
inline std::ostream& operator<<(std::ostream& os, const StringWrapper& sw) {
147
0
    return os << butil::StringPiece(sw.data(), sw.size());
148
0
}
149
150
class Serializer {
151
public:
152
    // Serialize into `output'.
153
    explicit Serializer(OutputStream* stream);
154
    ~Serializer();
155
156
0
    bool good() const { return _stream->good(); }
157
0
    void set_bad() { _stream->set_bad(); }
158
0
    size_t pushed_bytes() const { return _stream->pushed_bytes(); }
159
160
    // WARNING: Names to all methods cannot be longer that 254 bytes.
161
162
    // Append a primitive type with name.
163
    // Used between begin_object() and end_object().
164
    void add_int8(const StringWrapper& name, int8_t value);
165
    void add_int16(const StringWrapper& name, int16_t value);
166
    void add_int32(const StringWrapper& name, int32_t value);
167
    void add_int64(const StringWrapper& name, int64_t value);
168
    void add_uint8(const StringWrapper& name, uint8_t value);
169
    void add_uint16(const StringWrapper& name, uint16_t value);
170
    void add_uint32(const StringWrapper& name, uint32_t value);
171
    void add_uint64(const StringWrapper& name, uint64_t value);
172
    void add_bool(const StringWrapper& name, bool value);
173
    void add_float(const StringWrapper& name, float value);
174
    void add_double(const StringWrapper& name, double value);
175
176
    // Add a primitive type without name.
177
    // Used between begin_xxx_array() and end_xxx_array().
178
    void add_int8(int8_t value);
179
    void add_int16(int16_t value);
180
    void add_int32(int32_t value);
181
    void add_int64(int64_t value);
182
    void add_uint8(uint8_t value);
183
    void add_uint16(uint16_t value);
184
    void add_uint32(uint32_t value);
185
    void add_uint64(uint64_t value);
186
    void add_bool(bool value);
187
    void add_float(float value);
188
    void add_double(double value);
189
190
    // Add multiple primitive types in one call.
191
    void add_multiple_int8(const int8_t* values, size_t count);
192
    void add_multiple_int8(const uint8_t* values, size_t count);
193
    void add_multiple_int16(const int16_t* values, size_t count);
194
    void add_multiple_int16(const uint16_t* values, size_t count);
195
    void add_multiple_int32(const int32_t* values, size_t count);
196
    void add_multiple_int32(const uint32_t* values, size_t count);
197
    void add_multiple_int64(const int64_t* values, size_t count);
198
    void add_multiple_int64(const uint64_t* values, size_t count);
199
    void add_multiple_uint8(const uint8_t* values, size_t count);
200
    void add_multiple_uint8(const int8_t* values, size_t count);
201
    void add_multiple_uint16(const uint16_t* values, size_t count);
202
    void add_multiple_uint16(const int16_t* values, size_t count);
203
    void add_multiple_uint32(const uint32_t* values, size_t count);
204
    void add_multiple_uint32(const int32_t* values, size_t count);
205
    void add_multiple_uint64(const uint64_t* values, size_t count);
206
    void add_multiple_uint64(const int64_t* values, size_t count);
207
    void add_multiple_bool(const bool* values, size_t count);
208
    void add_multiple_float(const float* values, size_t count);
209
    void add_multiple_double(const double* values, size_t count);
210
211
    // Append a string.
212
    // The serialized value ends with 0 and the length counts 0.
213
    void add_string(const StringWrapper& name, const StringWrapper& str);
214
    void add_string(const StringWrapper& str);
215
216
    // Append binary data.
217
    void add_binary(const StringWrapper& name, const std::string& data);
218
    void add_binary(const StringWrapper& name, const void* data, size_t n);
219
    void add_binary(const std::string& data);
220
    void add_binary(const void* data, size_t n);
221
222
    // Append a null.
223
    void add_null(const StringWrapper& name);
224
    void add_null();
225
226
    // Append an empty array.
227
    void add_empty_array(const StringWrapper& name);
228
    void add_empty_array();
229
230
    // Begin/end an array.
231
    // All items inside the array must be of same type. This is not a
232
    // restriction of mcpack, but we want to align storage model with protobuf
233
    // as much as possible.
234
    // If too many levels of array/object reached, this function fails and
235
    // leaves the output unchanged.
236
    void begin_mcpack_array(const StringWrapper& name, FieldType item_type);
237
    void begin_mcpack_array(FieldType item_type);
238
    void begin_compack_array(const StringWrapper& name, FieldType item_type);
239
    void begin_compack_array(FieldType item_type);
240
    // End any kind of array.
241
    void end_array();
242
243
    // Begin/end an object.
244
    // If too many levels of array/object reached, this function fails and
245
    // leaves the output unchanged.
246
    void begin_object(const StringWrapper& name);
247
    void begin_object();
248
    void end_object();
249
    // TODO(gejun): move to begin_object
250
    void end_object_iso();
251
252
public:
253
    struct GroupInfo {
254
        uint32_t item_count;
255
        bool isomorphic;
256
        uint8_t item_type;
257
        uint8_t type;
258
        uint8_t name_size;
259
        size_t output_offset;
260
        int pending_null_count;
261
        OutputStream::Area head_area;
262
        OutputStream::Area items_head_area;
263
264
        void print(std::ostream&) const;
265
    };
266
267
private:
268
    DISALLOW_COPY_AND_ASSIGN(Serializer);
269
270
    GroupInfo* push_group_info();
271
    GroupInfo & peek_group_info();
272
    void begin_object_internal(const StringWrapper& name);
273
    void begin_object_internal();
274
    void end_object_internal(bool objectisoarray);
275
    void begin_array_internal(FieldType item_type, bool compack);
276
    void begin_array_internal(const StringWrapper& name,
277
                              FieldType item_type, bool compack);
278
279
    OutputStream* _stream;
280
    int _ndepth;
281
    GroupInfo _group_info_fast[15];
282
    GroupInfo *_group_info_more;
283
};
284
285
}  // namespace mcpack2pb
286
287
#include "mcpack2pb/serializer-inl.h"
288
289
#endif  // MCPACK2PB_MCPACK_SERIALIZER_H