forked from objectcomputing/mFAST
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfast_encoder.cpp
More file actions
260 lines (202 loc) · 7.14 KB
/
fast_encoder.cpp
File metadata and controls
260 lines (202 loc) · 7.14 KB
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
// Copyright (c) 2016, Huang-Ming Huang, Object Computing, Inc.
// All rights reserved.
//
// This file is part of mFAST.
// See the file license.txt for licensing information.
#include "../../field_visitor.h"
#include "../../sequence_ref.h"
#include "../fast_encoder.h"
#include "../common/template_repo.h"
#include "../common/exceptions.h"
#include "encoder_presence_map.h"
#include "encoder_field_operator.h"
#include "fast_ostream.h"
#include "resizable_fast_ostreambuf.h"
namespace mfast {
struct fast_encoder_impl;
struct fast_encoder_impl : simple_template_repo_t {
fast_ostream strm_;
int64_t active_message_id_;
encoder_presence_map *current_;
fast_encoder_impl(allocator *alloc);
~fast_encoder_impl();
encoder_presence_map ¤t_pmap();
struct pmap_state {
encoder_presence_map pmap_;
encoder_presence_map *prev_pmap_;
pmap_state() : prev_pmap_(nullptr) {}
};
void setup_pmap(pmap_state &state, std::size_t sz) {
state.prev_pmap_ = this->current_;
this->current_ = &state.pmap_;
state.pmap_.init(&this->strm_, sz);
}
void commit_pmap(pmap_state &state) {
if (state.prev_pmap_) {
state.pmap_.commit();
this->current_ = state.prev_pmap_;
}
}
void visit(enum_cref cref) {
uint64_cref tmp{cref};
this->visit(tmp);
}
void visit(set_cref cref) {
uint64_cref tmp{cref};
this->visit(tmp);
}
template <typename SimpleCRef> void visit(SimpleCRef cref);
template <typename IntType> void visit(int_vector_cref<IntType> cref);
void visit(group_cref cref, int);
void visit(sequence_cref, int);
void visit(sequence_element_cref cref, int);
void visit(nested_message_cref, int);
void visit(message_cref cref, bool force_reset);
};
inline fast_encoder_impl::fast_encoder_impl(allocator *alloc)
: simple_template_repo_t(alloc), strm_(alloc), active_message_id_(-1) {}
fast_encoder_impl::~fast_encoder_impl() {}
inline encoder_presence_map &fast_encoder_impl::current_pmap() {
return *current_;
}
template <typename SimpleCRef>
inline void fast_encoder_impl::visit(SimpleCRef cref) {
const encoder_field_operator *field_operator =
encoder_operators[cref.instruction()->field_operator()];
field_operator->encode(cref, strm_, current_pmap());
}
template <typename IntType>
void fast_encoder_impl::visit(int_vector_cref<IntType> cref) {
strm_.encode(static_cast<uint32_t>(cref.size()), !cref.present(),
cref.optional());
if (cref.present()) {
for (std::size_t i = 0; i < cref.size(); ++i) {
strm_.encode(cref[i], false, false);
}
}
}
inline void fast_encoder_impl::visit(group_cref cref, int) {
// If a group field is optional, it will occupy a single bit in the presence
// map.
// The contents of the group may appear in the stream iff the bit is set.
if (cref.optional()) {
current_pmap().set_next_bit(cref.present());
if (cref.absent())
return;
}
pmap_state state;
if (cref.instruction()->segment_pmap_size() > 0) {
setup_pmap(state, cref.instruction()->segment_pmap_size());
}
// apply_accessor(*this, field);;
for (auto &&field : aggregate_cref(cref)) {
apply_accessor(*this, field);
}
commit_pmap(state);
}
inline void fast_encoder_impl::visit(sequence_cref cref, int) {
if (cref.instruction()->optional() && !cref.present()) {
if (cref.instruction()->length_instruction()->pmap_size() > 0)
this->current_->set_next_bit(false);
if (cref.instruction()->length_instruction()->field_operator() != operator_constant &&
cref.instruction()->length_instruction()->field_operator() != operator_default &&
cref.instruction()->length_instruction()->field_operator() != operator_copy)
strm_.encode_null();
return;
}
value_storage storage;
uint32_mref length_mref(nullptr, &storage,
cref.instruction()->length_instruction());
if (cref.present())
length_mref.as(cref.size());
else
length_mref.omit();
this->visit(length_mref);
if (length_mref.present() && length_mref.value() > 0) {
// apply_accessor(*this, field);;
for (auto &&elem : cref) {
this->visit(elem, 0);
}
}
}
inline void fast_encoder_impl::visit(sequence_element_cref cref, int) {
pmap_state state;
if (cref.instruction()->segment_pmap_size() > 0) {
setup_pmap(state, cref.instruction()->segment_pmap_size());
}
for (auto &&field : cref) {
apply_accessor(*this, field);
}
commit_pmap(state);
}
inline void fast_encoder_impl::visit(nested_message_cref cref, int) {
int64_t saved_message_id = active_message_id_;
encoder_presence_map *prev_pmap = this->current_;
visit(cref.target(), false);
this->current_ = prev_pmap;
active_message_id_ = saved_message_id;
}
void fast_encoder_impl::visit(message_cref cref, bool force_reset) {
encoder_presence_map pmap;
this->current_ = &pmap;
uint32_t template_id = cref.id();
template_instruction *instruction = *this->find(template_id);
if (instruction != nullptr) {
constexpr std::size_t template_id_bit = 1;
current_pmap().init(&this->strm_, std::max<std::size_t>(instruction->segment_pmap_size() + template_id_bit, 1));
} else {
using namespace coder;
BOOST_THROW_EXCEPTION(fast_dynamic_error("D9")
<< template_id_info(template_id));
}
if (force_reset || instruction->has_reset_attribute())
this->reset_dictionary();
bool need_encode_template_id = (active_message_id_ != template_id);
current_pmap().set_next_bit(need_encode_template_id);
if (need_encode_template_id) {
active_message_id_ = template_id;
strm_.encode(template_id, false, false);
}
aggregate_cref message(cref.field_storage(0), instruction);
for (auto &&field : message)
{
if (field.present() || field.instruction()->field_operator() == operator_none)
apply_accessor(*this, field);
else if (!field.present() && field.instruction()->pmap_size())
current_pmap().set_next_bit(false);
}
pmap.commit();
}
fast_encoder::fast_encoder(allocator *alloc)
: impl_(new fast_encoder_impl(alloc)) {}
fast_encoder::~fast_encoder() { delete impl_; }
void fast_encoder::include(const templates_description *const *descriptions,
std::size_t description_count) {
impl_->build(descriptions, description_count);
template_instruction **entry = impl_->unique_entry();
if (entry != nullptr) {
impl_->active_message_id_ = (*entry)->id();
}
}
std::size_t fast_encoder::encode(const message_cref &message, char *buffer,
std::size_t buffer_size, bool force_reset) {
assert(buffer_size > 0);
fast_ostreambuf sb(buffer, buffer_size);
impl_->strm_.rdbuf(&sb);
impl_->visit(message, force_reset);
return sb.length();
}
void fast_encoder::encode(const message_cref &message,
std::vector<char> &buffer, bool force_reset) {
resizable_fast_ostreambuf sb(buffer);
impl_->strm_.rdbuf(&sb);
impl_->visit(message, force_reset);
buffer.resize(sb.length());
}
const template_instruction *fast_encoder::template_with_id(uint32_t id) {
return impl_->get_template(id);
}
void fast_encoder::allow_overlong_pmap(bool v) {
impl_->strm_.allow_overlong_pmap(v);
}
}