Merge lp:~tes/dccl/3.0-codec-groups into lp:~dccl-dev/dccl/3.0
- 3.0-codec-groups
- Merge into 3.0
Status: | Merged |
---|---|
Approved by: | toby schneider |
Approved revision: | 321 |
Merged at revision: | 297 |
Proposed branch: | lp:~tes/dccl/3.0-codec-groups |
Merge into: | lp:~dccl-dev/dccl/3.0 |
Diff against target: |
5407 lines (+2997/-930) 60 files modified
CMakeLists.txt (+2/-4) src/CMakeLists.txt (+12/-2) src/apps/dccl/dccl_tool.cpp (+208/-103) src/arithmetic/field_codec_arithmetic.cpp (+25/-2) src/binary.h (+23/-0) src/ccl/CMakeLists.txt (+0/-1) src/ccl/ccl_compatibility.cpp (+44/-17) src/ccl/ccl_compatibility.h (+3/-4) src/codec.cpp (+68/-30) src/codec.h (+28/-10) src/codecs2/field_codec_default.cpp (+25/-105) src/codecs2/field_codec_default.h (+299/-319) src/codecs2/field_codec_default_message.cpp (+15/-15) src/codecs2/field_codec_default_message.h (+159/-201) src/codecs3/field_codec_default.cpp (+122/-0) src/codecs3/field_codec_default.h (+77/-0) src/codecs3/field_codec_default_message.cpp (+236/-0) src/codecs3/field_codec_default_message.h (+213/-0) src/field_codec.cpp (+82/-18) src/field_codec.h (+47/-5) src/field_codec_id.cpp (+100/-0) src/field_codec_id.h (+50/-0) src/field_codec_manager.h (+169/-28) src/field_codec_message_stack.cpp (+38/-4) src/field_codec_message_stack.h (+7/-16) src/field_codec_typed.h (+12/-3) src/logger.cpp (+6/-4) src/logger.h (+2/-1) src/protobuf/option_extensions.proto (+8/-5) src/test/CMakeLists.txt (+5/-0) src/test/dccl_all_fields/test.cpp (+3/-1) src/test/dccl_all_fields/test.proto (+2/-2) src/test/dccl_arithmetic/test.proto (+7/-1) src/test/dccl_ccl/test.cpp (+2/-4) src/test/dccl_ccl/test.proto (+1/-0) src/test/dccl_codec_group/CMakeLists.txt (+6/-0) src/test/dccl_codec_group/test.cpp (+104/-0) src/test/dccl_codec_group/test.proto (+77/-0) src/test/dccl_custom_id/test.proto (+3/-0) src/test/dccl_custom_message/test.proto (+2/-0) src/test/dccl_default_id/test.proto (+8/-1) src/test/dccl_header/header.proto (+9/-18) src/test/dccl_header/test.cpp (+1/-1) src/test/dccl_header/test.proto (+2/-1) src/test/dccl_message_fix/CMakeLists.txt (+6/-0) src/test/dccl_message_fix/test.cpp (+110/-0) src/test/dccl_message_fix/test.proto (+31/-0) src/test/dccl_numeric_bounds/test.proto (+3/-0) src/test/dccl_repeated/test.cpp (+0/-1) src/test/dccl_repeated/test.proto (+3/-0) src/test/dccl_required_optional/test.proto (+1/-0) src/test/dccl_static_methods/test.proto (+3/-0) src/test/dccl_v2_all_fields/CMakeLists.txt (+6/-0) src/test/dccl_v2_all_fields/test.cpp (+175/-0) src/test/dccl_v2_all_fields/test.proto (+159/-0) src/test/dccl_v2_header/CMakeLists.txt (+6/-0) src/test/dccl_v2_header/header.proto (+54/-0) src/test/dccl_v2_header/test.cpp (+92/-0) src/test/dccl_v2_header/test.proto (+16/-0) src/type_helper.h (+20/-3) |
To merge this branch: | bzr merge lp:~tes/dccl/3.0-codec-groups |
Related bugs: | |
Related blueprints: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chris Murphy (community) | Approve | ||
Review via email: mp+216939@code.launchpad.net |
Commit message
Description of the change
Two blueprints implemented:
1. http://
These changes allow a user to change the codec name that is used for every field in an entire message with a single DCCLMessageOption. In addition, it defines an integer for the codec_version = N that resolves to a codec_group of "dccl.defaultN". This allows us to write new codecs for version 3 that fix bugs, improve functionality from version 2 while preserving backwards compatibility (since codec_version defaults to 2, the first version of Goby/DCCL that used Google Protobuf).
2. http://
These changes build on the codec_version defined in 1. to fix bugs and improve the efficiency of the DefaultMessageCodec and all the "repeated" field codecs that rely on the FieldCodecBase implementation (i.e. repeated calls of the singular encode/decode).
The links above go into more detail regarding the changes.
- 315. By toby schneider
-
Added exports for additional dccl libraries (ccl and arithmetic)
- 316. By toby schneider
-
Fixed export install location
- 317. By toby schneider
-
Added logging of size of each field to dlog
- 318. By toby schneider
-
1. Add vector size for repeated fields when reporting size during encode, 2. Restore setfill after timestamp formatting for logger
- 319. By toby schneider
-
Added b64_encode and b64_decode helper functions that are similar to their hex_* equivalents; Added 'loaded()' method to Codec to allow a user to see all the loaded DCCL messages
- 320. By toby schneider
-
Changed default string codec in v3 to use a length prefix that is sized based on max_length (not fixed to 8 bits)
- 321. By toby schneider
-
Added warning for users who don't specify (dccl.msg)
.codec_ version to encourage use of the DCCL3 defaults: option (dccl.msg) .codec_ version= 3
toby schneider (tes) wrote : | # |
The deprecation warning (1.) is included in this merge.
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-01-06 17:25:02 +0000 |
3 | +++ CMakeLists.txt 2014-08-27 16:27:22 +0000 |
4 | @@ -72,7 +72,7 @@ |
5 | install(DIRECTORY ${dccl_INC_DIR}/ DESTINATION ${CMAKE_INSTALL_PREFIX}/include |
6 | FILES_MATCHING PATTERN "*.h" PATTERN "*.proto" PATTERN "test*" EXCLUDE) |
7 | |
8 | -install(EXPORT dccl-config DESTINATION share/${PROJECTNAME}/cmake) |
9 | +install(EXPORT dccl-config DESTINATION share/dccl/cmake) |
10 | |
11 | ## let cmake know where the headers are |
12 | include_directories(${dccl_INC_DIR}) |
13 | @@ -132,10 +132,8 @@ |
14 | include_directories(${Cryptopp_INCLUDE_DIRS}) |
15 | endif() |
16 | |
17 | + |
18 | ## start adding subdirectories |
19 | add_subdirectory(src) |
20 | |
21 | -## export a file for folks to use |
22 | -export(TARGETS dccl FILE ${CMAKE_BINARY_DIR}/dccl-config.cmake) |
23 | -file(APPEND ${CMAKE_BINARY_DIR}/dccl-config.cmake "set(DCCL_INCLUDE_DIR \"${dccl_INC_DIR}\")") |
24 | |
25 | |
26 | === modified file 'src/CMakeLists.txt' |
27 | --- src/CMakeLists.txt 2014-01-08 22:30:52 +0000 |
28 | +++ src/CMakeLists.txt 2014-08-27 16:27:22 +0000 |
29 | @@ -10,9 +10,12 @@ |
30 | codec.cpp |
31 | field_codec.cpp |
32 | field_codec_message_stack.cpp |
33 | - field_codec_default.cpp |
34 | - field_codec_default_message.cpp |
35 | field_codec_manager.cpp |
36 | + field_codec_id.cpp |
37 | + codecs2/field_codec_default.cpp |
38 | + codecs2/field_codec_default_message.cpp |
39 | + codecs3/field_codec_default_message.cpp |
40 | + codecs3/field_codec_default.cpp |
41 | type_helper.cpp |
42 | bitset.cpp |
43 | dynamic_protobuf_manager.cpp |
44 | @@ -32,14 +35,21 @@ |
45 | option(build_arithmetic "Build arithmetic coders shared library" ON) |
46 | option(build_ccl "Build Compact Control Language (CCL) legacy support shared library" ON) |
47 | |
48 | +set(DCCL_EXPORT_TARGETS dccl) |
49 | + |
50 | if(build_ccl) |
51 | add_subdirectory(ccl) |
52 | + set(DCCL_EXPORT_TARGETS ${DCCL_EXPORT_TARGETS} dccl_ccl_compat) |
53 | endif() |
54 | |
55 | if(build_arithmetic) |
56 | add_subdirectory(arithmetic) |
57 | + set(DCCL_EXPORT_TARGETS ${DCCL_EXPORT_TARGETS} dccl_arithmetic) |
58 | endif() |
59 | |
60 | +export(TARGETS ${DCCL_EXPORT_TARGETS} FILE ${CMAKE_BINARY_DIR}/dccl-config.cmake) |
61 | +file(APPEND ${CMAKE_BINARY_DIR}/dccl-config.cmake "set(DCCL_INCLUDE_DIR \"${dccl_INC_DIR}\")") |
62 | + |
63 | if(enable_testing) |
64 | add_subdirectory(test) |
65 | endif() |
66 | |
67 | === modified file 'src/apps/dccl/dccl_tool.cpp' |
68 | --- src/apps/dccl/dccl_tool.cpp 2014-04-22 20:08:20 +0000 |
69 | +++ src/apps/dccl/dccl_tool.cpp 2014-08-27 16:27:22 +0000 |
70 | @@ -26,6 +26,8 @@ |
71 | |
72 | |
73 | #include <sstream> |
74 | +#include <fstream> |
75 | + |
76 | |
77 | #include <google/protobuf/descriptor.h> |
78 | #include <google/protobuf/text_format.h> |
79 | @@ -40,13 +42,16 @@ |
80 | #include "dccl_tool.pb.h" |
81 | |
82 | enum Action { NO_ACTION, ENCODE, DECODE, ANALYZE, DISP_PROTO }; |
83 | -enum Format { TEXTFORMAT, HEX, BASE64 }; |
84 | +enum Format { BINARY, TEXTFORMAT, HEX, BASE64 }; |
85 | |
86 | struct Config |
87 | { |
88 | Config() |
89 | : action(NO_ACTION), |
90 | - format(HEX) |
91 | + format(BINARY), |
92 | + id_codec(dccl::Codec::default_id_codec_name()), |
93 | + verbose(false), |
94 | + omit_prefix(false) |
95 | { } |
96 | |
97 | Action action; |
98 | @@ -55,11 +60,14 @@ |
99 | std::set<std::string> message; |
100 | std::set<std::string> proto_file; |
101 | Format format; |
102 | + std::string id_codec; |
103 | + bool verbose; |
104 | + bool omit_prefix; |
105 | }; |
106 | |
107 | |
108 | void analyze(dccl::Codec& dccl, const Config& cfg); |
109 | -void encode(dccl::Codec& dccl, const Config& cfg); |
110 | +void encode(dccl::Codec& dccl, Config& cfg); |
111 | void decode(dccl::Codec& dccl, const Config& cfg); |
112 | void disp_proto(dccl::Codec& dccl, const Config& cfg); |
113 | |
114 | @@ -67,67 +75,95 @@ |
115 | void load_desc(dccl::Codec* dccl, const google::protobuf::Descriptor* desc, const std::string& name); |
116 | void parse_options(int argc, char* argv[], Config* cfg); |
117 | |
118 | + |
119 | int main(int argc, char* argv[]) |
120 | { |
121 | - Config cfg; |
122 | - parse_options(argc, argv, &cfg); |
123 | - |
124 | - dccl::dlog.connect(dccl::logger::WARN_PLUS, &std::cerr); |
125 | - |
126 | - dccl::DynamicProtobufManager::enable_compilation(); |
127 | - |
128 | - for(std::set<std::string>::const_iterator it = cfg.include.begin(), |
129 | - end = cfg.include.end(); it != end; ++it) |
130 | - dccl::DynamicProtobufManager::add_include_path(*it); |
131 | - |
132 | - dccl::Codec dccl; |
133 | - for(std::set<std::string>::const_iterator it = cfg.dlopen.begin(), |
134 | - end = cfg.dlopen.end(); it != end; ++it) |
135 | - dccl.load_library(*it); |
136 | - |
137 | - for(std::set<std::string>::const_iterator it = cfg.proto_file.begin(), |
138 | - end = cfg.proto_file.end(); it != end; ++it) |
139 | - { |
140 | - const google::protobuf::FileDescriptor* file_desc = |
141 | - dccl::DynamicProtobufManager::load_from_proto_file(*it); |
142 | - |
143 | - if(!file_desc) |
144 | - { |
145 | - std::cerr << "failed to read in: " << *it << std::endl; |
146 | - exit(EXIT_FAILURE); |
147 | - } |
148 | - |
149 | - // if no messages explicity specified, load them all. |
150 | - if(cfg.message.empty()) |
151 | - { |
152 | - for(int i = 0, n = file_desc->message_type_count(); i < n; ++i) |
153 | - { |
154 | - const google::protobuf::Descriptor* desc = file_desc->message_type(i); |
155 | - cfg.message.insert(file_desc->message_type(i)->full_name()); |
156 | - } |
157 | - } |
158 | - } |
159 | - |
160 | - // Load up all the messages |
161 | - for(std::set<std::string>::const_iterator it = cfg.message.begin(), |
162 | - end = cfg.message.end(); it != end; ++it) |
163 | - { |
164 | - const google::protobuf::Descriptor* desc = |
165 | - dccl::DynamicProtobufManager::find_descriptor(*it); |
166 | - load_desc(&dccl, desc, *it); |
167 | - } |
168 | - |
169 | - switch(cfg.action) |
170 | - { |
171 | - case ENCODE: encode(dccl, cfg); break; |
172 | - case DECODE: decode(dccl, cfg); break; |
173 | - case ANALYZE: analyze(dccl, cfg); break; |
174 | - case DISP_PROTO: disp_proto(dccl, cfg); break; |
175 | - default: |
176 | - std::cerr << "No action specified (e.g. analyze, decode, encode). Try --help." << std::endl; |
177 | - exit(EXIT_SUCCESS); |
178 | - |
179 | - } |
180 | + std::vector<void *> dl_handles; |
181 | + { |
182 | + Config cfg; |
183 | + parse_options(argc, argv, &cfg); |
184 | + |
185 | + if(!cfg.verbose) |
186 | + dccl::dlog.connect(dccl::logger::WARN_PLUS, &std::cerr); |
187 | + else |
188 | + dccl::dlog.connect(dccl::logger::DEBUG1_PLUS, &std::cerr); |
189 | + |
190 | + dccl::DynamicProtobufManager::enable_compilation(); |
191 | + |
192 | + for(std::set<std::string>::const_iterator it = cfg.include.begin(), |
193 | + end = cfg.include.end(); it != end; ++it) |
194 | + dccl::DynamicProtobufManager::add_include_path(*it); |
195 | + |
196 | + for(std::set<std::string>::const_iterator it = cfg.dlopen.begin(), |
197 | + end = cfg.dlopen.end(); it != end; ++it) |
198 | + { |
199 | + void* handle = dlopen(it->c_str(), RTLD_LAZY); |
200 | + if(handle) |
201 | + { |
202 | + dl_handles.push_back(handle); |
203 | + } |
204 | + else |
205 | + { |
206 | + std::cerr << "Failed to open shared library: " << *it << std::endl; |
207 | + exit(EXIT_FAILURE); |
208 | + } |
209 | + |
210 | + } |
211 | + |
212 | + dccl::Codec dccl(cfg.id_codec); |
213 | + for(std::vector<void *>::iterator it = dl_handles.begin(), |
214 | + n = dl_handles.end(); it != n; ++it) |
215 | + dccl.load_library(*it); |
216 | + |
217 | + bool no_messages_specified = cfg.message.empty(); |
218 | + for(std::set<std::string>::const_iterator it = cfg.proto_file.begin(), |
219 | + end = cfg.proto_file.end(); it != end; ++it) |
220 | + { |
221 | + const google::protobuf::FileDescriptor* file_desc = |
222 | + dccl::DynamicProtobufManager::load_from_proto_file(*it); |
223 | + |
224 | + if(!file_desc) |
225 | + { |
226 | + std::cerr << "failed to read in: " << *it << std::endl; |
227 | + exit(EXIT_FAILURE); |
228 | + } |
229 | + |
230 | + // if no messages explicitly specified, load them all. |
231 | + if(no_messages_specified && cfg.action != ENCODE) |
232 | + { |
233 | + for(int i = 0, n = file_desc->message_type_count(); i < n; ++i) |
234 | + { |
235 | + cfg.message.insert(file_desc->message_type(i)->full_name()); |
236 | + } |
237 | + } |
238 | + } |
239 | + |
240 | + // Load up all the messages |
241 | + for(std::set<std::string>::const_iterator it = cfg.message.begin(), |
242 | + end = cfg.message.end(); it != end; ++it) |
243 | + { |
244 | + const google::protobuf::Descriptor* desc = |
245 | + dccl::DynamicProtobufManager::find_descriptor(*it); |
246 | + load_desc(&dccl, desc, *it); |
247 | + } |
248 | + |
249 | + switch(cfg.action) |
250 | + { |
251 | + case ENCODE: encode(dccl, cfg); break; |
252 | + case DECODE: decode(dccl, cfg); break; |
253 | + case ANALYZE: analyze(dccl, cfg); break; |
254 | + case DISP_PROTO: disp_proto(dccl, cfg); break; |
255 | + default: |
256 | + std::cerr << "No action specified (e.g. analyze, decode, encode). Try --help." << std::endl; |
257 | + exit(EXIT_SUCCESS); |
258 | + |
259 | + } |
260 | + } |
261 | + |
262 | + for(std::vector<void *>::iterator it = dl_handles.begin(), |
263 | + n = dl_handles.end(); it != n; ++it) |
264 | + dlclose(*it); |
265 | + |
266 | } |
267 | |
268 | |
269 | @@ -137,16 +173,14 @@ |
270 | dccl.info_all(&std::cout); |
271 | } |
272 | |
273 | -void encode(dccl::Codec& dccl, const Config& cfg) |
274 | +void encode(dccl::Codec& dccl, Config& cfg) |
275 | { |
276 | - if(cfg.message.size() != 1) |
277 | + if(cfg.message.size() > 1) |
278 | { |
279 | - std::cerr << "Exactly one DCCL message must be specified with -m or --message" << std::endl; |
280 | + std::cerr << "No more than one DCCL message can be specified with -m or --message for encoding." << std::endl; |
281 | exit(EXIT_FAILURE); |
282 | } |
283 | - const google::protobuf::Descriptor* desc = |
284 | - dccl::DynamicProtobufManager::find_descriptor(*cfg.message.begin()); |
285 | - int dccl_id = dccl.id(desc); |
286 | + std::string command_line_name = *cfg.message.begin(); |
287 | |
288 | while(!std::cin.eof()) |
289 | { |
290 | @@ -156,6 +190,50 @@ |
291 | boost::trim(input); |
292 | if(input.empty()) |
293 | continue; |
294 | + |
295 | + std::string name; |
296 | + if(input[0] == '|') |
297 | + { |
298 | + std::string::size_type close_bracket_pos = input.find('|', 1); |
299 | + if(close_bracket_pos == std::string::npos) |
300 | + { |
301 | + std::cerr << "Incorrectly formatted input: expected '|'" << std::endl; |
302 | + exit(EXIT_FAILURE); |
303 | + } |
304 | + |
305 | + name = input.substr(1, close_bracket_pos-1); |
306 | + if(cfg.message.find(name) == cfg.message.end()) |
307 | + { |
308 | + const google::protobuf::Descriptor* desc = |
309 | + dccl::DynamicProtobufManager::find_descriptor(name); |
310 | + load_desc(&dccl, desc, name); |
311 | + cfg.message.insert(name); |
312 | + } |
313 | + |
314 | + |
315 | + if(input.size() > close_bracket_pos+1) |
316 | + input = input.substr(close_bracket_pos+1); |
317 | + else |
318 | + input.clear(); |
319 | + } |
320 | + else |
321 | + { |
322 | + if(cfg.message.size() == 0) |
323 | + { |
324 | + std::cerr << "Message name not given with -m or in the input (i.e. '[Name] field1: value field2: value')." << std::endl; |
325 | + exit(EXIT_FAILURE); |
326 | + } |
327 | + |
328 | + name = command_line_name; |
329 | + } |
330 | + |
331 | + const google::protobuf::Descriptor* desc = dccl::DynamicProtobufManager::find_descriptor(name); |
332 | + if(desc == 0) |
333 | + { |
334 | + std::cerr << "No descriptor with name " << name << " found! Make sure you have loaded all the necessary .proto files and/or shared libraries. Also make sure you specified the fully qualified name including the package, if any (e.g. 'goby.acomms.protobuf.NetworkAck', not just 'NetworkAck')." << std::endl; |
335 | + exit(EXIT_FAILURE); |
336 | + } |
337 | + |
338 | |
339 | boost::shared_ptr<google::protobuf::Message> msg = dccl::DynamicProtobufManager::new_protobuf_message(desc); |
340 | google::protobuf::TextFormat::ParseFromString(input, msg.get()); |
341 | @@ -167,6 +245,13 @@ |
342 | switch(cfg.format) |
343 | { |
344 | default: |
345 | + case BINARY: |
346 | + { |
347 | + std::ofstream fout("/dev/stdout", std::ios::binary | std::ios::app); |
348 | + fout.write(encoded.data(), encoded.size()); |
349 | + break; |
350 | + } |
351 | + |
352 | case TEXTFORMAT: |
353 | { |
354 | |
355 | @@ -197,49 +282,61 @@ |
356 | |
357 | void decode(dccl::Codec& dccl, const Config& cfg) |
358 | { |
359 | - if(cfg.message.size() != 1) |
360 | + std::string input; |
361 | + if(cfg.format == BINARY) |
362 | { |
363 | - std::cerr << "Exactly one DCCL message must be specified with -m or --message" << std::endl; |
364 | - exit(EXIT_FAILURE); |
365 | + std::ifstream fin("/dev/stdin", std::ios::binary); |
366 | + std::ostringstream ostrm; |
367 | + ostrm << fin.rdbuf(); |
368 | + input = ostrm.str(); |
369 | } |
370 | - |
371 | - while(!std::cin.eof()) |
372 | + else |
373 | { |
374 | - std::string input; |
375 | - std::getline (std::cin, input); |
376 | - |
377 | - if(boost::trim_copy(input).empty()) |
378 | - continue; |
379 | - |
380 | - switch(cfg.format) |
381 | + while(!std::cin.eof()) |
382 | { |
383 | - default: |
384 | - case TEXTFORMAT: |
385 | + std::string line; |
386 | + std::getline (std::cin, line); |
387 | + |
388 | + if(boost::trim_copy(line).empty()) |
389 | + continue; |
390 | + |
391 | + switch(cfg.format) |
392 | { |
393 | - boost::trim_if(input, boost::is_any_of("\"")); |
394 | - |
395 | - |
396 | - ByteString s; |
397 | - google::protobuf::TextFormat::ParseFieldValueFromString("\"" + input + "\"", s.GetDescriptor()->FindFieldByNumber(1), &s); |
398 | - input = s.b(); |
399 | - break; |
400 | + default: |
401 | + case BINARY: |
402 | + break; |
403 | + |
404 | + case TEXTFORMAT: |
405 | + { |
406 | + boost::trim_if(line, boost::is_any_of("\"")); |
407 | + |
408 | + |
409 | + ByteString s; |
410 | + google::protobuf::TextFormat::ParseFieldValueFromString("\"" + line + "\"", s.GetDescriptor()->FindFieldByNumber(1), &s); |
411 | + input += s.b(); |
412 | + break; |
413 | + } |
414 | + case HEX: |
415 | + input += dccl::hex_decode(line); |
416 | + break; |
417 | + case BASE64: |
418 | + std::stringstream instream(line); |
419 | + std::stringstream outstream; |
420 | + base64::decoder D; |
421 | + D.decode(instream, outstream); |
422 | + input += outstream.str(); |
423 | + break; |
424 | } |
425 | - case HEX: |
426 | - input = dccl::hex_decode(input); |
427 | - break; |
428 | - case BASE64: |
429 | - std::string in = input; |
430 | - std::stringstream instream(input); |
431 | - std::stringstream outstream; |
432 | - base64::decoder D; |
433 | - D.decode(instream, outstream); |
434 | - input = outstream.str(); |
435 | - break; |
436 | } |
437 | + } |
438 | |
439 | - boost::shared_ptr<google::protobuf::Message> msg = dccl.decode<boost::shared_ptr<google::protobuf::Message> >(input); |
440 | + while(!input.empty()) |
441 | + { |
442 | + boost::shared_ptr<google::protobuf::Message> msg = dccl.decode<boost::shared_ptr<google::protobuf::Message> >(&input); |
443 | + if(!cfg.omit_prefix) |
444 | + std::cout << "|" << msg->GetDescriptor()->full_name() << "| "; |
445 | std::cout << msg->ShortDebugString() << std::endl; |
446 | - } |
447 | + } |
448 | } |
449 | |
450 | void disp_proto(dccl::Codec& dccl, const Config& cfg) |
451 | @@ -286,7 +383,10 @@ |
452 | options.push_back(dccl::Option('l', "dlopen", required_argument, "Open this shared library containing compiled DCCL messages.")); |
453 | options.push_back(dccl::Option('m', "message", required_argument, "Message name to encode, decode or analyze.")); |
454 | options.push_back(dccl::Option('f', "proto_file", required_argument, ".proto file to load.")); |
455 | - options.push_back(dccl::Option(0, "format", required_argument, "Format for encode output or decode input: 'hex' is ascii-encoded hexadecimal (default), 'textformat' is a Google Protobuf TextFormat byte string, 'base64' is ascii-encoded base 64.")); |
456 | + options.push_back(dccl::Option(0, "format", required_argument, "Format for encode output or decode input: 'bin' (default) is raw binary, 'hex' is ascii-encoded hexadecimal, 'textformat' is a Google Protobuf TextFormat byte string, 'base64' is ascii-encoded base 64.")); |
457 | + options.push_back(dccl::Option('v', "verbose", no_argument, "Display extra debugging information.")); |
458 | + options.push_back(dccl::Option('o', "omit_prefix", no_argument, "Omit the DCCL type name prefix from the output of decode.")); |
459 | + options.push_back(dccl::Option('i', "id_codec", required_argument, "(Advanced) name for a nonstandard DCCL ID codec to use")); |
460 | |
461 | std::vector<option> long_options; |
462 | std::string opt_string; |
463 | @@ -314,6 +414,8 @@ |
464 | cfg->format = HEX; |
465 | else if(!strcmp(optarg, "base64")) |
466 | cfg->format = BASE64; |
467 | + else if(!strcmp(optarg, "bin")) |
468 | + cfg->format = BINARY; |
469 | else |
470 | { |
471 | std::cerr << "Invalid format '" << optarg << "'" << std::endl; |
472 | @@ -336,6 +438,9 @@ |
473 | case 'l': cfg->dlopen.insert(optarg); break; |
474 | case 'm': cfg->message.insert(optarg); break; |
475 | case 'f': cfg->proto_file.insert(optarg); break; |
476 | + case 'i': cfg->id_codec = optarg; break; |
477 | + case 'v': cfg->verbose = true; break; |
478 | + case 'o': cfg->omit_prefix = true; break; |
479 | |
480 | case 'h': |
481 | std::cout << "Usage of the Dynamic Compact Control Language (DCCL) tool ('dccl'): " << std::endl; |
482 | |
483 | === modified file 'src/arithmetic/field_codec_arithmetic.cpp' |
484 | --- src/arithmetic/field_codec_arithmetic.cpp 2013-06-18 12:55:43 +0000 |
485 | +++ src/arithmetic/field_codec_arithmetic.cpp 2014-08-27 16:27:22 +0000 |
486 | @@ -38,9 +38,9 @@ |
487 | |
488 | // shared library load |
489 | |
490 | -extern "C" |
491 | +struct CodecLoader |
492 | { |
493 | - void dccl3_load(dccl::Codec* dccl) |
494 | + CodecLoader() |
495 | { |
496 | using namespace dccl; |
497 | |
498 | @@ -53,6 +53,29 @@ |
499 | FieldCodecManager::add<ArithmeticFieldCodec<bool> >("_arithmetic"); |
500 | FieldCodecManager::add<ArithmeticFieldCodec<const google::protobuf::EnumValueDescriptor*> >("_arithmetic"); |
501 | } |
502 | + ~CodecLoader() |
503 | + { |
504 | + using namespace dccl; |
505 | + |
506 | + FieldCodecManager::remove<ArithmeticFieldCodec<int32> >("_arithmetic"); |
507 | + FieldCodecManager::remove<ArithmeticFieldCodec<int64> >("_arithmetic"); |
508 | + FieldCodecManager::remove<ArithmeticFieldCodec<uint32> >("_arithmetic"); |
509 | + FieldCodecManager::remove<ArithmeticFieldCodec<uint64> >("_arithmetic"); |
510 | + FieldCodecManager::remove<ArithmeticFieldCodec<double> >("_arithmetic"); |
511 | + FieldCodecManager::remove<ArithmeticFieldCodec<float> >("_arithmetic"); |
512 | + FieldCodecManager::remove<ArithmeticFieldCodec<bool> >("_arithmetic"); |
513 | + FieldCodecManager::remove<ArithmeticFieldCodec<const google::protobuf::EnumValueDescriptor*> >("_arithmetic"); |
514 | + } |
515 | +}; |
516 | + |
517 | + |
518 | +static CodecLoader loader; |
519 | + |
520 | +extern "C" |
521 | +{ |
522 | + void dccl3_load(dccl::Codec* dccl) |
523 | + { |
524 | + } |
525 | } |
526 | |
527 | dccl::Model::symbol_type dccl::Model::value_to_symbol(value_type value) const |
528 | |
529 | === modified file 'src/binary.h' |
530 | --- src/binary.h 2014-04-22 20:10:37 +0000 |
531 | +++ src/binary.h 2014-08-27 16:27:22 +0000 |
532 | @@ -29,6 +29,8 @@ |
533 | #include <sstream> |
534 | |
535 | #include "dccl/common.h" |
536 | +#include "dccl/b64/encode.h" |
537 | +#include "dccl/b64/decode.h" |
538 | |
539 | namespace dccl |
540 | { |
541 | @@ -124,6 +126,27 @@ |
542 | hex_encode(in, &out); |
543 | return out; |
544 | } |
545 | + |
546 | + |
547 | + inline std::string b64_encode(const std::string& in) |
548 | + { |
549 | + std::stringstream instream(in); |
550 | + std::stringstream outstream; |
551 | + base64::encoder D; |
552 | + D.encode(instream, outstream); |
553 | + return outstream.str(); |
554 | + } |
555 | + |
556 | + inline std::string b64_decode(const std::string& in) |
557 | + { |
558 | + std::stringstream instream(in); |
559 | + std::stringstream outstream; |
560 | + base64::decoder D; |
561 | + D.decode(instream, outstream); |
562 | + return outstream.str(); |
563 | + } |
564 | + |
565 | + |
566 | |
567 | /// \return ceil(log2(v)) |
568 | inline unsigned ceil_log2(dccl::uint64 v) |
569 | |
570 | === modified file 'src/ccl/CMakeLists.txt' |
571 | --- src/ccl/CMakeLists.txt 2014-01-06 17:25:02 +0000 |
572 | +++ src/ccl/CMakeLists.txt 2014-08-27 16:27:22 +0000 |
573 | @@ -17,7 +17,6 @@ |
574 | set_target_properties(dccl_ccl_compat |
575 | PROPERTIES VERSION "${DCCL_VERSION}" SOVERSION "${DCCL_SOVERSION}") |
576 | |
577 | - |
578 | install(TARGETS dccl_ccl_compat EXPORT dccl-config |
579 | LIBRARY DESTINATION lib |
580 | ARCHIVE DESTINATION lib) |
581 | |
582 | === modified file 'src/ccl/ccl_compatibility.cpp' |
583 | --- src/ccl/ccl_compatibility.cpp 2013-06-18 12:55:43 +0000 |
584 | +++ src/ccl/ccl_compatibility.cpp 2014-08-27 16:27:22 +0000 |
585 | @@ -31,27 +31,54 @@ |
586 | |
587 | // shared library load |
588 | |
589 | +struct CodecLoader |
590 | +{ |
591 | + CodecLoader() |
592 | + { |
593 | + using namespace dccl; |
594 | + FieldCodecManager::add<LegacyCCLIdentifierCodec>("dccl.ccl.id"); |
595 | + |
596 | + FieldCodecManager::add<LegacyCCLLatLonCompressedCodec>("_ccl_latloncompressed"); |
597 | + FieldCodecManager::add<LegacyCCLFixAgeCodec>("_ccl_fix_age"); |
598 | + FieldCodecManager::add<LegacyCCLTimeDateCodec>("_ccl_time_date"); |
599 | + FieldCodecManager::add<LegacyCCLHeadingCodec>("_ccl_heading"); |
600 | + FieldCodecManager::add<LegacyCCLDepthCodec>("_ccl_depth"); |
601 | + FieldCodecManager::add<LegacyCCLVelocityCodec>("_ccl_velocity"); |
602 | + FieldCodecManager::add<LegacyCCLWattsCodec>("_ccl_watts"); |
603 | + FieldCodecManager::add<LegacyCCLGFIPitchOilCodec>("_ccl_gfi_pitch_oil"); |
604 | + FieldCodecManager::add<LegacyCCLSpeedCodec>("_ccl_speed"); |
605 | + FieldCodecManager::add<LegacyCCLHiResAltitudeCodec>("_ccl_hires_altitude"); |
606 | + FieldCodecManager::add<LegacyCCLTemperatureCodec>("_ccl_temperature"); |
607 | + FieldCodecManager::add<LegacyCCLSalinityCodec>("_ccl_salinity"); |
608 | + FieldCodecManager::add<LegacyCCLSoundSpeedCodec>("_ccl_sound_speed"); |
609 | + } |
610 | + ~CodecLoader() |
611 | + { |
612 | + using namespace dccl; |
613 | + FieldCodecManager::remove<LegacyCCLIdentifierCodec>("dccl.ccl.id"); |
614 | + |
615 | + FieldCodecManager::remove<LegacyCCLLatLonCompressedCodec>("_ccl_latloncompressed"); |
616 | + FieldCodecManager::remove<LegacyCCLFixAgeCodec>("_ccl_fix_age"); |
617 | + FieldCodecManager::remove<LegacyCCLTimeDateCodec>("_ccl_time_date"); |
618 | + FieldCodecManager::remove<LegacyCCLHeadingCodec>("_ccl_heading"); |
619 | + FieldCodecManager::remove<LegacyCCLDepthCodec>("_ccl_depth"); |
620 | + FieldCodecManager::remove<LegacyCCLVelocityCodec>("_ccl_velocity"); |
621 | + FieldCodecManager::remove<LegacyCCLWattsCodec>("_ccl_watts"); |
622 | + FieldCodecManager::remove<LegacyCCLGFIPitchOilCodec>("_ccl_gfi_pitch_oil"); |
623 | + FieldCodecManager::remove<LegacyCCLSpeedCodec>("_ccl_speed"); |
624 | + FieldCodecManager::remove<LegacyCCLHiResAltitudeCodec>("_ccl_hires_altitude"); |
625 | + FieldCodecManager::remove<LegacyCCLTemperatureCodec>("_ccl_temperature"); |
626 | + FieldCodecManager::remove<LegacyCCLSalinityCodec>("_ccl_salinity"); |
627 | + FieldCodecManager::remove<LegacyCCLSoundSpeedCodec>("_ccl_sound_speed"); |
628 | + } |
629 | +}; |
630 | + |
631 | +static CodecLoader loader; |
632 | |
633 | extern "C" |
634 | { |
635 | void dccl3_load(dccl::Codec* dccl) |
636 | - { |
637 | - using namespace dccl; |
638 | - |
639 | - FieldCodecManager::add<LegacyCCLLatLonCompressedCodec>("_ccl_latloncompressed"); |
640 | - FieldCodecManager::add<LegacyCCLFixAgeCodec>("_ccl_fix_age"); |
641 | - FieldCodecManager::add<LegacyCCLTimeDateCodec>("_ccl_time_date"); |
642 | - FieldCodecManager::add<LegacyCCLHeadingCodec>("_ccl_heading"); |
643 | - FieldCodecManager::add<LegacyCCLDepthCodec>("_ccl_depth"); |
644 | - FieldCodecManager::add<LegacyCCLVelocityCodec>("_ccl_velocity"); |
645 | - FieldCodecManager::add<LegacyCCLWattsCodec>("_ccl_watts"); |
646 | - FieldCodecManager::add<LegacyCCLGFIPitchOilCodec>("_ccl_gfi_pitch_oil"); |
647 | - FieldCodecManager::add<LegacyCCLSpeedCodec>("_ccl_speed"); |
648 | - FieldCodecManager::add<LegacyCCLHiResAltitudeCodec>("_ccl_hires_altitude"); |
649 | - FieldCodecManager::add<LegacyCCLTemperatureCodec>("_ccl_temperature"); |
650 | - FieldCodecManager::add<LegacyCCLSalinityCodec>("_ccl_salinity"); |
651 | - FieldCodecManager::add<LegacyCCLSoundSpeedCodec>("_ccl_sound_speed"); |
652 | - |
653 | + { |
654 | dccl->load<dccl::protobuf::CCLMDATEmpty>(); |
655 | dccl->load<dccl::protobuf::CCLMDATRedirect>(); |
656 | dccl->load<dccl::protobuf::CCLMDATBathy>(); |
657 | |
658 | === modified file 'src/ccl/ccl_compatibility.h' |
659 | --- src/ccl/ccl_compatibility.h 2013-09-12 16:23:45 +0000 |
660 | +++ src/ccl/ccl_compatibility.h 2014-08-27 16:27:22 +0000 |
661 | @@ -24,7 +24,8 @@ |
662 | #ifndef DCCLCCLCOMPATIBILITY20120426H |
663 | #define DCCLCCLCOMPATIBILITY20120426H |
664 | |
665 | -#include "dccl/field_codec_default.h" |
666 | +#include "dccl/codecs2/field_codec_default.h" |
667 | +#include "dccl/field_codec_id.h" |
668 | #include "dccl/ccl/protobuf/ccl.pb.h" |
669 | #include "dccl/ccl/protobuf/ccl_extensions.pb.h" |
670 | |
671 | @@ -33,8 +34,6 @@ |
672 | void dccl3_load(dccl::Codec* dccl); |
673 | } |
674 | |
675 | - |
676 | - |
677 | namespace dccl |
678 | { |
679 | const unsigned char DCCL_CCL_HEADER = 32; |
680 | @@ -117,7 +116,7 @@ |
681 | enum { LATLON_COMPRESSED_BYTE_SIZE = 3 }; |
682 | }; |
683 | |
684 | - class LegacyCCLFixAgeCodec : public dccl::DefaultNumericFieldCodec<dccl::uint32> |
685 | + class LegacyCCLFixAgeCodec : public dccl::v2::DefaultNumericFieldCodec<dccl::uint32> |
686 | { |
687 | private: |
688 | dccl::Bitset encode() |
689 | |
690 | === modified file 'src/codec.cpp' |
691 | --- src/codec.cpp 2014-04-22 20:10:37 +0000 |
692 | +++ src/codec.cpp 2014-08-27 16:27:22 +0000 |
693 | @@ -38,7 +38,9 @@ |
694 | #endif // HAS_CRYPTOPP |
695 | |
696 | #include "dccl/codec.h" |
697 | -#include "field_codec_default.h" |
698 | +#include "dccl/codecs2/field_codec_default.h" |
699 | +#include "dccl/codecs3/field_codec_default.h" |
700 | +#include "dccl/field_codec_id.h" |
701 | |
702 | #include "dccl/protobuf/option_extensions.pb.h" |
703 | |
704 | @@ -63,7 +65,7 @@ |
705 | dccl::Codec::Codec(const std::string& dccl_id_codec) |
706 | : id_codec_(dccl_id_codec) |
707 | { |
708 | - FieldCodecManager::add<DefaultIdentifierCodec>("_default_id_codec"); |
709 | + FieldCodecManager::add<DefaultIdentifierCodec>(default_id_codec_name()); |
710 | // make sure the id codec exists |
711 | id_codec(); |
712 | set_default_codecs(); |
713 | @@ -77,31 +79,59 @@ |
714 | if(!defaults_loaded) |
715 | { |
716 | using google::protobuf::FieldDescriptor; |
717 | - |
718 | - FieldCodecManager::add<DefaultNumericFieldCodec<double> >(default_codec_name()); |
719 | - FieldCodecManager::add<DefaultNumericFieldCodec<float> >(default_codec_name()); |
720 | - FieldCodecManager::add<DefaultBoolCodec>(default_codec_name()); |
721 | - FieldCodecManager::add<DefaultNumericFieldCodec<int32> >(default_codec_name()); |
722 | - FieldCodecManager::add<DefaultNumericFieldCodec<int64> >(default_codec_name()); |
723 | - FieldCodecManager::add<DefaultNumericFieldCodec<uint32> >(default_codec_name()); |
724 | - FieldCodecManager::add<DefaultNumericFieldCodec<uint64> >(default_codec_name()); |
725 | - FieldCodecManager::add<DefaultStringCodec, FieldDescriptor::TYPE_STRING>(default_codec_name()); |
726 | - FieldCodecManager::add<DefaultBytesCodec, FieldDescriptor::TYPE_BYTES>(default_codec_name()); |
727 | - FieldCodecManager::add<DefaultEnumCodec>(default_codec_name()); |
728 | - FieldCodecManager::add<DefaultMessageCodec, FieldDescriptor::TYPE_MESSAGE>(default_codec_name()); |
729 | - |
730 | - FieldCodecManager::add<TimeCodec<uint64> >("_time"); |
731 | - FieldCodecManager::add<TimeCodec<int64> >("_time"); |
732 | - FieldCodecManager::add<TimeCodec<double> >("_time"); |
733 | - |
734 | - FieldCodecManager::add<StaticCodec<std::string> >("_static"); |
735 | - FieldCodecManager::add<StaticCodec<double> >("_static"); |
736 | - FieldCodecManager::add<StaticCodec<float> >("_static"); |
737 | - FieldCodecManager::add<StaticCodec<int32> >("_static"); |
738 | - FieldCodecManager::add<StaticCodec<int64> >("_static"); |
739 | - FieldCodecManager::add<StaticCodec<uint32> >("_static"); |
740 | - FieldCodecManager::add<StaticCodec<uint64> >("_static"); |
741 | - |
742 | + |
743 | + // version 2 |
744 | + FieldCodecManager::add<v2::DefaultNumericFieldCodec<double> >(default_codec_name()); |
745 | + FieldCodecManager::add<v2::DefaultNumericFieldCodec<float> >(default_codec_name()); |
746 | + FieldCodecManager::add<v2::DefaultBoolCodec>(default_codec_name()); |
747 | + FieldCodecManager::add<v2::DefaultNumericFieldCodec<int32> >(default_codec_name()); |
748 | + FieldCodecManager::add<v2::DefaultNumericFieldCodec<int64> >(default_codec_name()); |
749 | + FieldCodecManager::add<v2::DefaultNumericFieldCodec<uint32> >(default_codec_name()); |
750 | + FieldCodecManager::add<v2::DefaultNumericFieldCodec<uint64> >(default_codec_name()); |
751 | + FieldCodecManager::add<v2::DefaultStringCodec, FieldDescriptor::TYPE_STRING>(default_codec_name()); |
752 | + FieldCodecManager::add<v2::DefaultBytesCodec, FieldDescriptor::TYPE_BYTES>(default_codec_name()); |
753 | + FieldCodecManager::add<v2::DefaultEnumCodec >(default_codec_name()); |
754 | + FieldCodecManager::add<v2::DefaultMessageCodec, FieldDescriptor::TYPE_MESSAGE>(default_codec_name()); |
755 | + |
756 | + FieldCodecManager::add<v2::TimeCodec<uint64> >("dccl.time2"); |
757 | + FieldCodecManager::add<v2::TimeCodec<int64> >("dccl.time2"); |
758 | + FieldCodecManager::add<v2::TimeCodec<double> >("dccl.time2"); |
759 | + |
760 | + FieldCodecManager::add<v2::StaticCodec<std::string> >("dccl.static2"); |
761 | + FieldCodecManager::add<v2::StaticCodec<double> >("dccl.static2"); |
762 | + FieldCodecManager::add<v2::StaticCodec<float> >("dccl.static2"); |
763 | + FieldCodecManager::add<v2::StaticCodec<int32> >("dccl.static2"); |
764 | + FieldCodecManager::add<v2::StaticCodec<int64> >("dccl.static2"); |
765 | + FieldCodecManager::add<v2::StaticCodec<uint32> >("dccl.static2"); |
766 | + FieldCodecManager::add<v2::StaticCodec<uint64> >("dccl.static2"); |
767 | + |
768 | + // version 3 |
769 | + FieldCodecManager::add<v3::DefaultNumericFieldCodec<double> >(default_codec_name(3)); |
770 | + FieldCodecManager::add<v3::DefaultNumericFieldCodec<float> >(default_codec_name(3)); |
771 | + FieldCodecManager::add<v3::DefaultBoolCodec>(default_codec_name(3)); |
772 | + FieldCodecManager::add<v3::DefaultNumericFieldCodec<int32> >(default_codec_name(3)); |
773 | + FieldCodecManager::add<v3::DefaultNumericFieldCodec<int64> >(default_codec_name(3)); |
774 | + FieldCodecManager::add<v3::DefaultNumericFieldCodec<uint32> >(default_codec_name(3)); |
775 | + FieldCodecManager::add<v3::DefaultNumericFieldCodec<uint64> >(default_codec_name(3)); |
776 | + FieldCodecManager::add<v3::DefaultStringCodec, FieldDescriptor::TYPE_STRING>(default_codec_name(3)); |
777 | + FieldCodecManager::add<v3::DefaultBytesCodec, FieldDescriptor::TYPE_BYTES>(default_codec_name(3)); |
778 | + FieldCodecManager::add<v3::DefaultEnumCodec >(default_codec_name(3)); |
779 | + FieldCodecManager::add<v3::DefaultMessageCodec, FieldDescriptor::TYPE_MESSAGE>(default_codec_name(3)); |
780 | + |
781 | + // for backwards compatibility |
782 | + FieldCodecManager::add<v2::TimeCodec<uint64> >("_time"); |
783 | + FieldCodecManager::add<v2::TimeCodec<int64> >("_time"); |
784 | + FieldCodecManager::add<v2::TimeCodec<double> >("_time"); |
785 | + |
786 | + FieldCodecManager::add<v2::StaticCodec<std::string> >("_static"); |
787 | + FieldCodecManager::add<v2::StaticCodec<double> >("_static"); |
788 | + FieldCodecManager::add<v2::StaticCodec<float> >("_static"); |
789 | + FieldCodecManager::add<v2::StaticCodec<int32> >("_static"); |
790 | + FieldCodecManager::add<v2::StaticCodec<int64> >("_static"); |
791 | + FieldCodecManager::add<v2::StaticCodec<uint32> >("_static"); |
792 | + FieldCodecManager::add<v2::StaticCodec<uint64> >("_static"); |
793 | + |
794 | + |
795 | defaults_loaded = true; |
796 | } |
797 | } |
798 | @@ -326,6 +356,9 @@ |
799 | throw(Exception("Missing message option `(dccl.msg).id`. Specify a unique id (e.g. 3) in the body of your .proto message using \"option (dccl.msg).id = 3\"")); |
800 | if(!desc->options().GetExtension(dccl::msg).has_max_bytes()) |
801 | throw(Exception("Missing message option `(dccl.msg).max_bytes`. Specify a maximum (encoded) message size in bytes (e.g. 32) in the body of your .proto message using \"option (dccl.msg).max_bytes = 32\"")); |
802 | + |
803 | + if(!desc->options().GetExtension(dccl::msg).has_codec_version()) |
804 | + dlog.is(WARN) && dlog << "** NOTE: No (dccl.msg).codec_version set for DCCL Message '" << desc->full_name() << "'. Unless you need backwards compatibility with Goby 2.0 (DCCL2), we highly recommend setting 'option (dccl.msg).codec_version = 3' in the message definition for " << desc->full_name() << " to use the default DCCL3 codecs. If you need compatibility with Goby 2.0, ignore this warning, or set 'option (dccl.msg).codec_version = 2' to remove this warning. **" << std::endl; |
805 | |
806 | boost::shared_ptr<FieldCodecBase> codec = FieldCodecManager::find(desc); |
807 | |
808 | @@ -419,7 +452,8 @@ |
809 | const unsigned allowed_byte_size = desc->options().GetExtension(dccl::msg).max_bytes(); |
810 | const unsigned allowed_bit_size = allowed_byte_size * BITS_IN_BYTE; |
811 | |
812 | - std::string guard = std::string((full_width-desc->full_name().size())/2, '='); |
813 | + std::string message_name = boost::lexical_cast<std::string>(dccl_id) + ": " + desc->full_name(); |
814 | + std::string guard = std::string((full_width-message_name.size())/2, '='); |
815 | |
816 | std::string bits_dccl_head_str = "dccl.id head"; |
817 | std::string bits_user_head_str = "user head"; |
818 | @@ -430,7 +464,7 @@ |
819 | const int spaces = 8; |
820 | std::string indent = std::string(spaces,' '); |
821 | |
822 | - *os << guard << " " << desc->full_name() << " " << guard << "\n" |
823 | + *os << guard << " " << message_name << " " << guard << "\n" |
824 | << "Actual maximum size of message: " << byte_size << " bytes / " |
825 | << byte_size*BITS_IN_BYTE << " bits\n" |
826 | << indent << bits_dccl_head_str << std::setfill('.') << std::setw(bits_width-bits_dccl_head_str.size()) << id_bit_size << "\n" |
827 | @@ -443,7 +477,7 @@ |
828 | std::string header_str = "Header"; |
829 | std::string header_guard = std::string((full_width-header_str.size())/2, '-'); |
830 | *os << header_guard << " " << header_str << " " << header_guard << std::endl; |
831 | - *os << bits_dccl_head_str << std::setfill('.') << std::setw(bits_width-bits_dccl_head_str.size()+spaces) << id_bit_size << "\n"; |
832 | + *os << bits_dccl_head_str << std::setfill('.') << std::setw(bits_width-bits_dccl_head_str.size()+spaces) << id_bit_size << " {" << id_codec()->name() << "}\n"; |
833 | codec->base_info(os, desc, MessageStack::HEAD); |
834 | // *os << std::string(header_str.size() + 2 + 2*header_guard.size(), '-') << std::endl; |
835 | |
836 | @@ -459,6 +493,9 @@ |
837 | { |
838 | dlog.is(DEBUG1) && dlog << "Message " << desc->full_name() << " cannot provide information due to invalid configuration. Reason: " << e.what() << std::endl; |
839 | } |
840 | + |
841 | + os->flush(); |
842 | + |
843 | } |
844 | |
845 | } |
846 | @@ -564,4 +601,5 @@ |
847 | |
848 | // *os << std::string(codec_str.size() + 2 + 2*codec_guard.size(), '|') << std::endl; |
849 | } |
850 | + |
851 | } |
852 | |
853 | === modified file 'src/codec.h' |
854 | --- src/codec.h 2014-04-22 20:10:37 +0000 |
855 | +++ src/codec.h 2014-08-27 16:27:22 +0000 |
856 | @@ -42,7 +42,9 @@ |
857 | #include "exception.h" |
858 | #include "field_codec.h" |
859 | #include "field_codec_fixed.h" |
860 | -#include "field_codec_default.h" |
861 | + |
862 | +#include "codecs2/field_codec_default_message.h" |
863 | +#include "codecs3/field_codec_default_message.h" |
864 | #include "type_helper.h" |
865 | #include "field_codec_manager.h" |
866 | |
867 | @@ -84,7 +86,7 @@ |
868 | class Codec |
869 | { |
870 | public: |
871 | - Codec(const std::string& dccl_id_codec = "_default_id_codec"); |
872 | + Codec(const std::string& dccl_id_codec = default_id_codec_name()); |
873 | virtual ~Codec() |
874 | { |
875 | for(std::vector<void *>::iterator it = dl_handles_.begin(), |
876 | @@ -181,6 +183,9 @@ |
877 | return desc->options().GetExtension(dccl::msg).id(); |
878 | } |
879 | |
880 | + /// \brief Provides a map of all loaded DCCL IDs to the equivalent Protobuf descriptor |
881 | + const std::map<int32, const google::protobuf::Descriptor*>& loaded() const { return id2desc_; } |
882 | + |
883 | //@} |
884 | |
885 | /// \brief Provides the encoded size (in bytes) of msg. This is useful if you need to know the size of a message before encoding it (encoding it is generally much more expensive than calling this method) |
886 | @@ -237,8 +242,26 @@ |
887 | /// \return pointer to decoded message (a google::protobuf::Message). You are responsible for deleting the memory used by this pointer, so we recommend using a smart pointer here (e.g. boost::shared_ptr or the C++11 equivalent). This message can be examined using the Google Reflection/Descriptor API. |
888 | template<typename GoogleProtobufMessagePointer> |
889 | GoogleProtobufMessagePointer decode(std::string* bytes); |
890 | - |
891 | - friend class DefaultMessageCodec; |
892 | + |
893 | + static std::string default_id_codec_name() |
894 | + { return "dccl.default.id"; } |
895 | + |
896 | + |
897 | + static std::string default_codec_name(int version = 2) |
898 | + { |
899 | + switch(version) |
900 | + { |
901 | + case 2: |
902 | + return dccl::DCCLFieldOptions::descriptor()->FindFieldByName("codec")->default_value_string(); |
903 | + default: |
904 | + return "dccl.default" + boost::lexical_cast<std::string>(version); |
905 | + } |
906 | + |
907 | + } |
908 | + |
909 | + |
910 | + friend class v2::DefaultMessageCodec; |
911 | + //friend class v3::DefaultMessageCodec; |
912 | private: |
913 | Codec(const Codec&); |
914 | Codec& operator= (const Codec&); |
915 | @@ -254,11 +277,6 @@ |
916 | id_codec_); |
917 | } |
918 | |
919 | - static const std::string& default_codec_name() |
920 | - { |
921 | - return dccl::DCCLFieldOptions::descriptor()->FindFieldByName("codec")->default_value_string(); |
922 | - } |
923 | - |
924 | private: |
925 | // SHA256 hash of the crypto passphrase |
926 | std::string crypto_key_; |
927 | @@ -287,7 +305,7 @@ |
928 | unsigned this_id = id(bytes); |
929 | |
930 | if(!id2desc_.count(this_id)) |
931 | - throw(Exception("Message id " + boost::lexical_cast<std::string>(this_id) + " has not been validated. Call validate() before decoding this type.")); |
932 | + throw(Exception("Message id " + boost::lexical_cast<std::string>(this_id) + " has not been loaded. Call load() before decoding this type.")); |
933 | |
934 | // ownership of this object goes to the caller of decode() |
935 | GoogleProtobufMessagePointer msg = |
936 | |
937 | === added directory 'src/codecs2' |
938 | === renamed file 'src/field_codec_default.cpp' => 'src/codecs2/field_codec_default.cpp' |
939 | --- src/field_codec_default.cpp 2014-04-22 20:10:37 +0000 |
940 | +++ src/codecs2/field_codec_default.cpp 2014-08-27 16:27:22 +0000 |
941 | @@ -25,108 +25,28 @@ |
942 | #include <sstream> |
943 | #include <algorithm> |
944 | |
945 | -#include "field_codec_default.h" |
946 | -#include "type_helper.h" |
947 | +#include "dccl/codecs2/field_codec_default.h" |
948 | +#include "dccl/type_helper.h" |
949 | #include "dccl/codec.h" |
950 | |
951 | using namespace dccl::logger; |
952 | |
953 | |
954 | // |
955 | -// DefaultIdentifierCodec |
956 | -// |
957 | - |
958 | -dccl::Bitset dccl::DefaultIdentifierCodec::encode() |
959 | -{ |
960 | - return encode(0); |
961 | -} |
962 | - |
963 | -dccl::Bitset dccl::DefaultIdentifierCodec::encode(const uint32& id) |
964 | -{ |
965 | - if(id <= ONE_BYTE_MAX_ID) |
966 | - { |
967 | - return(dccl::Bitset(this_size(id), id) << 1); |
968 | - } |
969 | - else |
970 | - { |
971 | - dccl::Bitset return_bits(this_size(id), id); |
972 | - return_bits <<= 1; |
973 | - // set LSB to indicate long header form |
974 | - return_bits.set(0, true); |
975 | - |
976 | - |
977 | - return return_bits; |
978 | - } |
979 | -} |
980 | - |
981 | -dccl::uint32 dccl::DefaultIdentifierCodec::decode(Bitset* bits) |
982 | -{ |
983 | - if(bits->test(0)) |
984 | - { |
985 | - // long header |
986 | - // grabs more bits to add to the MSB of `bits` |
987 | - bits->get_more_bits((LONG_FORM_ID_BYTES - SHORT_FORM_ID_BYTES)*BITS_IN_BYTE); |
988 | - // discard identifier |
989 | - *(bits) >>= 1; |
990 | - return bits->to_ulong(); |
991 | - } |
992 | - else |
993 | - { |
994 | - // short header |
995 | - *(bits) >>= 1; |
996 | - return bits->to_ulong(); |
997 | - } |
998 | -} |
999 | - |
1000 | -unsigned dccl::DefaultIdentifierCodec::size() |
1001 | -{ |
1002 | - return this_size(0); |
1003 | -} |
1004 | - |
1005 | -unsigned dccl::DefaultIdentifierCodec::size(const uint32& id) |
1006 | -{ |
1007 | - return this_size(id); |
1008 | -} |
1009 | - |
1010 | -unsigned dccl::DefaultIdentifierCodec::this_size(const uint32& id) |
1011 | -{ |
1012 | - if(id > TWO_BYTE_MAX_ID) |
1013 | - throw(Exception("dccl.id provided (" + boost::lexical_cast<std::string>(id) + ") exceeds maximum: " + boost::lexical_cast<std::string>(int(TWO_BYTE_MAX_ID)))); |
1014 | - |
1015 | - return (id <= ONE_BYTE_MAX_ID) ? |
1016 | - SHORT_FORM_ID_BYTES*BITS_IN_BYTE : |
1017 | - LONG_FORM_ID_BYTES*BITS_IN_BYTE; |
1018 | -} |
1019 | - |
1020 | - |
1021 | -unsigned dccl::DefaultIdentifierCodec::max_size() |
1022 | -{ |
1023 | - return LONG_FORM_ID_BYTES * BITS_IN_BYTE; |
1024 | -} |
1025 | - |
1026 | -unsigned dccl::DefaultIdentifierCodec::min_size() |
1027 | -{ |
1028 | - return SHORT_FORM_ID_BYTES * BITS_IN_BYTE; |
1029 | -} |
1030 | - |
1031 | - |
1032 | - |
1033 | - |
1034 | -// |
1035 | // DefaultBoolCodec |
1036 | // |
1037 | |
1038 | -dccl::Bitset dccl::DefaultBoolCodec::encode() |
1039 | +dccl::Bitset dccl::v2::DefaultBoolCodec::encode() |
1040 | { |
1041 | return Bitset(size()); |
1042 | } |
1043 | |
1044 | -dccl::Bitset dccl::DefaultBoolCodec::encode(const bool& wire_value) |
1045 | +dccl::Bitset dccl::v2::DefaultBoolCodec::encode(const bool& wire_value) |
1046 | { |
1047 | return Bitset(size(), this_field()->is_required() ? wire_value : wire_value + 1); |
1048 | } |
1049 | |
1050 | -bool dccl::DefaultBoolCodec::decode(Bitset* bits) |
1051 | +bool dccl::v2::DefaultBoolCodec::decode(Bitset* bits) |
1052 | { |
1053 | unsigned long t = bits->to_ulong(); |
1054 | if(this_field()->is_required()) |
1055 | @@ -145,7 +65,7 @@ |
1056 | } |
1057 | |
1058 | |
1059 | -unsigned dccl::DefaultBoolCodec::size() |
1060 | +unsigned dccl::v2::DefaultBoolCodec::size() |
1061 | { |
1062 | // true and false |
1063 | const unsigned BOOL_VALUES = 2; |
1064 | @@ -155,19 +75,19 @@ |
1065 | return dccl::ceil_log2(BOOL_VALUES + NULL_VALUE); |
1066 | } |
1067 | |
1068 | -void dccl::DefaultBoolCodec::validate() |
1069 | +void dccl::v2::DefaultBoolCodec::validate() |
1070 | { } |
1071 | |
1072 | // |
1073 | // DefaultStringCodec |
1074 | // |
1075 | |
1076 | -dccl::Bitset dccl::DefaultStringCodec::encode() |
1077 | +dccl::Bitset dccl::v2::DefaultStringCodec::encode() |
1078 | { |
1079 | return Bitset(min_size()); |
1080 | } |
1081 | |
1082 | -dccl::Bitset dccl::DefaultStringCodec::encode(const std::string& wire_value) |
1083 | +dccl::Bitset dccl::v2::DefaultStringCodec::encode(const std::string& wire_value) |
1084 | { |
1085 | std::string s = wire_value; |
1086 | if(s.size() > dccl_field_options().max_length()) |
1087 | @@ -197,7 +117,7 @@ |
1088 | return length_bits; |
1089 | } |
1090 | |
1091 | -std::string dccl::DefaultStringCodec::decode(Bitset* bits) |
1092 | +std::string dccl::v2::DefaultStringCodec::decode(Bitset* bits) |
1093 | { |
1094 | unsigned value_length = bits->to_ulong(); |
1095 | |
1096 | @@ -228,30 +148,30 @@ |
1097 | |
1098 | } |
1099 | |
1100 | -unsigned dccl::DefaultStringCodec::size() |
1101 | +unsigned dccl::v2::DefaultStringCodec::size() |
1102 | { |
1103 | return min_size(); |
1104 | } |
1105 | |
1106 | -unsigned dccl::DefaultStringCodec::size(const std::string& wire_value) |
1107 | +unsigned dccl::v2::DefaultStringCodec::size(const std::string& wire_value) |
1108 | { |
1109 | return std::min(min_size() + static_cast<unsigned>(wire_value.length()*BITS_IN_BYTE), max_size()); |
1110 | } |
1111 | |
1112 | |
1113 | -unsigned dccl::DefaultStringCodec::max_size() |
1114 | +unsigned dccl::v2::DefaultStringCodec::max_size() |
1115 | { |
1116 | // string length + actual string |
1117 | return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE; |
1118 | } |
1119 | |
1120 | -unsigned dccl::DefaultStringCodec::min_size() |
1121 | +unsigned dccl::v2::DefaultStringCodec::min_size() |
1122 | { |
1123 | return dccl::ceil_log2(MAX_STRING_LENGTH+1); |
1124 | } |
1125 | |
1126 | |
1127 | -void dccl::DefaultStringCodec::validate() |
1128 | +void dccl::v2::DefaultStringCodec::validate() |
1129 | { |
1130 | require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length"); |
1131 | require(dccl_field_options().max_length() <= MAX_STRING_LENGTH, |
1132 | @@ -261,13 +181,13 @@ |
1133 | // |
1134 | // DefaultBytesCodec |
1135 | // |
1136 | -dccl::Bitset dccl::DefaultBytesCodec::encode() |
1137 | +dccl::Bitset dccl::v2::DefaultBytesCodec::encode() |
1138 | { |
1139 | return Bitset(min_size(), 0); |
1140 | } |
1141 | |
1142 | |
1143 | -dccl::Bitset dccl::DefaultBytesCodec::encode(const std::string& wire_value) |
1144 | +dccl::Bitset dccl::v2::DefaultBytesCodec::encode(const std::string& wire_value) |
1145 | { |
1146 | Bitset bits; |
1147 | bits.from_byte_string(wire_value); |
1148 | @@ -282,19 +202,19 @@ |
1149 | return bits; |
1150 | } |
1151 | |
1152 | -unsigned dccl::DefaultBytesCodec::size() |
1153 | +unsigned dccl::v2::DefaultBytesCodec::size() |
1154 | { |
1155 | return min_size(); |
1156 | } |
1157 | |
1158 | |
1159 | -unsigned dccl::DefaultBytesCodec::size(const std::string& wire_value) |
1160 | +unsigned dccl::v2::DefaultBytesCodec::size(const std::string& wire_value) |
1161 | { |
1162 | return max_size(); |
1163 | } |
1164 | |
1165 | |
1166 | -std::string dccl::DefaultBytesCodec::decode(Bitset* bits) |
1167 | +std::string dccl::v2::DefaultBytesCodec::decode(Bitset* bits) |
1168 | { |
1169 | if(!this_field()->is_required()) |
1170 | { |
1171 | @@ -320,13 +240,13 @@ |
1172 | } |
1173 | } |
1174 | |
1175 | -unsigned dccl::DefaultBytesCodec::max_size() |
1176 | +unsigned dccl::v2::DefaultBytesCodec::max_size() |
1177 | { |
1178 | return dccl_field_options().max_length() * BITS_IN_BYTE + |
1179 | (this_field()->is_required() ? 0 : 1); // presence bit? |
1180 | } |
1181 | |
1182 | -unsigned dccl::DefaultBytesCodec::min_size() |
1183 | +unsigned dccl::v2::DefaultBytesCodec::min_size() |
1184 | { |
1185 | if(this_field()->is_required()) |
1186 | return max_size(); |
1187 | @@ -334,7 +254,7 @@ |
1188 | return 1; // presence bit |
1189 | } |
1190 | |
1191 | -void dccl::DefaultBytesCodec::validate() |
1192 | +void dccl::v2::DefaultBytesCodec::validate() |
1193 | { |
1194 | require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length"); |
1195 | } |
1196 | @@ -342,12 +262,12 @@ |
1197 | // |
1198 | // DefaultEnumCodec |
1199 | // |
1200 | -dccl::int32 dccl::DefaultEnumCodec::pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value) |
1201 | +dccl::int32 dccl::v2::DefaultEnumCodec::pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value) |
1202 | { |
1203 | return field_value->index(); |
1204 | } |
1205 | |
1206 | -const google::protobuf::EnumValueDescriptor* dccl::DefaultEnumCodec::post_decode(const dccl::int32& wire_value) |
1207 | +const google::protobuf::EnumValueDescriptor* dccl::v2::DefaultEnumCodec::post_decode(const dccl::int32& wire_value) |
1208 | { |
1209 | const google::protobuf::EnumDescriptor* e = this_field()->enum_type(); |
1210 | |
1211 | |
1212 | === renamed file 'src/field_codec_default.h' => 'src/codecs2/field_codec_default.h' |
1213 | --- src/field_codec_default.h 2014-04-22 20:10:37 +0000 |
1214 | +++ src/codecs2/field_codec_default.h 2014-08-27 16:27:22 +0000 |
1215 | @@ -2,6 +2,7 @@ |
1216 | // GobySoft, LLC (2013-) |
1217 | // Massachusetts Institute of Technology (2007-2014) |
1218 | // DCCL Developers Team (https://launchpad.net/~dccl-dev) |
1219 | +// |
1220 | // |
1221 | // This file is part of the Dynamic Compact Control Language Library |
1222 | // ("DCCL"). |
1223 | @@ -39,328 +40,307 @@ |
1224 | |
1225 | #include "dccl/protobuf/option_extensions.pb.h" |
1226 | |
1227 | -#include "field_codec_default_message.h" |
1228 | -#include "field_codec_fixed.h" |
1229 | -#include "field_codec.h" |
1230 | -#include "binary.h" |
1231 | +#include "dccl/codecs2/field_codec_default_message.h" |
1232 | +#include "dccl/field_codec_fixed.h" |
1233 | +#include "dccl/field_codec.h" |
1234 | +#include "dccl/binary.h" |
1235 | |
1236 | namespace dccl |
1237 | { |
1238 | - /// \brief Provides the default 1 byte or 2 byte DCCL ID codec |
1239 | - class DefaultIdentifierCodec : public TypedFieldCodec<uint32> |
1240 | - { |
1241 | - protected: |
1242 | - virtual Bitset encode(); |
1243 | - virtual Bitset encode(const uint32& wire_value); |
1244 | - virtual uint32 decode(Bitset* bits); |
1245 | - virtual unsigned size(); |
1246 | - virtual unsigned size(const uint32& wire_value); |
1247 | - virtual unsigned max_size(); |
1248 | - virtual unsigned min_size(); |
1249 | - virtual void validate() { } |
1250 | - |
1251 | - private: |
1252 | - unsigned this_size(const uint32& wire_value); |
1253 | - // maximum id we can fit in short or long header (MSB reserved to indicate |
1254 | - // short or long header) |
1255 | - enum { ONE_BYTE_MAX_ID = (1 << 7) - 1, |
1256 | - TWO_BYTE_MAX_ID = (1 << 15) - 1}; |
1257 | - |
1258 | - enum { SHORT_FORM_ID_BYTES = 1, |
1259 | - LONG_FORM_ID_BYTES = 2 }; |
1260 | - }; |
1261 | - |
1262 | - |
1263 | - |
1264 | - /// \brief Provides a basic bounded arbitrary length numeric (double, float, uint32, uint64, int32, int64) encoder. |
1265 | - /// |
1266 | - /// Takes ceil(log2((max-min)*10^precision)+1) bits for required fields, ceil(log2((max-min)*10^precision)+2) for optional fields. |
1267 | - template<typename WireType, typename FieldType = WireType> |
1268 | - class DefaultNumericFieldCodec : public TypedFixedFieldCodec<WireType, FieldType> |
1269 | - { |
1270 | - protected: |
1271 | - |
1272 | - virtual double max() |
1273 | - { return FieldCodecBase::dccl_field_options().max(); } |
1274 | - |
1275 | - virtual double min() |
1276 | - { return FieldCodecBase::dccl_field_options().min(); } |
1277 | - |
1278 | - virtual double precision() |
1279 | - { return FieldCodecBase::dccl_field_options().precision(); } |
1280 | - |
1281 | - virtual void validate() |
1282 | - { |
1283 | - FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_min(), |
1284 | - "missing (dccl.field).min"); |
1285 | - FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_max(), |
1286 | - "missing (dccl.field).max"); |
1287 | - |
1288 | - validate_numeric_bounds(); |
1289 | - } |
1290 | - |
1291 | - void validate_numeric_bounds() |
1292 | - { |
1293 | - |
1294 | - // ensure given max and min fit within WireType ranges |
1295 | - FieldCodecBase::require(min() >= boost::numeric::bounds<WireType>::lowest(), |
1296 | - "(dccl.field).min must be >= minimum of this field type."); |
1297 | - FieldCodecBase::require(max() <= boost::numeric::bounds<WireType>::highest(), |
1298 | - "(dccl.field).max must be <= maximum of this field type."); |
1299 | - |
1300 | - |
1301 | - // ensure value fits into double |
1302 | - FieldCodecBase::require((precision() + std::ceil(std::log10(max() - min()))) <= std::numeric_limits<double>::digits10, |
1303 | - "[(dccl.field).max-(dccl.field).min]*10^(dccl.field).precision must fit in a double-precision floating point value. Please increase min, decrease max, or decrease precision."); |
1304 | - |
1305 | - } |
1306 | - |
1307 | - |
1308 | - Bitset encode() |
1309 | - { |
1310 | - return Bitset(size()); |
1311 | - } |
1312 | - |
1313 | - |
1314 | - virtual Bitset encode(const WireType& value) |
1315 | - { |
1316 | - WireType wire_value = value; |
1317 | - |
1318 | - if(wire_value < min() || wire_value > max()) |
1319 | - return Bitset(size()); |
1320 | - |
1321 | - wire_value -= (WireType)min(); |
1322 | - |
1323 | - wire_value = dccl::round(wire_value, precision()); |
1324 | - if (precision() < 0) { |
1325 | - wire_value /= (WireType)std::pow(10.0, -precision()); |
1326 | - } else if (precision() > 0) { |
1327 | - wire_value *= (WireType)std::pow(10.0, precision()); |
1328 | - } |
1329 | - |
1330 | - // "presence" value (0) |
1331 | - if(!FieldCodecBase::this_field()->is_required()) |
1332 | - wire_value += 1; |
1333 | - |
1334 | - |
1335 | - Bitset encoded; |
1336 | - encoded.from(boost::numeric_cast<dccl::uint64>(dccl::round(wire_value, 0)), size()); |
1337 | - return encoded; |
1338 | - } |
1339 | - |
1340 | - virtual WireType decode(Bitset* bits) |
1341 | - { |
1342 | - // The line below SHOULD BE: |
1343 | - // dccl::uint64 t = bits->to<dccl::uint64>(); |
1344 | - // But GCC3.3 requires an explicit template modifier on the method. |
1345 | - // See, e.g., http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10959 |
1346 | - dccl::uint64 uint_value = (bits->template to<dccl::uint64>)(); |
1347 | - |
1348 | - if(!FieldCodecBase::this_field()->is_required()) |
1349 | - { |
1350 | - if(!uint_value) throw NullValueException(); |
1351 | - --uint_value; |
1352 | - } |
1353 | - |
1354 | - WireType wire_value = (WireType)uint_value; |
1355 | - |
1356 | - if (precision() < 0) { |
1357 | - wire_value *= (WireType)std::pow(10.0, -precision()); |
1358 | - } else if (precision() > 0) { |
1359 | - wire_value /= (WireType)std::pow(10.0, precision()); |
1360 | - } |
1361 | - |
1362 | - // round values again to properly handle cases where double precision |
1363 | - // leads to slightly off values (e.g. 2.099999999 instead of 2.1) |
1364 | - wire_value = dccl::round(wire_value + (WireType)min(), |
1365 | - precision()); |
1366 | - |
1367 | - return wire_value; |
1368 | - } |
1369 | - |
1370 | - unsigned size() |
1371 | - { |
1372 | - // if not required field, leave one value for unspecified (always encoded as 0) |
1373 | - const unsigned NULL_VALUE = FieldCodecBase::this_field()->is_required() ? 0 : 1; |
1374 | - |
1375 | - return dccl::ceil_log2((max()-min())*std::pow(10.0, precision())+1 + NULL_VALUE); |
1376 | - } |
1377 | - |
1378 | - }; |
1379 | - |
1380 | - /// \brief Provides a bool encoder. Uses 1 bit if field is `required`, 2 bits if `optional` |
1381 | - /// |
1382 | - /// [presence bit (0 bits if required, 1 bit if optional)][value (1 bit)] |
1383 | - class DefaultBoolCodec : public TypedFixedFieldCodec<bool> |
1384 | - { |
1385 | - private: |
1386 | - Bitset encode(const bool& wire_value); |
1387 | - Bitset encode(); |
1388 | - bool decode(Bitset* bits); |
1389 | - unsigned size(); |
1390 | - void validate(); |
1391 | - }; |
1392 | - |
1393 | - /// \brief Provides an variable length ASCII string encoder. Can encode strings up to 255 bytes by using a length byte preceeding the string. |
1394 | - /// |
1395 | - /// [length of following string (1 byte)][string (0-255 bytes)] |
1396 | - class DefaultStringCodec : public TypedFieldCodec<std::string> |
1397 | - { |
1398 | - private: |
1399 | - Bitset encode(); |
1400 | - Bitset encode(const std::string& wire_value); |
1401 | - std::string decode(Bitset* bits); |
1402 | - unsigned size(); |
1403 | - unsigned size(const std::string& wire_value); |
1404 | - unsigned max_size(); |
1405 | - unsigned min_size(); |
1406 | - void validate(); |
1407 | - private: |
1408 | - enum { MAX_STRING_LENGTH = 255 }; |
1409 | - |
1410 | - }; |
1411 | - |
1412 | - |
1413 | - /// \brief Provides an fixed length byte string encoder. |
1414 | - class DefaultBytesCodec : public TypedFieldCodec<std::string> |
1415 | - { |
1416 | - private: |
1417 | - Bitset encode(); |
1418 | - Bitset encode(const std::string& wire_value); |
1419 | - std::string decode(Bitset* bits); |
1420 | - unsigned size(); |
1421 | - unsigned size(const std::string& wire_value); |
1422 | - unsigned max_size(); |
1423 | - unsigned min_size(); |
1424 | - void validate(); |
1425 | - }; |
1426 | - |
1427 | - /// \brief Provides an enum encoder. This converts the enumeration to an integer (based on the enumeration <i>index</i> (<b>not</b> its <i>value</i>) and uses DefaultNumericFieldCodec to encode the integer. |
1428 | - class DefaultEnumCodec |
1429 | - : public DefaultNumericFieldCodec<int32, const google::protobuf::EnumValueDescriptor*> |
1430 | - { |
1431 | - public: |
1432 | - int32 pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value); |
1433 | - const google::protobuf::EnumValueDescriptor* post_decode(const int32& wire_value); |
1434 | - |
1435 | - private: |
1436 | - void validate() { } |
1437 | - |
1438 | - double max() |
1439 | - { |
1440 | - const google::protobuf::EnumDescriptor* e = this_field()->enum_type(); |
1441 | - return e->value_count()-1; |
1442 | - } |
1443 | - double min() |
1444 | - { return 0; } |
1445 | - }; |
1446 | - |
1447 | - |
1448 | - /// \brief Encodes time of day (default: second precision, but can be set with (dccl.field).precision extension) |
1449 | - /// |
1450 | - /// \tparam TimeType A type representing time: See the various specializations of this class for allowed types. |
1451 | - |
1452 | - typedef double time_wire_type; |
1453 | - template<typename TimeType, int conversion_factor> |
1454 | - class TimeCodecBase : public DefaultNumericFieldCodec<time_wire_type, TimeType> |
1455 | - { |
1456 | - public: |
1457 | - time_wire_type pre_encode(const TimeType& time_of_day) { |
1458 | - time_wire_type max_secs = max(); |
1459 | - return std::fmod(time_of_day / static_cast<time_wire_type>(conversion_factor), max_secs); |
1460 | - } |
1461 | - |
1462 | - TimeType post_decode(const time_wire_type& encoded_time) { |
1463 | - |
1464 | - int64 max_secs = (int64)max(); |
1465 | - timeval t; |
1466 | - gettimeofday(&t, 0); |
1467 | - int64 now = t.tv_sec; |
1468 | - int64 daystart = now - (now % max_secs); |
1469 | - int64 today_time = now - daystart; |
1470 | - |
1471 | - // If time is more than 12 hours ahead of now, assume it's yesterday. |
1472 | - if ((encoded_time - today_time) > (max_secs/2)) { |
1473 | - daystart -= max_secs; |
1474 | - } else if ((today_time - encoded_time) > (max_secs/2)) { |
1475 | - daystart += max_secs; |
1476 | - } |
1477 | - |
1478 | - return (TimeType)(conversion_factor * (daystart + encoded_time)); |
1479 | - } |
1480 | - |
1481 | - private: |
1482 | - void validate() |
1483 | - { |
1484 | - DefaultNumericFieldCodec<time_wire_type, TimeType>::validate_numeric_bounds(); |
1485 | - } |
1486 | - |
1487 | - double max() { |
1488 | - return FieldCodecBase::dccl_field_options().num_days() * SECONDS_IN_DAY; |
1489 | - } |
1490 | - |
1491 | - double min() { return 0; } |
1492 | - double precision() |
1493 | - { |
1494 | - if(!FieldCodecBase::dccl_field_options().has_precision()) |
1495 | - return 0; // default to second precision |
1496 | - else |
1497 | - { |
1498 | - return FieldCodecBase::dccl_field_options().precision() + (double)std::log10((double)conversion_factor); |
1499 | - } |
1500 | - |
1501 | - } |
1502 | - |
1503 | - |
1504 | - private: |
1505 | - enum { SECONDS_IN_DAY = 86400 }; |
1506 | - }; |
1507 | - |
1508 | - template<typename TimeType> |
1509 | - class TimeCodec : public TimeCodecBase<TimeType, 0> |
1510 | - { BOOST_STATIC_ASSERT(sizeof(TimeCodec) == 0); }; |
1511 | - |
1512 | - template<> class TimeCodec<uint64> : public TimeCodecBase<uint64, 1000000> { }; |
1513 | - template<> class TimeCodec<int64> : public TimeCodecBase<int64, 1000000> { }; |
1514 | - template<> class TimeCodec<double> : public TimeCodecBase<double, 1> { }; |
1515 | - |
1516 | - |
1517 | - /// \brief Placeholder codec that takes no space on the wire (0 bits). |
1518 | - template<typename T> |
1519 | - class StaticCodec : public TypedFixedFieldCodec<T> |
1520 | - { |
1521 | - Bitset encode(const T&) |
1522 | - { return Bitset(size()); } |
1523 | - |
1524 | - Bitset encode() |
1525 | - { return Bitset(size()); } |
1526 | - |
1527 | - T decode(Bitset* bits) |
1528 | - { |
1529 | - return boost::lexical_cast<T>( |
1530 | - FieldCodecBase::dccl_field_options().static_value()); |
1531 | - } |
1532 | - |
1533 | - unsigned size() |
1534 | - { return 0; } |
1535 | - |
1536 | - void validate() |
1537 | - { |
1538 | - FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_static_value(), "missing (dccl.field).static_value"); |
1539 | - |
1540 | - std::string t = FieldCodecBase::dccl_field_options().static_value(); |
1541 | - try |
1542 | - { |
1543 | - boost::lexical_cast<T>(t); |
1544 | - } |
1545 | - catch(boost::bad_lexical_cast&) |
1546 | - { |
1547 | - FieldCodecBase::require(false, "invalid static_value for this type."); |
1548 | - } |
1549 | - } |
1550 | - |
1551 | - }; |
1552 | - |
1553 | + namespace v2 |
1554 | + { |
1555 | + /// \brief Provides a basic bounded arbitrary length numeric (double, float, uint32, uint64, int32, int64) encoder. |
1556 | + /// |
1557 | + /// Takes ceil(log2((max-min)*10^precision)+1) bits for required fields, ceil(log2((max-min)*10^precision)+2) for optional fields. |
1558 | + template<typename WireType, typename FieldType = WireType> |
1559 | + class DefaultNumericFieldCodec : public TypedFixedFieldCodec<WireType, FieldType> |
1560 | + { |
1561 | + protected: |
1562 | + |
1563 | + virtual double max() |
1564 | + { return FieldCodecBase::dccl_field_options().max(); } |
1565 | + |
1566 | + virtual double min() |
1567 | + { return FieldCodecBase::dccl_field_options().min(); } |
1568 | + |
1569 | + virtual double precision() |
1570 | + { return FieldCodecBase::dccl_field_options().precision(); } |
1571 | + |
1572 | + virtual void validate() |
1573 | + { |
1574 | + FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_min(), |
1575 | + "missing (dccl.field).min"); |
1576 | + FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_max(), |
1577 | + "missing (dccl.field).max"); |
1578 | + |
1579 | + validate_numeric_bounds(); |
1580 | + } |
1581 | + |
1582 | + void validate_numeric_bounds() |
1583 | + { |
1584 | + |
1585 | + // ensure given max and min fit within WireType ranges |
1586 | + FieldCodecBase::require(min() >= boost::numeric::bounds<WireType>::lowest(), |
1587 | + "(dccl.field).min must be >= minimum of this field type."); |
1588 | + FieldCodecBase::require(max() <= boost::numeric::bounds<WireType>::highest(), |
1589 | + "(dccl.field).max must be <= maximum of this field type."); |
1590 | + |
1591 | + |
1592 | + // ensure value fits into double |
1593 | + FieldCodecBase::require((precision() + std::ceil(std::log10(max() - min()))) <= std::numeric_limits<double>::digits10, |
1594 | + "[(dccl.field).max-(dccl.field).min]*10^(dccl.field).precision must fit in a double-precision floating point value. Please increase min, decrease max, or decrease precision."); |
1595 | + |
1596 | + } |
1597 | + |
1598 | + |
1599 | + Bitset encode() |
1600 | + { |
1601 | + return Bitset(size()); |
1602 | + } |
1603 | + |
1604 | + |
1605 | + virtual Bitset encode(const WireType& value) |
1606 | + { |
1607 | + // round first, before checking bounds |
1608 | + WireType wire_value = dccl::round(value, precision()); |
1609 | + |
1610 | + // check bounds, if out-of-bounds, send as zeros |
1611 | + if(wire_value < min() || wire_value > max()) |
1612 | + return Bitset(size()); |
1613 | + |
1614 | + wire_value -= dccl::round((WireType)min(), precision()); |
1615 | + |
1616 | + if (precision() < 0) { |
1617 | + wire_value /= (WireType)std::pow(10.0, -precision()); |
1618 | + } else if (precision() > 0) { |
1619 | + wire_value *= (WireType)std::pow(10.0, precision()); |
1620 | + } |
1621 | + |
1622 | + dccl::uint64 uint_value = boost::numeric_cast<dccl::uint64>(dccl::round(wire_value, 0)); |
1623 | + |
1624 | + // "presence" value (0) |
1625 | + if(!FieldCodecBase::this_field()->is_required()) |
1626 | + uint_value += 1; |
1627 | + |
1628 | + |
1629 | + Bitset encoded; |
1630 | + encoded.from(uint_value, size()); |
1631 | + return encoded; |
1632 | + } |
1633 | + |
1634 | + virtual WireType decode(Bitset* bits) |
1635 | + { |
1636 | + // The line below SHOULD BE: |
1637 | + // dccl::uint64 t = bits->to<dccl::uint64>(); |
1638 | + // But GCC3.3 requires an explicit template modifier on the method. |
1639 | + // See, e.g., http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10959 |
1640 | + dccl::uint64 uint_value = (bits->template to<dccl::uint64>)(); |
1641 | + |
1642 | + if(!FieldCodecBase::this_field()->is_required()) |
1643 | + { |
1644 | + if(!uint_value) throw NullValueException(); |
1645 | + --uint_value; |
1646 | + } |
1647 | + |
1648 | + WireType wire_value = (WireType)uint_value; |
1649 | + |
1650 | + if (precision() < 0) { |
1651 | + wire_value *= (WireType)std::pow(10.0, -precision()); |
1652 | + } else if (precision() > 0) { |
1653 | + wire_value /= (WireType)std::pow(10.0, precision()); |
1654 | + } |
1655 | + |
1656 | + // round values again to properly handle cases where double precision |
1657 | + // leads to slightly off values (e.g. 2.099999999 instead of 2.1) |
1658 | + wire_value = dccl::round(wire_value + dccl::round((WireType)min(), precision()), |
1659 | + precision()); |
1660 | + |
1661 | + return wire_value; |
1662 | + } |
1663 | + |
1664 | + unsigned size() |
1665 | + { |
1666 | + // if not required field, leave one value for unspecified (always encoded as 0) |
1667 | + const unsigned NULL_VALUE = FieldCodecBase::this_field()->is_required() ? 0 : 1; |
1668 | + |
1669 | + return dccl::ceil_log2((max()-min())*std::pow(10.0, precision())+1 + NULL_VALUE); |
1670 | + } |
1671 | + |
1672 | + }; |
1673 | + |
1674 | + /// \brief Provides a bool encoder. Uses 1 bit if field is `required`, 2 bits if `optional` |
1675 | + /// |
1676 | + /// [presence bit (0 bits if required, 1 bit if optional)][value (1 bit)] |
1677 | + class DefaultBoolCodec : public TypedFixedFieldCodec<bool> |
1678 | + { |
1679 | + private: |
1680 | + Bitset encode(const bool& wire_value); |
1681 | + Bitset encode(); |
1682 | + bool decode(Bitset* bits); |
1683 | + unsigned size(); |
1684 | + void validate(); |
1685 | + }; |
1686 | + |
1687 | + /// \brief Provides an variable length ASCII string encoder. Can encode strings up to 255 bytes by using a length byte preceeding the string. |
1688 | + /// |
1689 | + /// [length of following string (1 byte)][string (0-255 bytes)] |
1690 | + class DefaultStringCodec : public TypedFieldCodec<std::string> |
1691 | + { |
1692 | + private: |
1693 | + Bitset encode(); |
1694 | + Bitset encode(const std::string& wire_value); |
1695 | + std::string decode(Bitset* bits); |
1696 | + unsigned size(); |
1697 | + unsigned size(const std::string& wire_value); |
1698 | + unsigned max_size(); |
1699 | + unsigned min_size(); |
1700 | + void validate(); |
1701 | + private: |
1702 | + enum { MAX_STRING_LENGTH = 255 }; |
1703 | + |
1704 | + }; |
1705 | + |
1706 | + |
1707 | + /// \brief Provides an fixed length byte string encoder. |
1708 | + class DefaultBytesCodec : public TypedFieldCodec<std::string> |
1709 | + { |
1710 | + private: |
1711 | + Bitset encode(); |
1712 | + Bitset encode(const std::string& wire_value); |
1713 | + std::string decode(Bitset* bits); |
1714 | + unsigned size(); |
1715 | + unsigned size(const std::string& wire_value); |
1716 | + unsigned max_size(); |
1717 | + unsigned min_size(); |
1718 | + void validate(); |
1719 | + }; |
1720 | + |
1721 | + /// \brief Provides an enum encoder. This converts the enumeration to an integer (based on the enumeration <i>index</i> (<b>not</b> its <i>value</i>) and uses DefaultNumericFieldCodec to encode the integer. |
1722 | + class DefaultEnumCodec |
1723 | + : public DefaultNumericFieldCodec<int32, const google::protobuf::EnumValueDescriptor*> |
1724 | + { |
1725 | + public: |
1726 | + int32 pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value); |
1727 | + const google::protobuf::EnumValueDescriptor* post_decode(const int32& wire_value); |
1728 | + |
1729 | + private: |
1730 | + void validate() { } |
1731 | + |
1732 | + double max() |
1733 | + { |
1734 | + const google::protobuf::EnumDescriptor* e = this_field()->enum_type(); |
1735 | + return e->value_count()-1; |
1736 | + } |
1737 | + double min() |
1738 | + { return 0; } |
1739 | + }; |
1740 | + |
1741 | + |
1742 | + /// \brief Encodes time of day (default: second precision, but can be set with (dccl.field).precision extension) |
1743 | + /// |
1744 | + /// \tparam TimeType A type representing time: See the various specializations of this class for allowed types. |
1745 | + |
1746 | + typedef double time_wire_type; |
1747 | + template<typename TimeType, int conversion_factor> |
1748 | + class TimeCodecBase : public DefaultNumericFieldCodec<time_wire_type, TimeType> |
1749 | + { |
1750 | + public: |
1751 | + time_wire_type pre_encode(const TimeType& time_of_day) { |
1752 | + time_wire_type max_secs = max(); |
1753 | + return std::fmod(time_of_day / static_cast<time_wire_type>(conversion_factor), max_secs); |
1754 | + } |
1755 | + |
1756 | + TimeType post_decode(const time_wire_type& encoded_time) { |
1757 | + |
1758 | + int64 max_secs = (int64)max(); |
1759 | + timeval t; |
1760 | + gettimeofday(&t, 0); |
1761 | + int64 now = t.tv_sec; |
1762 | + int64 daystart = now - (now % max_secs); |
1763 | + int64 today_time = now - daystart; |
1764 | + |
1765 | + // If time is more than 12 hours ahead of now, assume it's yesterday. |
1766 | + if ((encoded_time - today_time) > (max_secs/2)) { |
1767 | + daystart -= max_secs; |
1768 | + } else if ((today_time - encoded_time) > (max_secs/2)) { |
1769 | + daystart += max_secs; |
1770 | + } |
1771 | + |
1772 | + return (TimeType)(conversion_factor * (daystart + encoded_time)); |
1773 | + } |
1774 | + |
1775 | + private: |
1776 | + void validate() |
1777 | + { |
1778 | + DefaultNumericFieldCodec<time_wire_type, TimeType>::validate_numeric_bounds(); |
1779 | + } |
1780 | + |
1781 | + double max() { |
1782 | + return FieldCodecBase::dccl_field_options().num_days() * SECONDS_IN_DAY; |
1783 | + } |
1784 | + |
1785 | + double min() { return 0; } |
1786 | + double precision() |
1787 | + { |
1788 | + if(!FieldCodecBase::dccl_field_options().has_precision()) |
1789 | + return 0; // default to second precision |
1790 | + else |
1791 | + { |
1792 | + return FieldCodecBase::dccl_field_options().precision() + (double)std::log10((double)conversion_factor); |
1793 | + } |
1794 | + |
1795 | + } |
1796 | + |
1797 | + |
1798 | + private: |
1799 | + enum { SECONDS_IN_DAY = 86400 }; |
1800 | + }; |
1801 | + |
1802 | + template<typename TimeType> |
1803 | + class TimeCodec : public TimeCodecBase<TimeType, 0> |
1804 | + { BOOST_STATIC_ASSERT(sizeof(TimeCodec) == 0); }; |
1805 | + |
1806 | + template<> class TimeCodec<uint64> : public TimeCodecBase<uint64, 1000000> { }; |
1807 | + template<> class TimeCodec<int64> : public TimeCodecBase<int64, 1000000> { }; |
1808 | + template<> class TimeCodec<double> : public TimeCodecBase<double, 1> { }; |
1809 | + |
1810 | + |
1811 | + /// \brief Placeholder codec that takes no space on the wire (0 bits). |
1812 | + template<typename T> |
1813 | + class StaticCodec : public TypedFixedFieldCodec<T> |
1814 | + { |
1815 | + Bitset encode(const T&) |
1816 | + { return Bitset(size()); } |
1817 | + |
1818 | + Bitset encode() |
1819 | + { return Bitset(size()); } |
1820 | + |
1821 | + T decode(Bitset* bits) |
1822 | + { |
1823 | + return boost::lexical_cast<T>( |
1824 | + FieldCodecBase::dccl_field_options().static_value()); |
1825 | + } |
1826 | + |
1827 | + unsigned size() |
1828 | + { return 0; } |
1829 | + |
1830 | + void validate() |
1831 | + { |
1832 | + FieldCodecBase::require(FieldCodecBase::dccl_field_options().has_static_value(), "missing (dccl.field).static_value"); |
1833 | + |
1834 | + std::string t = FieldCodecBase::dccl_field_options().static_value(); |
1835 | + try |
1836 | + { |
1837 | + boost::lexical_cast<T>(t); |
1838 | + } |
1839 | + catch(boost::bad_lexical_cast&) |
1840 | + { |
1841 | + FieldCodecBase::require(false, "invalid static_value for this type."); |
1842 | + } |
1843 | + } |
1844 | + |
1845 | + }; |
1846 | + } |
1847 | } |
1848 | |
1849 | |
1850 | |
1851 | === renamed file 'src/field_codec_default_message.cpp' => 'src/codecs2/field_codec_default_message.cpp' |
1852 | --- src/field_codec_default_message.cpp 2014-04-22 20:10:37 +0000 |
1853 | +++ src/codecs2/field_codec_default_message.cpp 2014-08-27 16:27:22 +0000 |
1854 | @@ -30,17 +30,17 @@ |
1855 | // DefaultMessageCodec |
1856 | // |
1857 | |
1858 | -void dccl::DefaultMessageCodec::any_encode(Bitset* bits, const boost::any& wire_value) |
1859 | +void dccl::v2::DefaultMessageCodec::any_encode(Bitset* bits, const boost::any& wire_value) |
1860 | { |
1861 | - if(wire_value.empty()) |
1862 | - *bits = Bitset(min_size()); |
1863 | - else |
1864 | - *bits = traverse_const_message<Encoder, Bitset>(wire_value); |
1865 | + if(wire_value.empty()) |
1866 | + *bits = Bitset(min_size()); |
1867 | + else |
1868 | + *bits = traverse_const_message<Encoder, Bitset>(wire_value); |
1869 | } |
1870 | |
1871 | |
1872 | |
1873 | -unsigned dccl::DefaultMessageCodec::any_size(const boost::any& wire_value) |
1874 | +unsigned dccl::v2::DefaultMessageCodec::any_size(const boost::any& wire_value) |
1875 | { |
1876 | if(wire_value.empty()) |
1877 | return min_size(); |
1878 | @@ -49,7 +49,7 @@ |
1879 | } |
1880 | |
1881 | |
1882 | -void dccl::DefaultMessageCodec::any_decode(Bitset* bits, boost::any* wire_value) |
1883 | +void dccl::v2::DefaultMessageCodec::any_decode(Bitset* bits, boost::any* wire_value) |
1884 | { |
1885 | try |
1886 | { |
1887 | @@ -67,8 +67,8 @@ |
1888 | if(!check_field(field_desc)) |
1889 | continue; |
1890 | |
1891 | - boost::shared_ptr<FieldCodecBase> codec = |
1892 | - FieldCodecManager::find(field_desc); |
1893 | + |
1894 | + boost::shared_ptr<FieldCodecBase> codec = find(field_desc); |
1895 | boost::shared_ptr<FromProtoCppTypeBase> helper = |
1896 | TypeHelper::find(field_desc); |
1897 | |
1898 | @@ -127,14 +127,14 @@ |
1899 | } |
1900 | |
1901 | |
1902 | -unsigned dccl::DefaultMessageCodec::max_size() |
1903 | +unsigned dccl::v2::DefaultMessageCodec::max_size() |
1904 | { |
1905 | unsigned u = 0; |
1906 | traverse_descriptor<MaxSize>(&u); |
1907 | return u; |
1908 | } |
1909 | |
1910 | -unsigned dccl::DefaultMessageCodec::min_size() |
1911 | +unsigned dccl::v2::DefaultMessageCodec::min_size() |
1912 | { |
1913 | unsigned u = 0; |
1914 | traverse_descriptor<MinSize>(&u); |
1915 | @@ -142,20 +142,20 @@ |
1916 | } |
1917 | |
1918 | |
1919 | -void dccl::DefaultMessageCodec::validate() |
1920 | +void dccl::v2::DefaultMessageCodec::validate() |
1921 | { |
1922 | bool b = false; |
1923 | traverse_descriptor<Validate>(&b); |
1924 | } |
1925 | |
1926 | -std::string dccl::DefaultMessageCodec::info() |
1927 | +std::string dccl::v2::DefaultMessageCodec::info() |
1928 | { |
1929 | std::stringstream ss; |
1930 | traverse_descriptor<Info>(&ss); |
1931 | return ss.str(); |
1932 | } |
1933 | |
1934 | -bool dccl::DefaultMessageCodec::check_field(const google::protobuf::FieldDescriptor* field) |
1935 | +bool dccl::v2::DefaultMessageCodec::check_field(const google::protobuf::FieldDescriptor* field) |
1936 | { |
1937 | if(!field) |
1938 | { |
1939 | @@ -171,7 +171,7 @@ |
1940 | else if(MessageStack::current_part() == MessageStack::UNKNOWN) // part not yet explicitly specified |
1941 | { |
1942 | if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE && |
1943 | - FieldCodecManager::find(field)->name() == Codec::default_codec_name()) // default message codec will expand |
1944 | + find(field)->name() == Codec::default_codec_name()) // default message codec will expand |
1945 | return true; |
1946 | else if((part() == MessageStack::HEAD && !dccl_field_options.in_head()) |
1947 | || (part() == MessageStack::BODY && dccl_field_options.in_head())) |
1948 | |
1949 | === renamed file 'src/field_codec_default_message.h' => 'src/codecs2/field_codec_default_message.h' |
1950 | --- src/field_codec_default_message.h 2014-04-22 20:10:37 +0000 |
1951 | +++ src/codecs2/field_codec_default_message.h 2014-08-27 16:27:22 +0000 |
1952 | @@ -24,225 +24,183 @@ |
1953 | #ifndef DCCLFIELDCODECDEFAULTMESSAGE20110510H |
1954 | #define DCCLFIELDCODECDEFAULTMESSAGE20110510H |
1955 | |
1956 | -#include "field_codec.h" |
1957 | -#include "field_codec_manager.h" |
1958 | +#include "dccl/field_codec.h" |
1959 | +#include "dccl/field_codec_manager.h" |
1960 | |
1961 | #include "dccl/protobuf/option_extensions.pb.h" |
1962 | |
1963 | namespace dccl |
1964 | { |
1965 | - /// \brief Provides the default codec for encoding a base Google Protobuf message or an embedded message by calling the appropriate field codecs for every field. |
1966 | - class DefaultMessageCodec : public FieldCodecBase |
1967 | + namespace v2 |
1968 | { |
1969 | - private: |
1970 | - |
1971 | - void any_encode(Bitset* bits, const boost::any& wire_value); |
1972 | - void any_decode(Bitset* bits, boost::any* wire_value); |
1973 | - unsigned max_size(); |
1974 | - unsigned min_size(); |
1975 | - unsigned any_size(const boost::any& wire_value); |
1976 | - |
1977 | - |
1978 | - void validate(); |
1979 | - std::string info(); |
1980 | - bool check_field(const google::protobuf::FieldDescriptor* field); |
1981 | - |
1982 | - struct Size |
1983 | - { |
1984 | - static void repeated(boost::shared_ptr<FieldCodecBase> codec, |
1985 | - unsigned* return_value, |
1986 | - const std::vector<boost::any>& field_values, |
1987 | - const google::protobuf::FieldDescriptor* field_desc) |
1988 | - { |
1989 | - codec->field_size_repeated(return_value, field_values, field_desc); |
1990 | - } |
1991 | - |
1992 | - static void single(boost::shared_ptr<FieldCodecBase> codec, |
1993 | - unsigned* return_value, |
1994 | - const boost::any& field_value, |
1995 | - const google::protobuf::FieldDescriptor* field_desc) |
1996 | - { |
1997 | - codec->field_size(return_value, field_value, field_desc); |
1998 | - } |
1999 | - |
2000 | - }; |
2001 | - |
2002 | - struct Encoder |
2003 | - { |
2004 | - static void repeated(boost::shared_ptr<FieldCodecBase> codec, |
2005 | - Bitset* return_value, |
2006 | - const std::vector<boost::any>& field_values, |
2007 | - const google::protobuf::FieldDescriptor* field_desc) |
2008 | - { |
2009 | - codec->field_encode_repeated(return_value, field_values, field_desc); |
2010 | - } |
2011 | - |
2012 | - static void single(boost::shared_ptr<FieldCodecBase> codec, |
2013 | - Bitset* return_value, |
2014 | - const boost::any& field_value, |
2015 | - const google::protobuf::FieldDescriptor* field_desc) |
2016 | - { |
2017 | - codec->field_encode(return_value, field_value, field_desc); |
2018 | - } |
2019 | - }; |
2020 | - |
2021 | - struct MaxSize |
2022 | - { |
2023 | - static void field(boost::shared_ptr<FieldCodecBase> codec, |
2024 | - unsigned* return_value, |
2025 | - const google::protobuf::FieldDescriptor* field_desc) |
2026 | - { |
2027 | - codec->field_max_size(return_value, field_desc); |
2028 | - } |
2029 | - }; |
2030 | - |
2031 | - struct MinSize |
2032 | - { |
2033 | - static void field(boost::shared_ptr<FieldCodecBase> codec, |
2034 | - unsigned* return_value, |
2035 | - const google::protobuf::FieldDescriptor* field_desc) |
2036 | - { |
2037 | - codec->field_min_size(return_value, field_desc); |
2038 | - } |
2039 | - }; |
2040 | - |
2041 | - |
2042 | - struct Validate |
2043 | - { |
2044 | - static void field(boost::shared_ptr<FieldCodecBase> codec, |
2045 | - bool* return_value, |
2046 | - const google::protobuf::FieldDescriptor* field_desc) |
2047 | - { |
2048 | - codec->field_validate(return_value, field_desc); |
2049 | - } |
2050 | - }; |
2051 | - |
2052 | - struct Info |
2053 | - { |
2054 | - static void field(boost::shared_ptr<FieldCodecBase> codec, |
2055 | - std::stringstream* return_value, |
2056 | - const google::protobuf::FieldDescriptor* field_desc) |
2057 | - { |
2058 | - codec->field_info(return_value, field_desc); |
2059 | - } |
2060 | - }; |
2061 | - |
2062 | - |
2063 | - template<typename Action, typename ReturnType> |
2064 | - void traverse_descriptor(ReturnType* return_value) |
2065 | - { |
2066 | - const google::protobuf::Descriptor* desc = |
2067 | - FieldCodecBase::this_descriptor(); |
2068 | - for(int i = 0, n = desc->field_count(); i < n; ++i) |
2069 | - { |
2070 | - const google::protobuf::FieldDescriptor* field_desc = desc->field(i); |
2071 | + /// \brief Provides the default codec for encoding a base Google Protobuf message or an embedded message by calling the appropriate field codecs for every field. |
2072 | + class DefaultMessageCodec : public FieldCodecBase |
2073 | + { |
2074 | + private: |
2075 | + |
2076 | + void any_encode(Bitset* bits, const boost::any& wire_value); |
2077 | + void any_decode(Bitset* bits, boost::any* wire_value); |
2078 | + unsigned max_size(); |
2079 | + unsigned min_size(); |
2080 | + unsigned any_size(const boost::any& wire_value); |
2081 | + |
2082 | + |
2083 | + boost::shared_ptr<FieldCodecBase> find(const google::protobuf::FieldDescriptor* field_desc) |
2084 | + { |
2085 | + return FieldCodecManager::find(field_desc, has_codec_group(), codec_group()); |
2086 | + } |
2087 | + |
2088 | + |
2089 | + void validate(); |
2090 | + std::string info(); |
2091 | + bool check_field(const google::protobuf::FieldDescriptor* field); |
2092 | + |
2093 | + struct Size |
2094 | + { |
2095 | + static void repeated(boost::shared_ptr<FieldCodecBase> codec, |
2096 | + unsigned* return_value, |
2097 | + const std::vector<boost::any>& field_values, |
2098 | + const google::protobuf::FieldDescriptor* field_desc) |
2099 | + { |
2100 | + codec->field_size_repeated(return_value, field_values, field_desc); |
2101 | + } |
2102 | + |
2103 | + static void single(boost::shared_ptr<FieldCodecBase> codec, |
2104 | + unsigned* return_value, |
2105 | + const boost::any& field_value, |
2106 | + const google::protobuf::FieldDescriptor* field_desc) |
2107 | + { |
2108 | + codec->field_size(return_value, field_value, field_desc); |
2109 | + } |
2110 | + |
2111 | + }; |
2112 | + |
2113 | + struct Encoder |
2114 | + { |
2115 | + static void repeated(boost::shared_ptr<FieldCodecBase> codec, |
2116 | + Bitset* return_value, |
2117 | + const std::vector<boost::any>& field_values, |
2118 | + const google::protobuf::FieldDescriptor* field_desc) |
2119 | + { |
2120 | + codec->field_encode_repeated(return_value, field_values, field_desc); |
2121 | + } |
2122 | + |
2123 | + static void single(boost::shared_ptr<FieldCodecBase> codec, |
2124 | + Bitset* return_value, |
2125 | + const boost::any& field_value, |
2126 | + const google::protobuf::FieldDescriptor* field_desc) |
2127 | + { |
2128 | + codec->field_encode(return_value, field_value, field_desc); |
2129 | + } |
2130 | + }; |
2131 | + |
2132 | + struct MaxSize |
2133 | + { |
2134 | + static void field(boost::shared_ptr<FieldCodecBase> codec, |
2135 | + unsigned* return_value, |
2136 | + const google::protobuf::FieldDescriptor* field_desc) |
2137 | + { |
2138 | + codec->field_max_size(return_value, field_desc); |
2139 | + } |
2140 | + }; |
2141 | + |
2142 | + struct MinSize |
2143 | + { |
2144 | + static void field(boost::shared_ptr<FieldCodecBase> codec, |
2145 | + unsigned* return_value, |
2146 | + const google::protobuf::FieldDescriptor* field_desc) |
2147 | + { |
2148 | + codec->field_min_size(return_value, field_desc); |
2149 | + } |
2150 | + }; |
2151 | + |
2152 | + |
2153 | + struct Validate |
2154 | + { |
2155 | + static void field(boost::shared_ptr<FieldCodecBase> codec, |
2156 | + bool* return_value, |
2157 | + const google::protobuf::FieldDescriptor* field_desc) |
2158 | + { |
2159 | + codec->field_validate(return_value, field_desc); |
2160 | + } |
2161 | + }; |
2162 | + |
2163 | + struct Info |
2164 | + { |
2165 | + static void field(boost::shared_ptr<FieldCodecBase> codec, |
2166 | + std::stringstream* return_value, |
2167 | + const google::protobuf::FieldDescriptor* field_desc) |
2168 | + { |
2169 | + codec->field_info(return_value, field_desc); |
2170 | + } |
2171 | + }; |
2172 | + |
2173 | + |
2174 | + template<typename Action, typename ReturnType> |
2175 | + void traverse_descriptor(ReturnType* return_value) |
2176 | + { |
2177 | + const google::protobuf::Descriptor* desc = |
2178 | + FieldCodecBase::this_descriptor(); |
2179 | + for(int i = 0, n = desc->field_count(); i < n; ++i) |
2180 | + { |
2181 | + const google::protobuf::FieldDescriptor* field_desc = desc->field(i); |
2182 | |
2183 | - if(!check_field(field_desc)) |
2184 | - continue; |
2185 | + if(!check_field(field_desc)) |
2186 | + continue; |
2187 | |
2188 | - Action::field(FieldCodecManager::find(field_desc), |
2189 | - return_value, field_desc); |
2190 | + Action::field(find(field_desc), return_value, field_desc); |
2191 | + } |
2192 | } |
2193 | - } |
2194 | |
2195 | |
2196 | - template<typename Action, typename ReturnType> |
2197 | - ReturnType traverse_const_message(const boost::any& wire_value) |
2198 | - { |
2199 | - try |
2200 | + template<typename Action, typename ReturnType> |
2201 | + ReturnType traverse_const_message(const boost::any& wire_value) |
2202 | { |
2203 | - ReturnType return_value = ReturnType(); |
2204 | + try |
2205 | + { |
2206 | + ReturnType return_value = ReturnType(); |
2207 | |
2208 | - const google::protobuf::Message* msg = boost::any_cast<const google::protobuf::Message*>(wire_value); |
2209 | - const google::protobuf::Descriptor* desc = msg->GetDescriptor(); |
2210 | - const google::protobuf::Reflection* refl = msg->GetReflection(); |
2211 | - for(int i = 0, n = desc->field_count(); i < n; ++i) |
2212 | - { |
2213 | - const google::protobuf::FieldDescriptor* field_desc = desc->field(i); |
2214 | + const google::protobuf::Message* msg = boost::any_cast<const google::protobuf::Message*>(wire_value); |
2215 | + const google::protobuf::Descriptor* desc = msg->GetDescriptor(); |
2216 | + const google::protobuf::Reflection* refl = msg->GetReflection(); |
2217 | + for(int i = 0, n = desc->field_count(); i < n; ++i) |
2218 | + { |
2219 | + const google::protobuf::FieldDescriptor* field_desc = desc->field(i); |
2220 | |
2221 | - if(!check_field(field_desc)) |
2222 | - continue; |
2223 | + if(!check_field(field_desc)) |
2224 | + continue; |
2225 | |
2226 | - boost::shared_ptr<FieldCodecBase> codec = |
2227 | - FieldCodecManager::find(field_desc); |
2228 | - boost::shared_ptr<FromProtoCppTypeBase> helper = |
2229 | - TypeHelper::find(field_desc); |
2230 | - |
2231 | - |
2232 | - if(field_desc->is_repeated()) |
2233 | - { |
2234 | - std::vector<boost::any> field_values; |
2235 | - for(int j = 0, m = refl->FieldSize(*msg, field_desc); j < m; ++j) |
2236 | - field_values.push_back(helper->get_repeated_value(field_desc, *msg, j)); |
2237 | + boost::shared_ptr<FieldCodecBase> codec = find(field_desc); |
2238 | + boost::shared_ptr<FromProtoCppTypeBase> helper = |
2239 | + TypeHelper::find(field_desc); |
2240 | + |
2241 | + |
2242 | + if(field_desc->is_repeated()) |
2243 | + { |
2244 | + std::vector<boost::any> field_values; |
2245 | + for(int j = 0, m = refl->FieldSize(*msg, field_desc); j < m; ++j) |
2246 | + field_values.push_back(helper->get_repeated_value(field_desc, *msg, j)); |
2247 | |
2248 | - Action::repeated(codec, &return_value, field_values, field_desc); |
2249 | - } |
2250 | - else |
2251 | - { |
2252 | - Action::single(codec, &return_value, helper->get_value(field_desc, *msg), field_desc); |
2253 | - } |
2254 | - } |
2255 | - return return_value; |
2256 | - } |
2257 | - catch(boost::bad_any_cast& e) |
2258 | - { |
2259 | - throw(Exception("Bad type given to traverse const, expecting const google::protobuf::Message*, got " + std::string(wire_value.type().name()))); |
2260 | - } |
2261 | - |
2262 | - } |
2263 | - |
2264 | - template<typename Action, typename ReturnType> |
2265 | - ReturnType traverse_mutable_message(const boost::any& wire_value) |
2266 | - { |
2267 | - try |
2268 | - { |
2269 | - ReturnType return_value = ReturnType(); |
2270 | - |
2271 | - const google::protobuf::Message* msg = boost::any_cast<const google::protobuf::Message*>(wire_value); |
2272 | - const google::protobuf::Descriptor* desc = msg->GetDescriptor(); |
2273 | - const google::protobuf::Reflection* refl = msg->GetReflection(); |
2274 | - for(int i = 0, n = desc->field_count(); i < n; ++i) |
2275 | - { |
2276 | - const google::protobuf::FieldDescriptor* field_desc = desc->field(i); |
2277 | - |
2278 | - if(!check_field(field_desc)) |
2279 | - continue; |
2280 | - |
2281 | - boost::shared_ptr<FieldCodecBase> codec = |
2282 | - FieldCodecManager::find(field_desc); |
2283 | - boost::shared_ptr<FromProtoCppTypeBase> helper = |
2284 | - TypeHelper::find(field_desc); |
2285 | - |
2286 | - |
2287 | - if(field_desc->is_repeated()) |
2288 | - { |
2289 | - std::vector<boost::any> field_values; |
2290 | - for(int j = 0, m = refl->FieldSize(*msg, field_desc); j < m; ++j) |
2291 | - field_values.push_back(helper->get_repeated_value(field_desc, *msg, j)); |
2292 | - |
2293 | - Action::repeated(codec, &return_value, field_values, field_desc); |
2294 | - } |
2295 | - else |
2296 | - { |
2297 | - Action::single(codec, &return_value, helper->get_value(field_desc, *msg), field_desc); |
2298 | - } |
2299 | - } |
2300 | - return return_value; |
2301 | - } |
2302 | - catch(boost::bad_any_cast& e) |
2303 | - { |
2304 | - throw(Exception("Bad type given to traverse, expecting const google::protobuf::Message*")); |
2305 | - } |
2306 | - |
2307 | - } |
2308 | - |
2309 | - |
2310 | - |
2311 | - }; |
2312 | - |
2313 | + Action::repeated(codec, &return_value, field_values, field_desc); |
2314 | + } |
2315 | + else |
2316 | + { |
2317 | + Action::single(codec, &return_value, helper->get_value(field_desc, *msg), field_desc); |
2318 | + } |
2319 | + } |
2320 | + return return_value; |
2321 | + } |
2322 | + catch(boost::bad_any_cast& e) |
2323 | + { |
2324 | + throw(Exception("Bad type given to traverse const, expecting const google::protobuf::Message*, got " + std::string(wire_value.type().name()))); |
2325 | + } |
2326 | + |
2327 | + } |
2328 | + }; |
2329 | + |
2330 | + } |
2331 | } |
2332 | |
2333 | - |
2334 | //encode, size, etc. |
2335 | |
2336 | |
2337 | |
2338 | === added directory 'src/codecs3' |
2339 | === added file 'src/codecs3/field_codec_default.cpp' |
2340 | --- src/codecs3/field_codec_default.cpp 1970-01-01 00:00:00 +0000 |
2341 | +++ src/codecs3/field_codec_default.cpp 2014-08-27 16:27:22 +0000 |
2342 | @@ -0,0 +1,122 @@ |
2343 | +// Copyright 2009-2014 Toby Schneider (https://launchpad.net/~tes) |
2344 | +// GobySoft, LLC (2013-) |
2345 | +// Massachusetts Institute of Technology (2007-2014) |
2346 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
2347 | +// |
2348 | +// This file is part of the Dynamic Compact Control Language Library |
2349 | +// ("DCCL"). |
2350 | +// |
2351 | +// DCCL is free software: you can redistribute them and/or modify |
2352 | +// them under the terms of the GNU Lesser General Public License as published by |
2353 | +// the Free Software Foundation, either version 2.1 of the License, or |
2354 | +// (at your option) any later version. |
2355 | +// |
2356 | +// DCCL is distributed in the hope that they will be useful, |
2357 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
2358 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2359 | +// GNU Lesser General Public License for more details. |
2360 | +// |
2361 | +// You should have received a copy of the GNU Lesser General Public License |
2362 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
2363 | + |
2364 | +#include "dccl/codecs3/field_codec_default.h" |
2365 | + |
2366 | +using namespace dccl::logger; |
2367 | + |
2368 | +// |
2369 | +// DefaultStringCodec |
2370 | +// |
2371 | + |
2372 | +dccl::Bitset dccl::v3::DefaultStringCodec::encode() |
2373 | +{ |
2374 | + return Bitset(min_size()); |
2375 | +} |
2376 | + |
2377 | +dccl::Bitset dccl::v3::DefaultStringCodec::encode(const std::string& wire_value) |
2378 | +{ |
2379 | + std::string s = wire_value; |
2380 | + if(s.size() > dccl_field_options().max_length()) |
2381 | + { |
2382 | + dccl::dlog.is(DEBUG2) && dccl::dlog << "String " << s << " exceeds `dccl.max_length`, truncating" << std::endl; |
2383 | + s.resize(dccl_field_options().max_length()); |
2384 | + } |
2385 | + |
2386 | + |
2387 | + Bitset value_bits; |
2388 | + value_bits.from_byte_string(s); |
2389 | + |
2390 | + Bitset length_bits(min_size(), s.length()); |
2391 | + |
2392 | + dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec value_bits: " << value_bits << std::endl; |
2393 | + |
2394 | + |
2395 | + dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec length_bits: " << length_bits << std::endl; |
2396 | + |
2397 | + // adds to MSBs |
2398 | + for(int i = 0, n = value_bits.size(); i < n; ++i) |
2399 | + length_bits.push_back(value_bits[i]); |
2400 | + |
2401 | + dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec created: " << length_bits << std::endl; |
2402 | + |
2403 | + |
2404 | + return length_bits; |
2405 | +} |
2406 | + |
2407 | +std::string dccl::v3::DefaultStringCodec::decode(Bitset* bits) |
2408 | +{ |
2409 | + unsigned value_length = bits->to_ulong(); |
2410 | + |
2411 | + if(value_length) |
2412 | + { |
2413 | + |
2414 | + unsigned header_length = min_size(); |
2415 | + |
2416 | + dccl::dlog.is(DEBUG2) && dccl::dlog << "Length of string is = " << value_length << std::endl; |
2417 | + |
2418 | + dccl::dlog.is(DEBUG2) && dccl::dlog << "bits before get_more_bits " << *bits << std::endl; |
2419 | + |
2420 | + // grabs more bits to add to the MSBs of `bits` |
2421 | + bits->get_more_bits(value_length*BITS_IN_BYTE); |
2422 | + |
2423 | + |
2424 | + dccl::dlog.is(DEBUG2) && dccl::dlog << "bits after get_more_bits " << *bits << std::endl; |
2425 | + Bitset string_body_bits = *bits; |
2426 | + string_body_bits >>= header_length; |
2427 | + string_body_bits.resize(bits->size() - header_length); |
2428 | + |
2429 | + return string_body_bits.to_byte_string(); |
2430 | + } |
2431 | + else |
2432 | + { |
2433 | + throw NullValueException(); |
2434 | + } |
2435 | + |
2436 | +} |
2437 | + |
2438 | +unsigned dccl::v3::DefaultStringCodec::size() |
2439 | +{ |
2440 | + return min_size(); |
2441 | +} |
2442 | + |
2443 | +unsigned dccl::v3::DefaultStringCodec::size(const std::string& wire_value) |
2444 | +{ |
2445 | + return std::min(min_size() + static_cast<unsigned>(wire_value.length()*BITS_IN_BYTE), max_size()); |
2446 | +} |
2447 | + |
2448 | + |
2449 | +unsigned dccl::v3::DefaultStringCodec::max_size() |
2450 | +{ |
2451 | + // string length + actual string |
2452 | + return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE; |
2453 | +} |
2454 | + |
2455 | +unsigned dccl::v3::DefaultStringCodec::min_size() |
2456 | +{ |
2457 | + return dccl::ceil_log2(dccl_field_options().max_length()+1); |
2458 | +} |
2459 | + |
2460 | + |
2461 | +void dccl::v3::DefaultStringCodec::validate() |
2462 | +{ |
2463 | + require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length"); |
2464 | +} |
2465 | |
2466 | === added file 'src/codecs3/field_codec_default.h' |
2467 | --- src/codecs3/field_codec_default.h 1970-01-01 00:00:00 +0000 |
2468 | +++ src/codecs3/field_codec_default.h 2014-08-27 16:27:22 +0000 |
2469 | @@ -0,0 +1,77 @@ |
2470 | +// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes) |
2471 | +// Massachusetts Institute of Technology (2007-) |
2472 | +// Woods Hole Oceanographic Institution (2007-) |
2473 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
2474 | +// |
2475 | +// |
2476 | +// This file is part of the Dynamic Compact Control Language Library |
2477 | +// ("DCCL"). |
2478 | +// |
2479 | +// DCCL is free software: you can redistribute them and/or modify |
2480 | +// them under the terms of the GNU Lesser General Public License as published by |
2481 | +// the Free Software Foundation, either version 3 of the License, or |
2482 | +// (at your option) any later version. |
2483 | +// |
2484 | +// DCCL is distributed in the hope that they will be useful, |
2485 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
2486 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2487 | +// GNU Lesser General Public License for more details. |
2488 | +// |
2489 | +// You should have received a copy of the GNU Lesser General Public License |
2490 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
2491 | + |
2492 | + |
2493 | + |
2494 | +// implements FieldCodecBase for all the basic DCCL types for version 3 |
2495 | + |
2496 | +#ifndef DCCLV3FIELDCODECDEFAULT20140403H |
2497 | +#define DCCLV3FIELDCODECDEFAULT20140403H |
2498 | + |
2499 | +#include "dccl/codecs2/field_codec_default.h" |
2500 | + |
2501 | +namespace dccl |
2502 | +{ |
2503 | + namespace v3 |
2504 | + { |
2505 | + // all these are the same as version 2 |
2506 | + template<typename WireType, typename FieldType = WireType> |
2507 | + class DefaultNumericFieldCodec : public v2::DefaultNumericFieldCodec<WireType, FieldType> { }; |
2508 | + |
2509 | + typedef v2::DefaultBoolCodec DefaultBoolCodec; |
2510 | + typedef v2::DefaultBytesCodec DefaultBytesCodec; |
2511 | + typedef v2::DefaultEnumCodec DefaultEnumCodec; |
2512 | + |
2513 | + |
2514 | + template<typename TimeType> |
2515 | + class TimeCodec : public v2::TimeCodecBase<TimeType, 0> |
2516 | + { BOOST_STATIC_ASSERT(sizeof(TimeCodec) == 0); }; |
2517 | + |
2518 | + template<> class TimeCodec<uint64> : public v2::TimeCodecBase<uint64, 1000000> { }; |
2519 | + template<> class TimeCodec<int64> : public v2::TimeCodecBase<int64, 1000000> { }; |
2520 | + template<> class TimeCodec<double> : public v2::TimeCodecBase<double, 1> { }; |
2521 | + |
2522 | + template<typename T> |
2523 | + class StaticCodec : public v2::StaticCodec<T> |
2524 | + { }; |
2525 | + |
2526 | + |
2527 | + /// \brief Provides an variable length ASCII string encoder. |
2528 | + /// |
2529 | + /// [length of following string size: ceil(log2(max_length))][string] |
2530 | + class DefaultStringCodec : public TypedFieldCodec<std::string> |
2531 | + { |
2532 | + private: |
2533 | + Bitset encode(); |
2534 | + Bitset encode(const std::string& wire_value); |
2535 | + std::string decode(Bitset* bits); |
2536 | + unsigned size(); |
2537 | + unsigned size(const std::string& wire_value); |
2538 | + unsigned max_size(); |
2539 | + unsigned min_size(); |
2540 | + void validate(); |
2541 | + }; |
2542 | + |
2543 | + } |
2544 | +} |
2545 | + |
2546 | +#endif |
2547 | |
2548 | === added file 'src/codecs3/field_codec_default_message.cpp' |
2549 | --- src/codecs3/field_codec_default_message.cpp 1970-01-01 00:00:00 +0000 |
2550 | +++ src/codecs3/field_codec_default_message.cpp 2014-08-27 16:27:22 +0000 |
2551 | @@ -0,0 +1,236 @@ |
2552 | +// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes) |
2553 | +// Massachusetts Institute of Technology (2007-) |
2554 | +// Woods Hole Oceanographic Institution (2007-) |
2555 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
2556 | +// |
2557 | +// |
2558 | +// This file is part of the Dynamic Compact Control Language Library |
2559 | +// ("DCCL"). |
2560 | +// |
2561 | +// DCCL is free software: you can redistribute them and/or modify |
2562 | +// them under the terms of the GNU Lesser General Public License as published by |
2563 | +// the Free Software Foundation, either version 3 of the License, or |
2564 | +// (at your option) any later version. |
2565 | +// |
2566 | +// DCCL is distributed in the hope that they will be useful, |
2567 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
2568 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2569 | +// GNU Lesser General Public License for more details. |
2570 | +// |
2571 | +// You should have received a copy of the GNU Lesser General Public License |
2572 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
2573 | + |
2574 | + |
2575 | + |
2576 | +#include "dccl/codec.h" |
2577 | +#include "dccl/codecs3/field_codec_default_message.h" |
2578 | + |
2579 | +using dccl::dlog; |
2580 | + |
2581 | +// |
2582 | +// DefaultMessageCodec |
2583 | +// |
2584 | + |
2585 | +void dccl::v3::DefaultMessageCodec::any_encode(Bitset* bits, const boost::any& wire_value) |
2586 | +{ |
2587 | + if(wire_value.empty()) |
2588 | + { |
2589 | + *bits = Bitset(min_size()); |
2590 | + } |
2591 | + else |
2592 | + { |
2593 | + *bits = traverse_const_message<Encoder, Bitset>(wire_value); |
2594 | + |
2595 | + if(is_optional()) |
2596 | + bits->push_front(true); // presence bit |
2597 | + |
2598 | + } |
2599 | +} |
2600 | + |
2601 | + |
2602 | + |
2603 | +unsigned dccl::v3::DefaultMessageCodec::any_size(const boost::any& wire_value) |
2604 | +{ |
2605 | + if(wire_value.empty()) |
2606 | + { |
2607 | + return min_size(); |
2608 | + } |
2609 | + else |
2610 | + { |
2611 | + unsigned size = traverse_const_message<Size, unsigned>(wire_value); |
2612 | + if(is_optional()) |
2613 | + { |
2614 | + const unsigned presence_bit = 1; |
2615 | + size += presence_bit; |
2616 | + } |
2617 | + |
2618 | + return size; |
2619 | + } |
2620 | +} |
2621 | + |
2622 | + |
2623 | +void dccl::v3::DefaultMessageCodec::any_decode(Bitset* bits, boost::any* wire_value) |
2624 | +{ |
2625 | + try |
2626 | + { |
2627 | + |
2628 | + google::protobuf::Message* msg = boost::any_cast<google::protobuf::Message* >(*wire_value); |
2629 | + |
2630 | + if(is_optional()) |
2631 | + { |
2632 | + if(!bits->to_ulong()) |
2633 | + { |
2634 | + *wire_value = boost::any(); |
2635 | + return; |
2636 | + } |
2637 | + else |
2638 | + { |
2639 | + bits->pop_front(); // presence bit |
2640 | + } |
2641 | + } |
2642 | + |
2643 | + const google::protobuf::Descriptor* desc = msg->GetDescriptor(); |
2644 | + const google::protobuf::Reflection* refl = msg->GetReflection(); |
2645 | + |
2646 | + for(int i = 0, n = desc->field_count(); i < n; ++i) |
2647 | + { |
2648 | + |
2649 | + const google::protobuf::FieldDescriptor* field_desc = desc->field(i); |
2650 | + |
2651 | + if(!check_field(field_desc)) |
2652 | + continue; |
2653 | + |
2654 | + |
2655 | + boost::shared_ptr<FieldCodecBase> codec = find(field_desc); |
2656 | + boost::shared_ptr<FromProtoCppTypeBase> helper = |
2657 | + TypeHelper::find(field_desc); |
2658 | + |
2659 | + if(field_desc->is_repeated()) |
2660 | + { |
2661 | + std::vector<boost::any> field_values; |
2662 | + if(field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) |
2663 | + { |
2664 | + unsigned max_repeat = field_desc->options().GetExtension(dccl::field).max_repeat(); |
2665 | + for(unsigned j = 0, m = max_repeat; j < m; ++j) |
2666 | + field_values.push_back(refl->AddMessage(msg, field_desc)); |
2667 | + |
2668 | + codec->field_decode_repeated(bits, &field_values, field_desc); |
2669 | + |
2670 | + // remove the unused messages |
2671 | + for(int j = field_values.size(), m = max_repeat; j < m; ++j) |
2672 | + { |
2673 | + refl->RemoveLast(msg, field_desc); |
2674 | + } |
2675 | + } |
2676 | + else |
2677 | + { |
2678 | + // for primitive types |
2679 | + codec->field_decode_repeated(bits, &field_values, field_desc); |
2680 | + for(int j = 0, m = field_values.size(); j < m; ++j) |
2681 | + helper->add_value(field_desc, msg, field_values[j]); |
2682 | + } |
2683 | + } |
2684 | + else |
2685 | + { |
2686 | + boost::any field_value; |
2687 | + if(field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) |
2688 | + { |
2689 | + // allows us to propagate pointers instead of making many copies of entire messages |
2690 | + field_value = refl->MutableMessage(msg, field_desc); |
2691 | + codec->field_decode(bits, &field_value, field_desc); |
2692 | + if(field_value.empty()) refl->ClearField(msg, field_desc); |
2693 | + } |
2694 | + else |
2695 | + { |
2696 | + // for primitive types |
2697 | + codec->field_decode(bits, &field_value, field_desc); |
2698 | + helper->set_value(field_desc, msg, field_value); |
2699 | + } |
2700 | + } |
2701 | + } |
2702 | + |
2703 | + std::vector< const google::protobuf::FieldDescriptor* > set_fields; |
2704 | + refl->ListFields(*msg, &set_fields); |
2705 | + if(set_fields.empty() && this_field()) *wire_value = boost::any(); |
2706 | + else *wire_value = msg; |
2707 | + } |
2708 | + catch(boost::bad_any_cast& e) |
2709 | + { |
2710 | + throw(Exception("Bad type given to traverse mutable, expecting google::protobuf::Message*, got " + std::string(wire_value->type().name()))); |
2711 | + } |
2712 | + |
2713 | +} |
2714 | + |
2715 | + |
2716 | +unsigned dccl::v3::DefaultMessageCodec::max_size() |
2717 | +{ |
2718 | + unsigned u = 0; |
2719 | + traverse_descriptor<MaxSize>(&u); |
2720 | + |
2721 | + if(is_optional()) |
2722 | + { |
2723 | + const unsigned presence_bit = 1; |
2724 | + u += presence_bit; |
2725 | + } |
2726 | + |
2727 | + return u; |
2728 | +} |
2729 | + |
2730 | +unsigned dccl::v3::DefaultMessageCodec::min_size() |
2731 | +{ |
2732 | + if(is_optional()) |
2733 | + { |
2734 | + const unsigned presence_bit = 1; |
2735 | + return presence_bit; |
2736 | + } |
2737 | + else |
2738 | + { |
2739 | + unsigned u = 0; |
2740 | + traverse_descriptor<MinSize>(&u); |
2741 | + return u; |
2742 | + } |
2743 | +} |
2744 | + |
2745 | + |
2746 | +void dccl::v3::DefaultMessageCodec::validate() |
2747 | +{ |
2748 | + bool b = false; |
2749 | + traverse_descriptor<Validate>(&b); |
2750 | +} |
2751 | + |
2752 | +std::string dccl::v3::DefaultMessageCodec::info() |
2753 | +{ |
2754 | + std::stringstream ss; |
2755 | + traverse_descriptor<Info>(&ss); |
2756 | + return ss.str(); |
2757 | +} |
2758 | + |
2759 | +bool dccl::v3::DefaultMessageCodec::check_field(const google::protobuf::FieldDescriptor* field) |
2760 | +{ |
2761 | + if(!field) |
2762 | + { |
2763 | + return true; |
2764 | + } |
2765 | + else |
2766 | + { |
2767 | + dccl::DCCLFieldOptions dccl_field_options = field->options().GetExtension(dccl::field); |
2768 | + if(dccl_field_options.omit()) // omit |
2769 | + { |
2770 | + return false; |
2771 | + } |
2772 | + else if(MessageStack::current_part() == MessageStack::UNKNOWN) // part not yet explicitly specified |
2773 | + { |
2774 | + if((part() == MessageStack::HEAD && !dccl_field_options.in_head()) |
2775 | + || (part() == MessageStack::BODY && dccl_field_options.in_head())) |
2776 | + return false; |
2777 | + else |
2778 | + return true; |
2779 | + } |
2780 | + else if(MessageStack::current_part() != part()) // part specified and doesn't match |
2781 | + return false; |
2782 | + else |
2783 | + return true; |
2784 | + } |
2785 | +} |
2786 | + |
2787 | + |
2788 | |
2789 | === added file 'src/codecs3/field_codec_default_message.h' |
2790 | --- src/codecs3/field_codec_default_message.h 1970-01-01 00:00:00 +0000 |
2791 | +++ src/codecs3/field_codec_default_message.h 2014-08-27 16:27:22 +0000 |
2792 | @@ -0,0 +1,213 @@ |
2793 | +// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes) |
2794 | +// Massachusetts Institute of Technology (2007-) |
2795 | +// Woods Hole Oceanographic Institution (2007-) |
2796 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
2797 | +// |
2798 | +// |
2799 | +// This file is part of the Dynamic Compact Control Language Library |
2800 | +// ("DCCL"). |
2801 | +// |
2802 | +// DCCL is free software: you can redistribute them and/or modify |
2803 | +// them under the terms of the GNU Lesser General Public License as published by |
2804 | +// the Free Software Foundation, either version 3 of the License, or |
2805 | +// (at your option) any later version. |
2806 | +// |
2807 | +// DCCL is distributed in the hope that they will be useful, |
2808 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
2809 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2810 | +// GNU Lesser General Public License for more details. |
2811 | +// |
2812 | +// You should have received a copy of the GNU Lesser General Public License |
2813 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
2814 | + |
2815 | + |
2816 | + |
2817 | +#ifndef DCCLFIELDCODECDEFAULTMESSAGEV320140421H |
2818 | +#define DCCLFIELDCODECDEFAULTMESSAGEV320140421H |
2819 | + |
2820 | +#include "dccl/field_codec.h" |
2821 | +#include "dccl/field_codec_manager.h" |
2822 | + |
2823 | +#include "dccl/protobuf/option_extensions.pb.h" |
2824 | + |
2825 | +namespace dccl |
2826 | +{ |
2827 | + namespace v3 |
2828 | + { |
2829 | + /// \brief Provides the default codec for encoding a base Google Protobuf message or an embedded message by calling the appropriate field codecs for every field. |
2830 | + class DefaultMessageCodec : public FieldCodecBase |
2831 | + { |
2832 | + private: |
2833 | + |
2834 | + void any_encode(Bitset* bits, const boost::any& wire_value); |
2835 | + void any_decode(Bitset* bits, boost::any* wire_value); |
2836 | + unsigned max_size(); |
2837 | + unsigned min_size(); |
2838 | + unsigned any_size(const boost::any& wire_value); |
2839 | + |
2840 | + |
2841 | + boost::shared_ptr<FieldCodecBase> find(const google::protobuf::FieldDescriptor* field_desc) |
2842 | + { |
2843 | + return FieldCodecManager::find(field_desc, has_codec_group(), codec_group()); |
2844 | + } |
2845 | + |
2846 | + bool is_optional() |
2847 | + { return this_field() && this_field()->is_optional(); } |
2848 | + |
2849 | + |
2850 | + void validate(); |
2851 | + std::string info(); |
2852 | + bool check_field(const google::protobuf::FieldDescriptor* field); |
2853 | + |
2854 | + struct Size |
2855 | + { |
2856 | + static void repeated(boost::shared_ptr<FieldCodecBase> codec, |
2857 | + unsigned* return_value, |
2858 | + const std::vector<boost::any>& field_values, |
2859 | + const google::protobuf::FieldDescriptor* field_desc) |
2860 | + { |
2861 | + codec->field_size_repeated(return_value, field_values, field_desc); |
2862 | + } |
2863 | + |
2864 | + static void single(boost::shared_ptr<FieldCodecBase> codec, |
2865 | + unsigned* return_value, |
2866 | + const boost::any& field_value, |
2867 | + const google::protobuf::FieldDescriptor* field_desc) |
2868 | + { |
2869 | + codec->field_size(return_value, field_value, field_desc); |
2870 | + } |
2871 | + |
2872 | + }; |
2873 | + |
2874 | + struct Encoder |
2875 | + { |
2876 | + static void repeated(boost::shared_ptr<FieldCodecBase> codec, |
2877 | + Bitset* return_value, |
2878 | + const std::vector<boost::any>& field_values, |
2879 | + const google::protobuf::FieldDescriptor* field_desc) |
2880 | + { |
2881 | + codec->field_encode_repeated(return_value, field_values, field_desc); |
2882 | + } |
2883 | + |
2884 | + static void single(boost::shared_ptr<FieldCodecBase> codec, |
2885 | + Bitset* return_value, |
2886 | + const boost::any& field_value, |
2887 | + const google::protobuf::FieldDescriptor* field_desc) |
2888 | + { |
2889 | + codec->field_encode(return_value, field_value, field_desc); |
2890 | + } |
2891 | + }; |
2892 | + |
2893 | + struct MaxSize |
2894 | + { |
2895 | + static void field(boost::shared_ptr<FieldCodecBase> codec, |
2896 | + unsigned* return_value, |
2897 | + const google::protobuf::FieldDescriptor* field_desc) |
2898 | + { |
2899 | + codec->field_max_size(return_value, field_desc); |
2900 | + } |
2901 | + }; |
2902 | + |
2903 | + struct MinSize |
2904 | + { |
2905 | + static void field(boost::shared_ptr<FieldCodecBase> codec, |
2906 | + unsigned* return_value, |
2907 | + const google::protobuf::FieldDescriptor* field_desc) |
2908 | + { |
2909 | + codec->field_min_size(return_value, field_desc); |
2910 | + } |
2911 | + }; |
2912 | + |
2913 | + |
2914 | + struct Validate |
2915 | + { |
2916 | + static void field(boost::shared_ptr<FieldCodecBase> codec, |
2917 | + bool* return_value, |
2918 | + const google::protobuf::FieldDescriptor* field_desc) |
2919 | + { |
2920 | + codec->field_validate(return_value, field_desc); |
2921 | + } |
2922 | + }; |
2923 | + |
2924 | + struct Info |
2925 | + { |
2926 | + static void field(boost::shared_ptr<FieldCodecBase> codec, |
2927 | + std::stringstream* return_value, |
2928 | + const google::protobuf::FieldDescriptor* field_desc) |
2929 | + { |
2930 | + codec->field_info(return_value, field_desc); |
2931 | + } |
2932 | + }; |
2933 | + |
2934 | + |
2935 | + template<typename Action, typename ReturnType> |
2936 | + void traverse_descriptor(ReturnType* return_value) |
2937 | + { |
2938 | + const google::protobuf::Descriptor* desc = |
2939 | + FieldCodecBase::this_descriptor(); |
2940 | + for(int i = 0, n = desc->field_count(); i < n; ++i) |
2941 | + { |
2942 | + const google::protobuf::FieldDescriptor* field_desc = desc->field(i); |
2943 | + |
2944 | + if(!check_field(field_desc)) |
2945 | + continue; |
2946 | + |
2947 | + Action::field(find(field_desc), return_value, field_desc); |
2948 | + } |
2949 | + } |
2950 | + |
2951 | + |
2952 | + template<typename Action, typename ReturnType> |
2953 | + ReturnType traverse_const_message(const boost::any& wire_value) |
2954 | + { |
2955 | + try |
2956 | + { |
2957 | + ReturnType return_value = ReturnType(); |
2958 | + |
2959 | + const google::protobuf::Message* msg = boost::any_cast<const google::protobuf::Message*>(wire_value); |
2960 | + const google::protobuf::Descriptor* desc = msg->GetDescriptor(); |
2961 | + const google::protobuf::Reflection* refl = msg->GetReflection(); |
2962 | + for(int i = 0, n = desc->field_count(); i < n; ++i) |
2963 | + { |
2964 | + const google::protobuf::FieldDescriptor* field_desc = desc->field(i); |
2965 | + |
2966 | + if(!check_field(field_desc)) |
2967 | + continue; |
2968 | + |
2969 | + boost::shared_ptr<FieldCodecBase> codec = find(field_desc); |
2970 | + boost::shared_ptr<FromProtoCppTypeBase> helper = |
2971 | + TypeHelper::find(field_desc); |
2972 | + |
2973 | + |
2974 | + if(field_desc->is_repeated()) |
2975 | + { |
2976 | + std::vector<boost::any> field_values; |
2977 | + for(int j = 0, m = refl->FieldSize(*msg, field_desc); j < m; ++j) |
2978 | + field_values.push_back(helper->get_repeated_value(field_desc, *msg, j)); |
2979 | + |
2980 | + Action::repeated(codec, &return_value, field_values, field_desc); |
2981 | + } |
2982 | + else |
2983 | + { |
2984 | + Action::single(codec, &return_value, helper->get_value(field_desc, *msg), field_desc); |
2985 | + } |
2986 | + } |
2987 | + return return_value; |
2988 | + } |
2989 | + catch(boost::bad_any_cast& e) |
2990 | + { |
2991 | + throw(Exception("Bad type given to traverse const, expecting const google::protobuf::Message*, got " + std::string(wire_value.type().name()))); |
2992 | + } |
2993 | + |
2994 | + } |
2995 | + }; |
2996 | + |
2997 | + } |
2998 | +} |
2999 | + |
3000 | +//encode, size, etc. |
3001 | + |
3002 | + |
3003 | + |
3004 | + |
3005 | +#endif |
3006 | |
3007 | === modified file 'src/field_codec.cpp' |
3008 | --- src/field_codec.cpp 2014-04-22 20:10:37 +0000 |
3009 | +++ src/field_codec.cpp 2014-08-27 16:27:22 +0000 |
3010 | @@ -29,6 +29,7 @@ |
3011 | dccl::MessageStack::UNKNOWN; |
3012 | |
3013 | const google::protobuf::Message* dccl::FieldCodecBase::root_message_ = 0; |
3014 | +const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor_ = 0; |
3015 | |
3016 | using dccl::dlog; |
3017 | using namespace dccl::logger; |
3018 | @@ -66,6 +67,7 @@ |
3019 | |
3020 | Bitset new_bits; |
3021 | any_encode(&new_bits, wire_value); |
3022 | + disp_size(field, new_bits, msg_handler.field_.size()); |
3023 | bits->append(new_bits); |
3024 | } |
3025 | |
3026 | @@ -80,6 +82,7 @@ |
3027 | |
3028 | Bitset new_bits; |
3029 | any_encode_repeated(&new_bits, wire_values); |
3030 | + disp_size(field, new_bits, msg_handler.field_.size(), wire_values.size()); |
3031 | bits->append(new_bits); |
3032 | } |
3033 | |
3034 | @@ -190,7 +193,8 @@ |
3035 | |
3036 | std::vector<boost::any> wire_values = *field_values; |
3037 | any_decode_repeated(&these_bits, &wire_values); |
3038 | - |
3039 | + |
3040 | + field_values->clear(); |
3041 | field_post_decode_repeated(wire_values, field_values); |
3042 | } |
3043 | |
3044 | @@ -199,7 +203,7 @@ |
3045 | const google::protobuf::Descriptor* desc, |
3046 | MessageStack::MessagePart part) |
3047 | { |
3048 | - BaseRAII scoped_globals(part); |
3049 | + BaseRAII scoped_globals(part, desc); |
3050 | *bit_size = 0; |
3051 | |
3052 | MessageStack msg_handler; |
3053 | @@ -228,7 +232,7 @@ |
3054 | const google::protobuf::Descriptor* desc, |
3055 | MessageStack::MessagePart part) |
3056 | { |
3057 | - BaseRAII scoped_globals(part); |
3058 | + BaseRAII scoped_globals(part, desc); |
3059 | |
3060 | *bit_size = 0; |
3061 | |
3062 | @@ -257,7 +261,7 @@ |
3063 | void dccl::FieldCodecBase::base_validate(const google::protobuf::Descriptor* desc, |
3064 | MessageStack::MessagePart part) |
3065 | { |
3066 | - BaseRAII scoped_globals(part); |
3067 | + BaseRAII scoped_globals(part, desc); |
3068 | |
3069 | MessageStack msg_handler; |
3070 | if(desc) |
3071 | @@ -283,7 +287,7 @@ |
3072 | |
3073 | void dccl::FieldCodecBase::base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessageStack::MessagePart part) |
3074 | { |
3075 | - BaseRAII scoped_globals(part); |
3076 | + BaseRAII scoped_globals(part, desc); |
3077 | |
3078 | MessageStack msg_handler; |
3079 | if(desc) |
3080 | @@ -337,7 +341,11 @@ |
3081 | } |
3082 | |
3083 | int width = this_field() ? full_width-name.size() : full_width-name.size()+spaces; |
3084 | - ss << indent << name << std::setfill('.') << std::setw(std::max(1, width)) << range.str(); |
3085 | + ss << indent << name << |
3086 | + std::setfill('.') << std::setw(std::max(1, width)) << range.str() |
3087 | + << " {" << (this_field() ? FieldCodecManager::find(this_field(), has_codec_group(), codec_group())->name() : FieldCodecManager::find(root_descriptor_)->name()) << "}"; |
3088 | + |
3089 | + |
3090 | |
3091 | // std::string s = ss.str(); |
3092 | // boost::replace_all(s, "\n", "\n" + indent); |
3093 | @@ -353,6 +361,14 @@ |
3094 | |
3095 | } |
3096 | |
3097 | +std::string dccl::FieldCodecBase::codec_group(const google::protobuf::Descriptor* desc) |
3098 | +{ |
3099 | + if(desc->options().GetExtension(dccl::msg).has_codec_group()) |
3100 | + return desc->options().GetExtension(dccl::msg).codec_group(); |
3101 | + else |
3102 | + return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version()); |
3103 | +} |
3104 | + |
3105 | |
3106 | // |
3107 | // FieldCodecBase protected |
3108 | @@ -366,7 +382,18 @@ |
3109 | void dccl::FieldCodecBase::any_encode_repeated(dccl::Bitset* bits, const std::vector<boost::any>& wire_values) |
3110 | { |
3111 | // out_bits = [field_values[2]][field_values[1]][field_values[0]] |
3112 | - for(unsigned i = 0, n = dccl_field_options().max_repeat(); i < n; ++i) |
3113 | + |
3114 | + unsigned wire_vector_size = dccl_field_options().max_repeat(); |
3115 | + |
3116 | + // for DCCL3 and beyond, add a prefix numeric field giving the vector size (rather than always going to max_repeat |
3117 | + if(codec_version() > 2) |
3118 | + { |
3119 | + wire_vector_size = std::min((int)dccl_field_options().max_repeat(), (int)wire_values.size()); |
3120 | + Bitset size_bits(repeated_vector_field_size(dccl_field_options().max_repeat()), wire_values.size()); |
3121 | + bits->append(size_bits); |
3122 | + } |
3123 | + |
3124 | + for(unsigned i = 0, n = wire_vector_size; i < n; ++i) |
3125 | { |
3126 | Bitset new_bits; |
3127 | if(i < wire_values.size()) |
3128 | @@ -379,27 +406,41 @@ |
3129 | } |
3130 | |
3131 | |
3132 | + |
3133 | void dccl::FieldCodecBase::any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* wire_values) |
3134 | { |
3135 | - for(unsigned i = 0, n = dccl_field_options().max_repeat(); i < n; ++i) |
3136 | + |
3137 | + unsigned wire_vector_size = dccl_field_options().max_repeat(); |
3138 | + if(codec_version() > 2) |
3139 | + { |
3140 | + Bitset size_bits(repeated_bits); |
3141 | + size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().max_repeat())); |
3142 | + |
3143 | + wire_vector_size = size_bits.to_ulong(); |
3144 | + } |
3145 | + |
3146 | + wire_values->resize(wire_vector_size); |
3147 | + |
3148 | + for(unsigned i = 0, n = wire_vector_size; i < n; ++i) |
3149 | { |
3150 | Bitset these_bits(repeated_bits); |
3151 | - these_bits.get_more_bits(min_size()); |
3152 | - |
3153 | - boost::any value; |
3154 | - |
3155 | - if(wire_values->size() > i) |
3156 | - value = (*wire_values)[i]; |
3157 | - |
3158 | - any_decode(&these_bits, &value); |
3159 | - wire_values->push_back(value); |
3160 | + these_bits.get_more_bits(min_size()); |
3161 | + any_decode(&these_bits, &(*wire_values)[i]); |
3162 | } |
3163 | } |
3164 | |
3165 | unsigned dccl::FieldCodecBase::any_size_repeated(const std::vector<boost::any>& wire_values) |
3166 | { |
3167 | unsigned out = 0; |
3168 | - for(unsigned i = 0, n = dccl_field_options().max_repeat(); i < n; ++i) |
3169 | + unsigned wire_vector_size = dccl_field_options().max_repeat(); |
3170 | + |
3171 | + if(codec_version() > 2) |
3172 | + { |
3173 | + wire_vector_size = std::min((int)dccl_field_options().max_repeat(), (int)wire_values.size()); |
3174 | + out += repeated_vector_field_size(dccl_field_options().max_repeat()); |
3175 | + } |
3176 | + |
3177 | + for(unsigned i = 0, n = wire_vector_size; i < n; ++i) |
3178 | { |
3179 | if(i < wire_values.size()) |
3180 | out += any_size(wire_values[i]); |
3181 | @@ -413,6 +454,8 @@ |
3182 | { |
3183 | if(!dccl_field_options().has_max_repeat()) |
3184 | throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field: " + this_field()->DebugString())); |
3185 | + else if(codec_version() > 2) |
3186 | + return repeated_vector_field_size(dccl_field_options().max_repeat()) + max_size() * dccl_field_options().max_repeat(); |
3187 | else |
3188 | return max_size() * dccl_field_options().max_repeat(); |
3189 | } |
3190 | @@ -421,6 +464,8 @@ |
3191 | { |
3192 | if(!dccl_field_options().has_max_repeat()) |
3193 | throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field " + this_field()->DebugString())); |
3194 | + else if(codec_version() > 2) |
3195 | + return repeated_vector_field_size(dccl_field_options().max_repeat()); |
3196 | else |
3197 | return min_size() * dccl_field_options().max_repeat(); |
3198 | } |
3199 | @@ -453,3 +498,22 @@ |
3200 | // FieldCodecBase private |
3201 | // |
3202 | |
3203 | +void dccl::FieldCodecBase::disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size /* = -1 */) |
3204 | +{ |
3205 | + if(!root_descriptor_) |
3206 | + return; |
3207 | + |
3208 | + if(dlog.is(INFO, SIZE)) |
3209 | + { |
3210 | + std::string name = ((field) ? field->name() : root_descriptor_->full_name()); |
3211 | + if(vector_size >= 0) |
3212 | + name += "[" + boost::lexical_cast<std::string>(vector_size) + "]"; |
3213 | + |
3214 | + |
3215 | + dlog << std::string(depth, '|') << name << std::setfill('.') << std::setw(40-name.size()-depth) << new_bits.size() << std::endl; |
3216 | + |
3217 | + if(!field) |
3218 | + dlog << std::endl; |
3219 | + |
3220 | + } |
3221 | +} |
3222 | |
3223 | === modified file 'src/field_codec.h' |
3224 | --- src/field_codec.h 2014-04-22 20:10:37 +0000 |
3225 | +++ src/field_codec.h 2014-08-27 16:27:22 +0000 |
3226 | @@ -28,6 +28,7 @@ |
3227 | #include <string> |
3228 | |
3229 | #include <boost/any.hpp> |
3230 | +#include <boost/lexical_cast.hpp> |
3231 | |
3232 | #include <google/protobuf/message.h> |
3233 | #include <google/protobuf/descriptor.pb.h> |
3234 | @@ -38,6 +39,7 @@ |
3235 | #include "dccl/protobuf/option_extensions.pb.h" |
3236 | #include "type_helper.h" |
3237 | #include "field_codec_message_stack.h" |
3238 | +#include "dccl/binary.h" |
3239 | |
3240 | namespace dccl |
3241 | { |
3242 | @@ -94,7 +96,25 @@ |
3243 | // currently encoded or (partially) decoded root message |
3244 | static const google::protobuf::Message* root_message() |
3245 | { return root_message_; } |
3246 | - |
3247 | + |
3248 | + static bool has_codec_group() |
3249 | + { |
3250 | + if(root_descriptor_) |
3251 | + { |
3252 | + return root_descriptor_->options().GetExtension(dccl::msg).has_codec_group() || |
3253 | + root_descriptor_->options().GetExtension(dccl::msg).has_codec_version(); |
3254 | + } |
3255 | + else |
3256 | + return false; |
3257 | + } |
3258 | + |
3259 | + static std::string codec_group(const google::protobuf::Descriptor* desc); |
3260 | + |
3261 | + static std::string codec_group() |
3262 | + { return codec_group(root_descriptor_); } |
3263 | + |
3264 | + static int codec_version() |
3265 | + { return root_descriptor_->options().GetExtension(dccl::msg).codec_version(); } |
3266 | |
3267 | /// \brief the part of the message currently being encoded (head or body). |
3268 | static MessageStack::MessagePart part() { return part_; } |
3269 | @@ -379,7 +399,6 @@ |
3270 | /// |
3271 | /// \return Minimum size of this field (in bits). |
3272 | virtual unsigned min_size() = 0; |
3273 | - |
3274 | |
3275 | virtual void any_encode_repeated(Bitset* bits, const std::vector<boost::any>& wire_values); |
3276 | virtual void any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* field_values); |
3277 | @@ -404,29 +423,52 @@ |
3278 | void set_wire_type(google::protobuf::FieldDescriptor::CppType type) |
3279 | { wire_type_ = type; } |
3280 | |
3281 | - bool variable_size() { return max_size() != min_size(); } |
3282 | - |
3283 | + bool variable_size() |
3284 | + { |
3285 | + if(this_field() && this_field()->is_repeated()) |
3286 | + return max_size_repeated() != min_size_repeated(); |
3287 | + else |
3288 | + return max_size() != min_size(); |
3289 | + } |
3290 | + |
3291 | + int repeated_vector_field_size(int max_repeat) |
3292 | + { return dccl::ceil_log2(max_repeat+1); } |
3293 | + |
3294 | + void disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size = -1); |
3295 | + |
3296 | + |
3297 | private: |
3298 | // sets global statics relating the current message begin processed |
3299 | // and unsets them on destruction |
3300 | struct BaseRAII |
3301 | { |
3302 | BaseRAII(MessageStack::MessagePart part, |
3303 | - const google::protobuf::Message* root_message = 0) |
3304 | + const google::protobuf::Descriptor* root_descriptor) |
3305 | + { |
3306 | + FieldCodecBase::part_ = part; |
3307 | + FieldCodecBase::root_message_ = 0; |
3308 | + FieldCodecBase::root_descriptor_ = root_descriptor; |
3309 | + } |
3310 | + |
3311 | + BaseRAII(MessageStack::MessagePart part, |
3312 | + const google::protobuf::Message* root_message) |
3313 | { |
3314 | FieldCodecBase::part_ = part; |
3315 | FieldCodecBase::root_message_ = root_message; |
3316 | + FieldCodecBase::root_descriptor_ = root_message->GetDescriptor(); |
3317 | } |
3318 | ~BaseRAII() |
3319 | { |
3320 | FieldCodecBase::part_ = dccl::MessageStack::UNKNOWN; |
3321 | FieldCodecBase::root_message_ = 0; |
3322 | + FieldCodecBase::root_descriptor_ = 0; |
3323 | } |
3324 | }; |
3325 | |
3326 | |
3327 | static MessageStack::MessagePart part_; |
3328 | static const google::protobuf::Message* root_message_; |
3329 | + static const google::protobuf::Descriptor* root_descriptor_; |
3330 | |
3331 | std::string name_; |
3332 | google::protobuf::FieldDescriptor::Type field_type_; |
3333 | |
3334 | === added file 'src/field_codec_id.cpp' |
3335 | --- src/field_codec_id.cpp 1970-01-01 00:00:00 +0000 |
3336 | +++ src/field_codec_id.cpp 2014-08-27 16:27:22 +0000 |
3337 | @@ -0,0 +1,100 @@ |
3338 | +// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes) |
3339 | +// Massachusetts Institute of Technology (2007-) |
3340 | +// Woods Hole Oceanographic Institution (2007-) |
3341 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
3342 | +// |
3343 | +// |
3344 | +// This file is part of the Dynamic Compact Control Language Library |
3345 | +// ("DCCL"). |
3346 | +// |
3347 | +// DCCL is free software: you can redistribute them and/or modify |
3348 | +// them under the terms of the GNU Lesser General Public License as published by |
3349 | +// the Free Software Foundation, either version 3 of the License, or |
3350 | +// (at your option) any later version. |
3351 | +// |
3352 | +// DCCL is distributed in the hope that they will be useful, |
3353 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3354 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3355 | +// GNU Lesser General Public License for more details. |
3356 | +// |
3357 | +// You should have received a copy of the GNU Lesser General Public License |
3358 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
3359 | + |
3360 | +#include "field_codec_id.h" |
3361 | + |
3362 | +// |
3363 | +// DefaultIdentifierCodec |
3364 | +// |
3365 | + |
3366 | +dccl::Bitset dccl::DefaultIdentifierCodec::encode() |
3367 | +{ |
3368 | + return encode(0); |
3369 | +} |
3370 | + |
3371 | +dccl::Bitset dccl::DefaultIdentifierCodec::encode(const uint32& id) |
3372 | +{ |
3373 | + if(id <= ONE_BYTE_MAX_ID) |
3374 | + { |
3375 | + return(dccl::Bitset(this_size(id), id) << 1); |
3376 | + } |
3377 | + else |
3378 | + { |
3379 | + dccl::Bitset return_bits(this_size(id), id); |
3380 | + return_bits <<= 1; |
3381 | + // set LSB to indicate long header form |
3382 | + return_bits.set(0, true); |
3383 | + |
3384 | + |
3385 | + return return_bits; |
3386 | + } |
3387 | +} |
3388 | + |
3389 | +dccl::uint32 dccl::DefaultIdentifierCodec::decode(Bitset* bits) |
3390 | +{ |
3391 | + if(bits->test(0)) |
3392 | + { |
3393 | + // long header |
3394 | + // grabs more bits to add to the MSB of `bits` |
3395 | + bits->get_more_bits((LONG_FORM_ID_BYTES - SHORT_FORM_ID_BYTES)*BITS_IN_BYTE); |
3396 | + // discard identifier |
3397 | + *(bits) >>= 1; |
3398 | + return bits->to_ulong(); |
3399 | + } |
3400 | + else |
3401 | + { |
3402 | + // short header |
3403 | + *(bits) >>= 1; |
3404 | + return bits->to_ulong(); |
3405 | + } |
3406 | +} |
3407 | + |
3408 | +unsigned dccl::DefaultIdentifierCodec::size() |
3409 | +{ |
3410 | + return this_size(0); |
3411 | +} |
3412 | + |
3413 | +unsigned dccl::DefaultIdentifierCodec::size(const uint32& id) |
3414 | +{ |
3415 | + return this_size(id); |
3416 | +} |
3417 | + |
3418 | +unsigned dccl::DefaultIdentifierCodec::this_size(const uint32& id) |
3419 | +{ |
3420 | + if(id > TWO_BYTE_MAX_ID) |
3421 | + throw(Exception("dccl.id provided (" + boost::lexical_cast<std::string>(id) + ") exceeds maximum: " + boost::lexical_cast<std::string>(int(TWO_BYTE_MAX_ID)))); |
3422 | + |
3423 | + return (id <= ONE_BYTE_MAX_ID) ? |
3424 | + SHORT_FORM_ID_BYTES*BITS_IN_BYTE : |
3425 | + LONG_FORM_ID_BYTES*BITS_IN_BYTE; |
3426 | +} |
3427 | + |
3428 | + |
3429 | +unsigned dccl::DefaultIdentifierCodec::max_size() |
3430 | +{ |
3431 | + return LONG_FORM_ID_BYTES * BITS_IN_BYTE; |
3432 | +} |
3433 | + |
3434 | +unsigned dccl::DefaultIdentifierCodec::min_size() |
3435 | +{ |
3436 | + return SHORT_FORM_ID_BYTES * BITS_IN_BYTE; |
3437 | +} |
3438 | |
3439 | === added file 'src/field_codec_id.h' |
3440 | --- src/field_codec_id.h 1970-01-01 00:00:00 +0000 |
3441 | +++ src/field_codec_id.h 2014-08-27 16:27:22 +0000 |
3442 | @@ -0,0 +1,50 @@ |
3443 | +// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes) |
3444 | +// Massachusetts Institute of Technology (2007-) |
3445 | +// Woods Hole Oceanographic Institution (2007-) |
3446 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
3447 | +// |
3448 | +// |
3449 | +// This file is part of the Dynamic Compact Control Language Library |
3450 | +// ("DCCL"). |
3451 | +// |
3452 | +// DCCL is free software: you can redistribute them and/or modify |
3453 | +// them under the terms of the GNU Lesser General Public License as published by |
3454 | +// the Free Software Foundation, either version 3 of the License, or |
3455 | +// (at your option) any later version. |
3456 | +// |
3457 | +// DCCL is distributed in the hope that they will be useful, |
3458 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
3459 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3460 | +// GNU Lesser General Public License for more details. |
3461 | +// |
3462 | +// You should have received a copy of the GNU Lesser General Public License |
3463 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
3464 | + |
3465 | +#include "field_codec_fixed.h" |
3466 | + |
3467 | +namespace dccl |
3468 | +{ |
3469 | + /// \brief Provides the default 1 byte or 2 byte DCCL ID codec |
3470 | + class DefaultIdentifierCodec : public TypedFieldCodec<uint32> |
3471 | + { |
3472 | + protected: |
3473 | + virtual Bitset encode(); |
3474 | + virtual Bitset encode(const uint32& wire_value); |
3475 | + virtual uint32 decode(Bitset* bits); |
3476 | + virtual unsigned size(); |
3477 | + virtual unsigned size(const uint32& wire_value); |
3478 | + virtual unsigned max_size(); |
3479 | + virtual unsigned min_size(); |
3480 | + virtual void validate() { } |
3481 | + |
3482 | + private: |
3483 | + unsigned this_size(const uint32& wire_value); |
3484 | + // maximum id we can fit in short or long header (MSB reserved to indicate |
3485 | + // short or long header) |
3486 | + enum { ONE_BYTE_MAX_ID = (1 << 7) - 1, |
3487 | + TWO_BYTE_MAX_ID = (1 << 15) - 1}; |
3488 | + |
3489 | + enum { SHORT_FORM_ID_BYTES = 1, |
3490 | + LONG_FORM_ID_BYTES = 2 }; |
3491 | + }; |
3492 | +} |
3493 | |
3494 | === modified file 'src/field_codec_manager.h' |
3495 | --- src/field_codec_manager.h 2014-04-22 20:10:37 +0000 |
3496 | +++ src/field_codec_manager.h 2014-08-27 16:27:22 +0000 |
3497 | @@ -81,12 +81,49 @@ |
3498 | template<class Codec, google::protobuf::FieldDescriptor::Type type> |
3499 | static void add(const std::string& name); |
3500 | |
3501 | + /// \brief Remove a new field codec (used for codecs operating on statically generated Protobuf messages, that is, children of google::protobuf::Message but not google::protobuf::Message itself). |
3502 | + /// |
3503 | + /// \tparam Codec A child of FieldCodecBase |
3504 | + /// \param name Name to use for this codec. Corresponds to (dccl.field).codec="name" in .proto file. |
3505 | + /// \return nothing (void). Return templates are used for template metaprogramming selection of the proper remove() overload. |
3506 | + template<class Codec> |
3507 | + typename boost::enable_if< |
3508 | + boost::mpl::and_<boost::is_base_of<google::protobuf::Message, typename Codec::wire_type>, |
3509 | + boost::mpl::not_<boost::is_same<google::protobuf::Message, typename Codec::wire_type> > |
3510 | + >, |
3511 | + void>::type |
3512 | + static remove(const std::string& name, dummy_fcm<0> dummy_fcm = 0); |
3513 | + |
3514 | + /// \brief Remove a new field codec (used for codecs operating on all types except statically generated Protobuf messages). |
3515 | + /// |
3516 | + /// \tparam Codec A child of FieldCodecBase |
3517 | + /// \param name Name to use for this codec. Corresponds to (dccl.field).codec="name" in .proto file. |
3518 | + /// \return nothing (void). Return templates are used for template metaprogramming selection of the proper remove() overload. |
3519 | + template<class Codec> |
3520 | + typename boost::disable_if< |
3521 | + boost::mpl::and_<boost::is_base_of<google::protobuf::Message, typename Codec::wire_type>, |
3522 | + boost::mpl::not_<boost::is_same<google::protobuf::Message,typename Codec::wire_type> > |
3523 | + >, |
3524 | + void>::type |
3525 | + static remove(const std::string& name, dummy_fcm<1> dummy_fcm = 0); |
3526 | + |
3527 | + /// \brief Remove a new field codec only valid for a specific google::protobuf::FieldDescriptor::Type. This is useful if a given codec is designed to work with only a specific Protobuf type that shares an underlying C++ type (e.g. Protobuf types `bytes` and `string`) |
3528 | + /// |
3529 | + /// \tparam Codec A child of FieldCodecBase |
3530 | + /// \tparam type The google::protobuf::FieldDescriptor::Type enumeration that this codec works on. |
3531 | + /// \param name Name to use for this codec. Corresponds to (dccl.field).codec="name" in .proto file. |
3532 | + template<class Codec, google::protobuf::FieldDescriptor::Type type> |
3533 | + static void remove(const std::string& name); |
3534 | + |
3535 | + |
3536 | /// \brief Find the codec for a given field. For embedded messages, prefers (dccl.field).codec (inside field) over (dccl.msg).codec (inside embedded message). |
3537 | static boost::shared_ptr<FieldCodecBase> find( |
3538 | - const google::protobuf::FieldDescriptor* field) |
3539 | + const google::protobuf::FieldDescriptor* field, |
3540 | + bool has_codec_group, |
3541 | + const std::string& codec_group) |
3542 | { |
3543 | - std::string name = __find_codec(field); |
3544 | - |
3545 | + std::string name = __find_codec(field, has_codec_group, codec_group); |
3546 | + |
3547 | if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) |
3548 | return find(field->message_type(), name); |
3549 | else |
3550 | @@ -101,9 +138,16 @@ |
3551 | const google::protobuf::Descriptor* desc, |
3552 | std::string name = "") |
3553 | { |
3554 | + // this was called on the root message |
3555 | if(name.empty()) |
3556 | - name = desc->options().GetExtension(dccl::msg).codec(); |
3557 | - |
3558 | + { |
3559 | + // explicitly declared codec takes precedence over group |
3560 | + if(desc->options().GetExtension(dccl::msg).has_codec()) |
3561 | + name = desc->options().GetExtension(dccl::msg).codec(); |
3562 | + else |
3563 | + name = FieldCodecBase::codec_group(desc); |
3564 | + } |
3565 | + |
3566 | return __find(google::protobuf::FieldDescriptor::TYPE_MESSAGE, |
3567 | name, desc->full_name()); |
3568 | } |
3569 | @@ -115,6 +159,11 @@ |
3570 | return __find(type, name); |
3571 | } |
3572 | |
3573 | + static void clear() |
3574 | + { |
3575 | + TypeHelper::reset(); |
3576 | + codecs_.clear(); |
3577 | + } |
3578 | |
3579 | |
3580 | private: |
3581 | @@ -132,27 +181,41 @@ |
3582 | |
3583 | static std::string __mangle_name(const std::string& codec_name, |
3584 | const std::string& type_name) |
3585 | - { return type_name.empty() ? codec_name : codec_name + "@@" + type_name; } |
3586 | + { return type_name.empty() ? codec_name : codec_name + "[" + type_name + "]"; } |
3587 | |
3588 | |
3589 | template<typename WireType, typename FieldType, class Codec> |
3590 | - static void __add(const std::string& name); |
3591 | - |
3592 | - template<class Codec> |
3593 | - static void __add(const std::string& name, |
3594 | - google::protobuf::FieldDescriptor::Type field_type, |
3595 | - google::protobuf::FieldDescriptor::CppType wire_type); |
3596 | - |
3597 | - |
3598 | - static std::string __find_codec(const google::protobuf::FieldDescriptor* field) |
3599 | + static void add_all_types(const std::string& name); |
3600 | + |
3601 | + template<class Codec> |
3602 | + static void add_single_type(const std::string& name, |
3603 | + google::protobuf::FieldDescriptor::Type field_type, |
3604 | + google::protobuf::FieldDescriptor::CppType wire_type); |
3605 | + |
3606 | + template<typename WireType, typename FieldType, class Codec> |
3607 | + static void remove_all_types(const std::string& name); |
3608 | + |
3609 | + template<class Codec> |
3610 | + static void remove_single_type(const std::string& name, |
3611 | + google::protobuf::FieldDescriptor::Type field_type, |
3612 | + google::protobuf::FieldDescriptor::CppType wire_type); |
3613 | + |
3614 | + |
3615 | + static std::string __find_codec(const google::protobuf::FieldDescriptor* field, |
3616 | + bool has_codec_group, const std::string& codec_group) |
3617 | { |
3618 | dccl::DCCLFieldOptions dccl_field_options = field->options().GetExtension(dccl::field); |
3619 | |
3620 | // prefer the codec listed as a field extension |
3621 | if(dccl_field_options.has_codec()) |
3622 | - return dccl_field_options.codec(); |
3623 | - else if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) |
3624 | + return dccl_field_options.codec(); |
3625 | + // then, the codec embedded in the message option extension |
3626 | + else if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE && field->message_type()->options().GetExtension(dccl::msg).has_codec()) |
3627 | return field->message_type()->options().GetExtension(dccl::msg).codec(); |
3628 | + // then the overarching codec group |
3629 | + else if(has_codec_group) |
3630 | + return codec_group; |
3631 | + // finally the default |
3632 | else |
3633 | return dccl_field_options.codec(); |
3634 | } |
3635 | @@ -173,9 +236,9 @@ |
3636 | dccl::FieldCodecManager::add(const std::string& name, dummy_fcm<0> dummy_fcm) |
3637 | { |
3638 | TypeHelper::add<typename Codec::wire_type>(); |
3639 | - __add<Codec>(__mangle_name(name, Codec::wire_type::descriptor()->full_name()), |
3640 | - google::protobuf::FieldDescriptor::TYPE_MESSAGE, |
3641 | - google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE); |
3642 | + add_single_type<Codec>(__mangle_name(name, Codec::wire_type::descriptor()->full_name()), |
3643 | + google::protobuf::FieldDescriptor::TYPE_MESSAGE, |
3644 | + google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE); |
3645 | } |
3646 | |
3647 | template<class Codec> |
3648 | @@ -187,18 +250,18 @@ |
3649 | void>::type |
3650 | dccl::FieldCodecManager::add(const std::string& name, dummy_fcm<1> dummy_fcm) |
3651 | { |
3652 | - __add<typename Codec::wire_type, typename Codec::field_type, Codec>(name); |
3653 | + add_all_types<typename Codec::wire_type, typename Codec::field_type, Codec>(name); |
3654 | } |
3655 | |
3656 | template<class Codec, google::protobuf::FieldDescriptor::Type type> |
3657 | void dccl::FieldCodecManager::add(const std::string& name) |
3658 | { |
3659 | - __add<Codec>(name, type, google::protobuf::FieldDescriptor::TypeToCppType(type)); |
3660 | + add_single_type<Codec>(name, type, google::protobuf::FieldDescriptor::TypeToCppType(type)); |
3661 | } |
3662 | |
3663 | |
3664 | template<typename WireType, typename FieldType, class Codec> |
3665 | - void dccl::FieldCodecManager::__add(const std::string& name) |
3666 | + void dccl::FieldCodecManager::add_all_types(const std::string& name) |
3667 | { |
3668 | using google::protobuf::FieldDescriptor; |
3669 | const FieldDescriptor::CppType cpp_field_type = ToProtoCppType<FieldType>::as_enum(); |
3670 | @@ -209,17 +272,17 @@ |
3671 | FieldDescriptor::Type field_type = static_cast<FieldDescriptor::Type>(i); |
3672 | if(FieldDescriptor::TypeToCppType(field_type) == cpp_field_type) |
3673 | { |
3674 | - __add<Codec>(name, field_type, cpp_wire_type); |
3675 | + add_single_type<Codec>(name, field_type, cpp_wire_type); |
3676 | } |
3677 | } |
3678 | } |
3679 | |
3680 | template<class Codec> |
3681 | -void dccl::FieldCodecManager::__add(const std::string& name, |
3682 | - google::protobuf::FieldDescriptor::Type field_type, |
3683 | - google::protobuf::FieldDescriptor::CppType wire_type) |
3684 | +void dccl::FieldCodecManager::add_single_type(const std::string& name, |
3685 | + google::protobuf::FieldDescriptor::Type field_type, |
3686 | + google::protobuf::FieldDescriptor::CppType wire_type) |
3687 | { |
3688 | - using google::protobuf::FieldDescriptor; |
3689 | + using google::protobuf::FieldDescriptor; |
3690 | if(!codecs_[field_type].count(name)) |
3691 | { |
3692 | boost::shared_ptr<FieldCodecBase> new_field_codec(new Codec()); |
3693 | @@ -246,4 +309,82 @@ |
3694 | |
3695 | |
3696 | |
3697 | +template<class Codec> |
3698 | +typename boost::enable_if< |
3699 | +boost::mpl::and_< |
3700 | +boost::is_base_of<google::protobuf::Message, typename Codec::wire_type>, |
3701 | +boost::mpl::not_<boost::is_same<google::protobuf::Message, typename Codec::wire_type> > |
3702 | +>, |
3703 | +void>::type |
3704 | +dccl::FieldCodecManager::remove(const std::string& name, dummy_fcm<0> dummy_fcm) |
3705 | +{ |
3706 | + TypeHelper::remove<typename Codec::wire_type>(); |
3707 | + remove_single_type<Codec>(__mangle_name(name, Codec::wire_type::descriptor()->full_name()), |
3708 | + google::protobuf::FieldDescriptor::TYPE_MESSAGE, |
3709 | + google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE); |
3710 | +} |
3711 | + |
3712 | +template<class Codec> |
3713 | +typename boost::disable_if< |
3714 | +boost::mpl::and_< |
3715 | +boost::is_base_of<google::protobuf::Message, typename Codec::wire_type>, |
3716 | + boost::mpl::not_<boost::is_same<google::protobuf::Message, typename Codec::wire_type> > |
3717 | + >, |
3718 | + void>::type |
3719 | + dccl::FieldCodecManager::remove(const std::string& name, dummy_fcm<1> dummy_fcm) |
3720 | +{ |
3721 | + remove_all_types<typename Codec::wire_type, typename Codec::field_type, Codec>(name); |
3722 | +} |
3723 | + |
3724 | +template<class Codec, google::protobuf::FieldDescriptor::Type type> |
3725 | + void dccl::FieldCodecManager::remove(const std::string& name) |
3726 | +{ |
3727 | + remove_single_type<Codec>(name, type, google::protobuf::FieldDescriptor::TypeToCppType(type)); |
3728 | +} |
3729 | + |
3730 | + |
3731 | +template<typename WireType, typename FieldType, class Codec> |
3732 | + void dccl::FieldCodecManager::remove_all_types(const std::string& name) |
3733 | +{ |
3734 | + using google::protobuf::FieldDescriptor; |
3735 | + const FieldDescriptor::CppType cpp_field_type = ToProtoCppType<FieldType>::as_enum(); |
3736 | + const FieldDescriptor::CppType cpp_wire_type = ToProtoCppType<WireType>::as_enum(); |
3737 | + |
3738 | + for(int i = 1, n = FieldDescriptor::MAX_TYPE; i <= n; ++i) |
3739 | + { |
3740 | + FieldDescriptor::Type field_type = static_cast<FieldDescriptor::Type>(i); |
3741 | + if(FieldDescriptor::TypeToCppType(field_type) == cpp_field_type) |
3742 | + { |
3743 | + remove_single_type<Codec>(name, field_type, cpp_wire_type); |
3744 | + } |
3745 | + } |
3746 | +} |
3747 | + |
3748 | +template<class Codec> |
3749 | +void dccl::FieldCodecManager::remove_single_type(const std::string& name, |
3750 | + google::protobuf::FieldDescriptor::Type field_type, |
3751 | + google::protobuf::FieldDescriptor::CppType wire_type) |
3752 | +{ |
3753 | + using google::protobuf::FieldDescriptor; |
3754 | + if(codecs_[field_type].count(name)) |
3755 | + { |
3756 | + dccl::dlog.is(dccl::logger::DEBUG1) && dccl::dlog << "Removing codec " << *codecs_[field_type][name] << std::endl; |
3757 | + codecs_[field_type].erase(name); |
3758 | + } |
3759 | + else |
3760 | + { |
3761 | + boost::shared_ptr<FieldCodecBase> new_field_codec(new Codec()); |
3762 | + new_field_codec->set_name(name); |
3763 | + new_field_codec->set_field_type(field_type); |
3764 | + new_field_codec->set_wire_type(wire_type); |
3765 | + |
3766 | + dccl::dlog.is(dccl::logger::DEBUG1) && dccl::dlog << "Trying to remove: " << *new_field_codec |
3767 | + << ", but no such codec exists" |
3768 | + << std::endl; |
3769 | + } |
3770 | +} |
3771 | + |
3772 | + |
3773 | + |
3774 | + |
3775 | #endif |
3776 | |
3777 | === modified file 'src/field_codec_message_stack.cpp' |
3778 | --- src/field_codec_message_stack.cpp 2014-04-22 20:10:37 +0000 |
3779 | +++ src/field_codec_message_stack.cpp 2014-08-27 16:27:22 +0000 |
3780 | @@ -26,7 +26,7 @@ |
3781 | |
3782 | std::vector<const google::protobuf::FieldDescriptor*> dccl::MessageStack::field_; |
3783 | std::vector<const google::protobuf::Descriptor*> dccl::MessageStack::desc_; |
3784 | -dccl::MessageStack::MessagePart dccl::MessageStack::current_part_ = dccl::MessageStack::UNKNOWN; |
3785 | +std::vector<dccl::MessageStack::MessagePart> dccl::MessageStack::parts_; |
3786 | |
3787 | // |
3788 | // MessageStack |
3789 | @@ -45,6 +45,12 @@ |
3790 | ++fields_pushed_; |
3791 | } |
3792 | |
3793 | +void dccl::MessageStack::push(MessagePart part) |
3794 | +{ |
3795 | + parts_.push_back(part); |
3796 | + ++parts_pushed_; |
3797 | +} |
3798 | + |
3799 | |
3800 | void dccl::MessageStack::__pop_desc() |
3801 | { |
3802 | @@ -58,17 +64,34 @@ |
3803 | field_.pop_back(); |
3804 | } |
3805 | |
3806 | +void dccl::MessageStack::__pop_parts() |
3807 | +{ |
3808 | + if(!parts_.empty()) |
3809 | + parts_.pop_back(); |
3810 | +} |
3811 | + |
3812 | + |
3813 | dccl::MessageStack::MessageStack(const google::protobuf::FieldDescriptor* field) |
3814 | : descriptors_pushed_(0), |
3815 | - fields_pushed_(0) |
3816 | + fields_pushed_(0), |
3817 | + parts_pushed_(0) |
3818 | { |
3819 | if(field) |
3820 | { |
3821 | if(field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) |
3822 | { |
3823 | - // if explicitly set, set part (HEAD or BODY) of message for all children of this message |
3824 | + MessagePart part = UNKNOWN; |
3825 | if(field->options().GetExtension(dccl::field).has_in_head()) |
3826 | - current_part_ = field->options().GetExtension(dccl::field).in_head() ? HEAD : BODY; |
3827 | + { |
3828 | + // if explicitly set, set part (HEAD or BODY) of message for all children of this message |
3829 | + part = field->options().GetExtension(dccl::field).in_head() ? HEAD : BODY; |
3830 | + } |
3831 | + else |
3832 | + { |
3833 | + // use the parent's current part |
3834 | + part = current_part(); |
3835 | + } |
3836 | + push(part); |
3837 | |
3838 | push(field->message_type()); |
3839 | } |
3840 | @@ -77,3 +100,14 @@ |
3841 | |
3842 | } |
3843 | |
3844 | +dccl::MessageStack::~MessageStack() |
3845 | +{ |
3846 | + for(int i = 0; i < fields_pushed_; ++i) |
3847 | + __pop_field(); |
3848 | + |
3849 | + for(int i = 0; i < descriptors_pushed_; ++i) |
3850 | + __pop_desc(); |
3851 | + |
3852 | + for(int i = 0; i < parts_pushed_; ++i) |
3853 | + __pop_parts(); |
3854 | +} |
3855 | |
3856 | === modified file 'src/field_codec_message_stack.h' |
3857 | --- src/field_codec_message_stack.h 2014-04-22 20:10:37 +0000 |
3858 | +++ src/field_codec_message_stack.h 2014-08-27 16:27:22 +0000 |
3859 | @@ -34,19 +34,7 @@ |
3860 | public: |
3861 | MessageStack(const google::protobuf::FieldDescriptor* field = 0); |
3862 | |
3863 | - ~MessageStack() |
3864 | - { |
3865 | - for(int i = 0; i < descriptors_pushed_; ++i) |
3866 | - __pop_desc(); |
3867 | - |
3868 | - for(int i = 0; i < fields_pushed_; ++i) |
3869 | - __pop_field(); |
3870 | - |
3871 | - if(desc_.empty()) |
3872 | - { |
3873 | - current_part_ = UNKNOWN; |
3874 | - } |
3875 | - } |
3876 | + ~MessageStack(); |
3877 | |
3878 | enum MessagePart { HEAD, BODY, UNKNOWN }; |
3879 | |
3880 | @@ -57,19 +45,22 @@ |
3881 | |
3882 | void push(const google::protobuf::Descriptor* desc); |
3883 | void push(const google::protobuf::FieldDescriptor* field); |
3884 | + void push(MessagePart part); |
3885 | |
3886 | - static MessagePart current_part() { return current_part_; } |
3887 | - |
3888 | + static MessagePart current_part() { return parts_.empty() ? UNKNOWN : parts_.back(); } |
3889 | + |
3890 | friend class FieldCodecBase; |
3891 | private: |
3892 | void __pop_desc(); |
3893 | void __pop_field(); |
3894 | + void __pop_parts(); |
3895 | |
3896 | static std::vector<const google::protobuf::Descriptor*> desc_; |
3897 | static std::vector<const google::protobuf::FieldDescriptor*> field_; |
3898 | + static std::vector<MessagePart> parts_; |
3899 | int descriptors_pushed_; |
3900 | int fields_pushed_; |
3901 | - static MessagePart current_part_; |
3902 | + int parts_pushed_; |
3903 | }; |
3904 | } |
3905 | |
3906 | |
3907 | === modified file 'src/field_codec_typed.h' |
3908 | --- src/field_codec_typed.h 2014-04-22 20:10:37 +0000 |
3909 | +++ src/field_codec_typed.h 2014-08-27 16:27:22 +0000 |
3910 | @@ -24,6 +24,9 @@ |
3911 | #ifndef DCCLFIELDCODECTYPED20120312H |
3912 | #define DCCLFIELDCODECTYPED20120312H |
3913 | |
3914 | + |
3915 | +#include <boost/type_traits.hpp> |
3916 | + |
3917 | #include "field_codec.h" |
3918 | |
3919 | namespace dccl |
3920 | @@ -72,7 +75,7 @@ |
3921 | class TypedFieldCodec : public FieldCodecSelector<WireType, FieldType> |
3922 | { |
3923 | public: |
3924 | - typedef WireType wire_type; |
3925 | +typedef WireType wire_type; |
3926 | typedef FieldType field_type; |
3927 | |
3928 | public: |
3929 | @@ -256,8 +259,14 @@ |
3930 | /// |
3931 | /// \param bits Bits to use for decoding. |
3932 | /// \return the decoded value. |
3933 | - virtual WireType decode(Bitset* bits) |
3934 | - { return decode_repeated(bits).at(0); } |
3935 | + virtual WireType decode(dccl::Bitset* bits) |
3936 | + { |
3937 | + std::vector<WireType> return_vec = decode_repeated(bits); |
3938 | + if(return_vec.empty()) |
3939 | + throw dccl::NullValueException(); |
3940 | + else |
3941 | + return return_vec.at(0); |
3942 | + } |
3943 | |
3944 | /// \brief Calculate the size (in bits) of an empty field. |
3945 | /// |
3946 | |
3947 | === modified file 'src/logger.cpp' |
3948 | --- src/logger.cpp 2014-04-22 20:10:37 +0000 |
3949 | +++ src/logger.cpp 2014-08-27 16:27:22 +0000 |
3950 | @@ -55,6 +55,7 @@ |
3951 | case logger::GENERAL: break; |
3952 | case logger::ENCODE: grp_str = "{encode}: "; break; |
3953 | case logger::DECODE: grp_str = "{decode}: "; break; |
3954 | + case logger::SIZE: grp_str = "{size}: "; break; |
3955 | } |
3956 | |
3957 | std::time_t now = std::time(0); |
3958 | @@ -64,11 +65,12 @@ |
3959 | { |
3960 | *os << "[ " << (t->tm_year+1900) << "-" |
3961 | << std::setw(2) << std::setfill('0') << (t->tm_mon+1) << "-" |
3962 | - << std::setw(2) << std::setfill('0') << t->tm_mday |
3963 | + << std::setw(2) << t->tm_mday |
3964 | << " " |
3965 | - << std::setw(2) << std::setfill('0') << t->tm_hour << ":" |
3966 | - << std::setw(2) << std::setfill('0') << t->tm_min << ":" |
3967 | - << std::setw(2) << std::setfill('0') << t->tm_sec << " ]: "; |
3968 | + << std::setw(2) << t->tm_hour << ":" |
3969 | + << std::setw(2) << t->tm_min << ":" |
3970 | + << std::setw(2) << t->tm_sec << " ]: " |
3971 | + << std::setfill(' '); |
3972 | } |
3973 | |
3974 | *os << grp_str << msg << std::endl; |
3975 | |
3976 | === modified file 'src/logger.h' |
3977 | --- src/logger.h 2014-04-22 20:10:37 +0000 |
3978 | +++ src/logger.h 2014-08-27 16:27:22 +0000 |
3979 | @@ -47,10 +47,11 @@ |
3980 | DEBUG3_PLUS = DEBUG3 | (DEBUG3 - 1) |
3981 | }; |
3982 | enum Group |
3983 | - { GENERAL, ENCODE, DECODE }; |
3984 | + { GENERAL, ENCODE, DECODE, SIZE }; |
3985 | |
3986 | } |
3987 | |
3988 | + |
3989 | |
3990 | void to_ostream(const std::string& msg, dccl::logger::Verbosity vrb, |
3991 | dccl::logger::Group grp, std::ostream* os, bool add_timestamp); |
3992 | |
3993 | === modified file 'src/protobuf/option_extensions.proto' |
3994 | --- src/protobuf/option_extensions.proto 2013-08-20 16:17:28 +0000 |
3995 | +++ src/protobuf/option_extensions.proto 2014-08-27 16:27:22 +0000 |
3996 | @@ -25,7 +25,7 @@ |
3997 | message DCCLFieldOptions |
3998 | { |
3999 | // what encoder / decoder should we use? |
4000 | - optional string codec = 1 [default = "dccl.default"]; |
4001 | + optional string codec = 1 [default = "dccl.default2"]; |
4002 | // leave this field out of DCCL transmissions (has_field() will be false on receipt) |
4003 | optional bool omit = 2 [default = false]; |
4004 | // set true for fields in the header (will *not* be encrypte)d |
4005 | @@ -60,9 +60,12 @@ |
4006 | |
4007 | message DCCLMessageOptions |
4008 | { |
4009 | - required int32 id = 1; |
4010 | - required uint32 max_bytes = 2; |
4011 | - |
4012 | - optional string codec = 3 [default = "dccl.default"]; |
4013 | + optional int32 id = 1; |
4014 | + optional uint32 max_bytes = 2; |
4015 | + |
4016 | + optional string codec = 3 [default = "dccl.default2"]; |
4017 | + |
4018 | + optional string codec_group = 4 [default = "dccl.default2"]; |
4019 | + optional int32 codec_version = 5 [default = 2]; |
4020 | } |
4021 | |
4022 | |
4023 | === modified file 'src/test/CMakeLists.txt' |
4024 | --- src/test/CMakeLists.txt 2014-03-26 16:25:12 +0000 |
4025 | +++ src/test/CMakeLists.txt 2014-08-27 16:27:22 +0000 |
4026 | @@ -10,6 +10,8 @@ |
4027 | add_subdirectory(dccl_static_methods) |
4028 | add_subdirectory(dccl_custom_id) |
4029 | add_subdirectory(dccl_numeric_bounds) |
4030 | +add_subdirectory(dccl_codec_group) |
4031 | +add_subdirectory(dccl_message_fix) |
4032 | |
4033 | if(build_ccl) |
4034 | add_subdirectory(dccl_ccl) |
4035 | @@ -19,6 +21,9 @@ |
4036 | add_subdirectory(dccl_arithmetic) |
4037 | endif() |
4038 | |
4039 | +add_subdirectory(dccl_v2_all_fields) |
4040 | +add_subdirectory(dccl_v2_header) |
4041 | + |
4042 | add_subdirectory(bitset1) |
4043 | |
4044 | add_subdirectory(logger1) |
4045 | |
4046 | === modified file 'src/test/dccl_all_fields/test.cpp' |
4047 | --- src/test/dccl_all_fields/test.cpp 2014-04-22 20:13:39 +0000 |
4048 | +++ src/test/dccl_all_fields/test.cpp 2014-08-27 16:27:22 +0000 |
4049 | @@ -136,7 +136,9 @@ |
4050 | decode_check(bytes); |
4051 | |
4052 | // make sure DCCL defaults stay wire compatible |
4053 | - decode_check(dccl::hex_decode("047f277b9628060000b95660c0b0188000d8c0132858800008000dc2c4c6626466024488cca8ee324bd05c3f23af0000ad9112a09509788013e0820b18e0005ed0204c6c2c4666062042644675975982c65235f10a00ad718a5801000000905f27121600000000a0170050640300309201001a0b00007d320a0000a61a0070b20100a81b00d09c6f0000a0401026361643102636160300f0dfbd5b2280ea2e330f3da59a2100aabfa55a000000000000000000000000")); |
4054 | + |
4055 | + // v3 |
4056 | + decode_check(dccl::hex_decode("047f277b16b95660c0b0188000d8c0132858800008002d4c6c2c4666264084c88cea2eb304cdeb67cc2b00b4464a805626e0014e800b2e60800378410b131b8b91990188109951dd6596a0b154cd7805506b9c2256caaf13094ba0978a6c248a692493c682fa6454a69a4e36a16e6ace37a918263616c330b1b118fd77ef9608a0bacbac574fa9cd1050fd6daa0500")); |
4057 | |
4058 | // run a bunch of tests with random strings |
4059 | std::string random = bytes; |
4060 | |
4061 | === modified file 'src/test/dccl_all_fields/test.proto' |
4062 | --- src/test/dccl_all_fields/test.proto 2012-10-19 16:41:36 +0000 |
4063 | +++ src/test/dccl_all_fields/test.proto 2014-08-27 16:27:22 +0000 |
4064 | @@ -29,6 +29,7 @@ |
4065 | { |
4066 | option (dccl.msg).id = 2; |
4067 | option (dccl.msg).max_bytes = 512; |
4068 | + option (dccl.msg).codec_version = 3; |
4069 | |
4070 | // test default enc/dec |
4071 | optional double double_default_optional = 1 [(dccl.field).min=-100, |
4072 | @@ -123,8 +124,7 @@ |
4073 | (dccl.field).max_repeat=4]; |
4074 | repeated uint32 uint32_default_repeat = 105 [(dccl.field).min=0, |
4075 | (dccl.field).max=100, |
4076 | - (dccl.field).max_repeat=4, |
4077 | - (dccl.field).in_head=true]; |
4078 | + (dccl.field).max_repeat=4]; |
4079 | repeated uint64 uint64_default_repeat = 106 [(dccl.field).min=0, |
4080 | (dccl.field).max=100, |
4081 | (dccl.field).max_repeat=4]; |
4082 | |
4083 | === modified file 'src/test/dccl_arithmetic/test.proto' |
4084 | --- src/test/dccl_arithmetic/test.proto 2012-10-23 00:46:12 +0000 |
4085 | +++ src/test/dccl_arithmetic/test.proto 2014-08-27 16:27:22 +0000 |
4086 | @@ -25,7 +25,8 @@ |
4087 | { |
4088 | option (dccl.msg).id = 1; |
4089 | option (dccl.msg).max_bytes = 512; |
4090 | - |
4091 | + option (dccl.msg).codec_version = 3; |
4092 | + |
4093 | repeated double value = 101 [(dccl.field).codec = "_arithmetic", |
4094 | (dccl.field).(arithmetic).model = "model", |
4095 | (dccl.field).(arithmetic).debug_assert = true, |
4096 | @@ -35,6 +36,7 @@ |
4097 | { |
4098 | option (dccl.msg).id = 2; |
4099 | option (dccl.msg).max_bytes = 512; |
4100 | + option (dccl.msg).codec_version = 3; |
4101 | |
4102 | repeated Enum1 value = 114 [(dccl.field).codec = "_arithmetic", |
4103 | (dccl.field).(arithmetic).model = "model", |
4104 | @@ -47,6 +49,7 @@ |
4105 | { |
4106 | option (dccl.msg).id = 3; |
4107 | option (dccl.msg).max_bytes = 512; |
4108 | + option (dccl.msg).codec_version = 3; |
4109 | |
4110 | required Enum1 value = 114 [(dccl.field).codec = "_arithmetic", |
4111 | (dccl.field).(arithmetic).model = "model", |
4112 | @@ -58,6 +61,7 @@ |
4113 | { |
4114 | option (dccl.msg).id = 4; |
4115 | option (dccl.msg).max_bytes = 512; |
4116 | + option (dccl.msg).codec_version = 3; |
4117 | |
4118 | repeated Enum2 value = 114 [(dccl.field).codec = "_arithmetic", |
4119 | (dccl.field).(arithmetic).model = "model", |
4120 | @@ -70,6 +74,7 @@ |
4121 | { |
4122 | option (dccl.msg).id = 5; |
4123 | option (dccl.msg).max_bytes = 10000; |
4124 | + option (dccl.msg).codec_version = 3; |
4125 | |
4126 | repeated int32 value = 101 [(dccl.field).codec = "_arithmetic", |
4127 | (dccl.field).(arithmetic).model = "model", |
4128 | @@ -82,6 +87,7 @@ |
4129 | { |
4130 | option (dccl.msg).id = 6; |
4131 | option (dccl.msg).max_bytes = 10000; |
4132 | + option (dccl.msg).codec_version = 3; |
4133 | |
4134 | repeated int32 value = 101 [(dccl.field).codec = "_arithmetic", |
4135 | (dccl.field).(arithmetic).model = "model", |
4136 | |
4137 | === modified file 'src/test/dccl_ccl/test.cpp' |
4138 | --- src/test/dccl_ccl/test.cpp 2014-04-22 20:13:39 +0000 |
4139 | +++ src/test/dccl_ccl/test.cpp 2014-08-27 16:27:22 +0000 |
4140 | @@ -48,11 +48,9 @@ |
4141 | { |
4142 | dccl::dlog.connect(dccl::logger::ALL, &std::cerr); |
4143 | |
4144 | - { |
4145 | - dccl::FieldCodecManager::add<dccl::LegacyCCLIdentifierCodec>("ccl_id_codec"); |
4146 | - dccl::Codec codec("ccl_id_codec"); |
4147 | - |
4148 | + { |
4149 | void* dl_handle = dlopen("libdccl_ccl_compat" SHARED_LIBRARY_SUFFIX, RTLD_LAZY); |
4150 | + dccl::Codec codec("dccl.ccl.id"); |
4151 | |
4152 | if(!dl_handle) |
4153 | { |
4154 | |
4155 | === modified file 'src/test/dccl_ccl/test.proto' |
4156 | --- src/test/dccl_ccl/test.proto 2012-10-24 14:10:06 +0000 |
4157 | +++ src/test/dccl_ccl/test.proto 2014-08-27 16:27:22 +0000 |
4158 | @@ -4,6 +4,7 @@ |
4159 | { |
4160 | option (dccl.msg).id = 1; |
4161 | option (dccl.msg).max_bytes = 32; |
4162 | + option (dccl.msg).codec_version = 3; |
4163 | |
4164 | required int32 a = 1 [(dccl.field).min=0, |
4165 | (dccl.field).max=0xFFFF]; |
4166 | |
4167 | === added directory 'src/test/dccl_codec_group' |
4168 | === added file 'src/test/dccl_codec_group/CMakeLists.txt' |
4169 | --- src/test/dccl_codec_group/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
4170 | +++ src/test/dccl_codec_group/CMakeLists.txt 2014-08-27 16:27:22 +0000 |
4171 | @@ -0,0 +1,6 @@ |
4172 | +protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS test.proto) |
4173 | + |
4174 | +add_executable(dccl_test_codec_group test.cpp ${PROTO_SRCS} ${PROTO_HDRS}) |
4175 | +target_link_libraries(dccl_test_codec_group dccl) |
4176 | + |
4177 | +add_test(dccl_test_codec_group ${dccl_BIN_DIR}/dccl_test_codec_group) |
4178 | |
4179 | === added file 'src/test/dccl_codec_group/test.cpp' |
4180 | --- src/test/dccl_codec_group/test.cpp 1970-01-01 00:00:00 +0000 |
4181 | +++ src/test/dccl_codec_group/test.cpp 2014-08-27 16:27:22 +0000 |
4182 | @@ -0,0 +1,104 @@ |
4183 | +// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes) |
4184 | +// Massachusetts Institute of Technology (2007-) |
4185 | +// Woods Hole Oceanographic Institution (2007-) |
4186 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
4187 | +// |
4188 | +// |
4189 | +// This file is part of the Dynamic Compact Control Language Library |
4190 | +// ("DCCL"). |
4191 | +// |
4192 | +// DCCL is free software: you can redistribute them and/or modify |
4193 | +// them under the terms of the GNU Lesser General Public License as published by |
4194 | +// the Free Software Foundation, either version 3 of the License, or |
4195 | +// (at your option) any later version. |
4196 | +// |
4197 | +// DCCL is distributed in the hope that they will be useful, |
4198 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
4199 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4200 | +// GNU Lesser General Public License for more details. |
4201 | +// |
4202 | +// You should have received a copy of the GNU Lesser General Public License |
4203 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
4204 | + |
4205 | + |
4206 | +// tests all protobuf types with _default codecs, repeat and non repeat |
4207 | + |
4208 | +#include <fstream> |
4209 | + |
4210 | +#include <google/protobuf/descriptor.pb.h> |
4211 | + |
4212 | +#include "dccl/codec.h" |
4213 | +#include "dccl/codecs3/field_codec_default.h" |
4214 | + |
4215 | +#include "test.pb.h" |
4216 | +#include "dccl/binary.h" |
4217 | + |
4218 | +template <typename Msg> |
4219 | +void check(double val, bool should_pass); |
4220 | +dccl::Codec codec; |
4221 | +TestMsg msg_in; |
4222 | +TestMsgGroup msg_group_in; |
4223 | + |
4224 | +class TestCodec : public dccl::v3::DefaultNumericFieldCodec<double> |
4225 | +{ |
4226 | + double max() { return 100; } |
4227 | + double min() { return -100; } |
4228 | + double precision() { return 1; } |
4229 | + void validate() { } |
4230 | +}; |
4231 | + |
4232 | + |
4233 | + |
4234 | + |
4235 | +int main(int argc, char* argv[]) |
4236 | +{ |
4237 | +// dccl::dlog.connect(dccl::logger::ALL, &std::cerr); |
4238 | + |
4239 | + dccl::FieldCodecManager::add<TestCodec>("test.grouptest"); |
4240 | + dccl::FieldCodecManager::add<dccl::v3::DefaultMessageCodec, google::protobuf::FieldDescriptor::TYPE_MESSAGE>("test.grouptest"); |
4241 | + |
4242 | + check<TestMsg>(50, true); |
4243 | + check<TestMsg>(-50, false); |
4244 | + check<TestMsgGroup>(50, true); |
4245 | + check<TestMsgGroup>(-50, true); |
4246 | + check<TestMsgVersion>(50, true); |
4247 | + |
4248 | + std::cout << "all tests passed" << std::endl; |
4249 | +} |
4250 | + |
4251 | + |
4252 | +template <typename Msg> |
4253 | +void check(double val, bool should_pass) |
4254 | +{ |
4255 | + Msg msg_in; |
4256 | + int i = 0; |
4257 | + msg_in.set_d(++i + 0.1); |
4258 | + msg_in.add_d_repeat(12.1); |
4259 | + msg_in.add_d_repeat(12.2); |
4260 | + msg_in.add_d_repeat(12.3); |
4261 | + |
4262 | + msg_in.mutable_msg()->set_val(val); |
4263 | + msg_in.mutable_msg()->mutable_msg()->set_val(val); |
4264 | + codec.info(msg_in.GetDescriptor(), &std::cout); |
4265 | + |
4266 | + std::cout << "Message in:\n" << msg_in.DebugString() << std::endl; |
4267 | + |
4268 | + codec.load(msg_in.GetDescriptor()); |
4269 | + |
4270 | + std::cout << "Try encode..." << std::endl; |
4271 | + std::string bytes; |
4272 | + codec.encode(&bytes, msg_in); |
4273 | + std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes) << std::endl; |
4274 | + |
4275 | + std::cout << "Try decode..." << std::endl; |
4276 | + |
4277 | + Msg msg_out; |
4278 | + codec.decode(bytes, &msg_out); |
4279 | + |
4280 | + std::cout << "... got Message out:\n" << msg_out.DebugString() << std::endl; |
4281 | + |
4282 | + if(should_pass) |
4283 | + assert(msg_in.SerializeAsString() == msg_out.SerializeAsString()); |
4284 | + else |
4285 | + assert(msg_in.SerializeAsString() != msg_out.SerializeAsString()); |
4286 | +} |
4287 | |
4288 | === added file 'src/test/dccl_codec_group/test.proto' |
4289 | --- src/test/dccl_codec_group/test.proto 1970-01-01 00:00:00 +0000 |
4290 | +++ src/test/dccl_codec_group/test.proto 2014-08-27 16:27:22 +0000 |
4291 | @@ -0,0 +1,77 @@ |
4292 | +import "dccl/protobuf/option_extensions.proto"; |
4293 | + |
4294 | + |
4295 | +message EmbeddedMsg1 |
4296 | +{ |
4297 | + option (dccl.msg).codec="dccl.default3"; |
4298 | + |
4299 | + optional double val = 1 [(dccl.field).min=0, |
4300 | + (dccl.field).max=100, |
4301 | + (dccl.field).precision=3]; |
4302 | + |
4303 | + |
4304 | + optional EmbeddedMsg2 msg = 2; |
4305 | +} |
4306 | + |
4307 | +message EmbeddedMsg2 |
4308 | +{ |
4309 | + optional double val = 1 [(dccl.field).min=0, |
4310 | + (dccl.field).max=100, |
4311 | + (dccl.field).precision=2]; |
4312 | + |
4313 | +} |
4314 | + |
4315 | +message TestMsg |
4316 | +{ |
4317 | + option (dccl.msg).id = 1; |
4318 | + option (dccl.msg).max_bytes = 32; |
4319 | + option (dccl.msg).codec_version = 3; |
4320 | + |
4321 | + optional double d = 1 [(dccl.field).min=-100, |
4322 | + (dccl.field).max=126, |
4323 | + (dccl.field).precision=1, |
4324 | + (dccl.field).codec="dccl.default3"]; |
4325 | + |
4326 | + |
4327 | + |
4328 | + repeated double d_repeat = 3 [(dccl.field).max_repeat=5, |
4329 | + (dccl.field).codec="test.grouptest"]; |
4330 | + optional EmbeddedMsg1 msg = 2; |
4331 | +} |
4332 | + |
4333 | +message TestMsgGroup |
4334 | +{ |
4335 | + option (dccl.msg).id = 2; |
4336 | + option (dccl.msg).max_bytes = 32; |
4337 | + option (dccl.msg).codec_group = "test.grouptest"; |
4338 | + option (dccl.msg).codec_version = 3; |
4339 | + |
4340 | + optional double d = 1 [(dccl.field).min=-100, |
4341 | + (dccl.field).max=126, |
4342 | + (dccl.field).precision=1, |
4343 | + (dccl.field).codec="dccl.default3"]; |
4344 | + |
4345 | + repeated double d_repeat = 3 [(dccl.field).max_repeat=5]; |
4346 | + optional EmbeddedMsg1 msg = 2; |
4347 | + |
4348 | +} |
4349 | + |
4350 | + |
4351 | +message TestMsgVersion |
4352 | +{ |
4353 | + option (dccl.msg).id = 3; |
4354 | + option (dccl.msg).max_bytes = 32; |
4355 | + option (dccl.msg).codec_version = 2; |
4356 | + |
4357 | + optional double d = 1 [(dccl.field).min=-100, |
4358 | + (dccl.field).max=126, |
4359 | + (dccl.field).precision=2]; |
4360 | + |
4361 | + repeated double d_repeat = 3 [(dccl.field).min=12.0, |
4362 | + (dccl.field).max=13.6, |
4363 | + (dccl.field).precision=1, |
4364 | + (dccl.field).max_repeat=5]; |
4365 | + |
4366 | + optional EmbeddedMsg1 msg = 2; |
4367 | + |
4368 | +} |
4369 | |
4370 | === modified file 'src/test/dccl_custom_id/test.proto' |
4371 | --- src/test/dccl_custom_id/test.proto 2012-10-24 14:10:06 +0000 |
4372 | +++ src/test/dccl_custom_id/test.proto 2014-08-27 16:27:22 +0000 |
4373 | @@ -4,6 +4,7 @@ |
4374 | { |
4375 | option (dccl.msg).id = 1000001; |
4376 | option (dccl.msg).max_bytes = 2; |
4377 | + option (dccl.msg).codec_version = 3; |
4378 | |
4379 | required uint32 user = 1 [(dccl.field).min=0, |
4380 | (dccl.field).max=0x03FF, |
4381 | @@ -14,6 +15,7 @@ |
4382 | { |
4383 | option (dccl.msg).id = 1000002; |
4384 | option (dccl.msg).max_bytes = 2; |
4385 | + option (dccl.msg).codec_version = 3; |
4386 | |
4387 | required uint32 clock_mode = 1 [(dccl.field).min=0, |
4388 | (dccl.field).max=3, |
4389 | @@ -32,6 +34,7 @@ |
4390 | { |
4391 | option (dccl.msg).id = 1000003; |
4392 | option (dccl.msg).max_bytes = 2; |
4393 | + option (dccl.msg).codec_version = 3; |
4394 | |
4395 | required uint32 user = 1 [(dccl.field).min=0, |
4396 | (dccl.field).max=0x03FF, |
4397 | |
4398 | === modified file 'src/test/dccl_custom_message/test.proto' |
4399 | --- src/test/dccl_custom_message/test.proto 2012-10-19 16:41:36 +0000 |
4400 | +++ src/test/dccl_custom_message/test.proto 2014-08-27 16:27:22 +0000 |
4401 | @@ -6,6 +6,7 @@ |
4402 | option (dccl.msg).id = 3; |
4403 | option (dccl.msg).max_bytes = 256; |
4404 | option (dccl.msg).codec = "custom_codec"; |
4405 | + option (dccl.msg).codec_version = 3; |
4406 | |
4407 | optional uint32 a = 1; |
4408 | optional bool b = 2; |
4409 | @@ -16,6 +17,7 @@ |
4410 | { |
4411 | option (dccl.msg).id = 4; |
4412 | option (dccl.msg).max_bytes = 256; |
4413 | + option (dccl.msg).codec_version = 3; |
4414 | |
4415 | optional CustomMsg msg = 1; |
4416 | repeated int32 c = 3 [(dccl.field).max=100, |
4417 | |
4418 | === modified file 'src/test/dccl_default_id/test.proto' |
4419 | --- src/test/dccl_default_id/test.proto 2012-10-19 16:41:36 +0000 |
4420 | +++ src/test/dccl_default_id/test.proto 2014-08-27 16:27:22 +0000 |
4421 | @@ -4,12 +4,14 @@ |
4422 | { |
4423 | option (dccl.msg).id = 2; |
4424 | option (dccl.msg).max_bytes = 1; |
4425 | + option (dccl.msg).codec_version = 3; |
4426 | } |
4427 | |
4428 | message ShortIDMsgWithData |
4429 | { |
4430 | option (dccl.msg).id = 3; |
4431 | option (dccl.msg).max_bytes = 10; |
4432 | + option (dccl.msg).codec_version = 3; |
4433 | |
4434 | optional int32 in_head = 1 [(dccl.field).in_head=true, (dccl.field).min=0, (dccl.field).max=100]; |
4435 | optional int32 in_body = 2 [(dccl.field).in_head=true, (dccl.field).min=0, (dccl.field).max=100]; |
4436 | @@ -17,23 +19,28 @@ |
4437 | |
4438 | message LongIDMsg |
4439 | { |
4440 | - option (dccl.msg).id = 10000; option (dccl.msg).max_bytes = 2; |
4441 | + option (dccl.msg).id = 10000; |
4442 | + option (dccl.msg).max_bytes = 2; |
4443 | + option (dccl.msg).codec_version = 3; |
4444 | } |
4445 | |
4446 | message TooLongIDMsg |
4447 | { |
4448 | option (dccl.msg).id = 32768; |
4449 | option (dccl.msg).max_bytes = 32; |
4450 | + option (dccl.msg).codec_version = 3; |
4451 | } |
4452 | |
4453 | message LongIDEdgeMsg |
4454 | { |
4455 | option (dccl.msg).id = 128; |
4456 | option (dccl.msg).max_bytes = 2; |
4457 | + option (dccl.msg).codec_version = 3; |
4458 | } |
4459 | |
4460 | message ShortIDEdgeMsg |
4461 | { |
4462 | option (dccl.msg).id = 127; |
4463 | option (dccl.msg).max_bytes = 1; |
4464 | + option (dccl.msg).codec_version = 3; |
4465 | } |
4466 | |
4467 | === modified file 'src/test/dccl_header/header.proto' |
4468 | --- src/test/dccl_header/header.proto 2013-08-22 18:58:12 +0000 |
4469 | +++ src/test/dccl_header/header.proto 2014-08-27 16:27:22 +0000 |
4470 | @@ -11,44 +11,35 @@ |
4471 | // microseconds since Unix |
4472 | |
4473 | // second precision (default) |
4474 | - required uint64 time = 10 [(dccl.field).codec="_time", |
4475 | - (dccl.field).in_head=true]; |
4476 | - |
4477 | - optional int64 time_signed = 20 [(dccl.field).codec="_time", |
4478 | - (dccl.field).in_head=true]; |
4479 | - optional double time_double = 21 [(dccl.field).codec="_time", |
4480 | - (dccl.field).in_head=true]; |
4481 | + required uint64 time = 10 [(dccl.field).codec="_time"]; |
4482 | + |
4483 | + optional int64 time_signed = 20 [(dccl.field).codec="_time"]; |
4484 | + optional double time_double = 21 [(dccl.field).codec="_time"]; |
4485 | optional double pasttime_double = 22 [(dccl.field).codec="_time", |
4486 | - (dccl.field).num_days=6, |
4487 | - (dccl.field).in_head=true]; |
4488 | + (dccl.field).num_days=6]; |
4489 | optional double futuretime_double = 23 [(dccl.field).codec="_time", |
4490 | - (dccl.field).num_days=6, |
4491 | - (dccl.field).in_head=true]; |
4492 | + (dccl.field).num_days=6]; |
4493 | |
4494 | // microsecond precision |
4495 | optional int64 time_precision = 24 [(dccl.field).codec="_time", |
4496 | - (dccl.field).in_head=true, |
4497 | (dccl.field).precision=-3]; |
4498 | optional double time_double_precision = 25 [(dccl.field).codec="_time", |
4499 | - (dccl.field).in_head=true, |
4500 | (dccl.field).precision=6]; |
4501 | |
4502 | // |
4503 | // source |
4504 | // |
4505 | required int32 source_platform = 11 [(dccl.field).min = 0, |
4506 | - (dccl.field).max = 31, |
4507 | - (dccl.field).in_head=true]; |
4508 | + (dccl.field).max = 31]; |
4509 | optional string source_app = 12 [(dccl.field).omit=true]; |
4510 | |
4511 | // |
4512 | // destination |
4513 | // |
4514 | enum PublishDestination { PUBLISH_SELF = 1; PUBLISH_OTHER = 2; PUBLISH_ALL = 3; } |
4515 | - optional PublishDestination dest_type = 13 [default = PUBLISH_SELF, (dccl.field).in_head=true]; |
4516 | + optional PublishDestination dest_type = 13 [default = PUBLISH_SELF]; |
4517 | |
4518 | optional int32 dest_platform = 14 [(dccl.field).min = 0, |
4519 | - (dccl.field).max = 31, |
4520 | - (dccl.field).in_head=true]; // required if dest_type == other |
4521 | + (dccl.field).max = 31]; // required if dest_type == other |
4522 | |
4523 | } |
4524 | |
4525 | === modified file 'src/test/dccl_header/test.cpp' |
4526 | --- src/test/dccl_header/test.cpp 2014-04-22 20:13:39 +0000 |
4527 | +++ src/test/dccl_header/test.cpp 2014-08-27 16:27:22 +0000 |
4528 | @@ -24,9 +24,9 @@ |
4529 | // tests proper encoding of standard Goby header |
4530 | |
4531 | #include "dccl/codec.h" |
4532 | -#include "dccl/field_codec_default.h" |
4533 | #include "test.pb.h" |
4534 | |
4535 | +#include <sys/time.h> |
4536 | |
4537 | #include "dccl/binary.h" |
4538 | |
4539 | |
4540 | === modified file 'src/test/dccl_header/test.proto' |
4541 | --- src/test/dccl_header/test.proto 2013-08-22 18:24:42 +0000 |
4542 | +++ src/test/dccl_header/test.proto 2014-08-27 16:27:22 +0000 |
4543 | @@ -5,9 +5,10 @@ |
4544 | { |
4545 | option (dccl.msg).id = 4; |
4546 | option (dccl.msg).max_bytes = 64; |
4547 | + option (dccl.msg).codec_version = 3; |
4548 | |
4549 | required string telegram = 1 [(dccl.field).max_length=10]; |
4550 | - required Header header = 2; |
4551 | + required Header header = 2 [(dccl.field).in_head = true]; |
4552 | |
4553 | optional int32 const_int =3 [(dccl.field).static_value="3", (dccl.field).codec="_static"]; |
4554 | } |
4555 | |
4556 | === added directory 'src/test/dccl_message_fix' |
4557 | === added file 'src/test/dccl_message_fix/CMakeLists.txt' |
4558 | --- src/test/dccl_message_fix/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
4559 | +++ src/test/dccl_message_fix/CMakeLists.txt 2014-08-27 16:27:22 +0000 |
4560 | @@ -0,0 +1,6 @@ |
4561 | +protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS test.proto) |
4562 | + |
4563 | +add_executable(dccl_test_message_fix test.cpp ${PROTO_SRCS} ${PROTO_HDRS}) |
4564 | +target_link_libraries(dccl_test_message_fix dccl) |
4565 | + |
4566 | +add_test(dccl_test_message_fix ${dccl_BIN_DIR}/dccl_test_message_fix) |
4567 | |
4568 | === added file 'src/test/dccl_message_fix/test.cpp' |
4569 | --- src/test/dccl_message_fix/test.cpp 1970-01-01 00:00:00 +0000 |
4570 | +++ src/test/dccl_message_fix/test.cpp 2014-08-27 16:27:22 +0000 |
4571 | @@ -0,0 +1,110 @@ |
4572 | +// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes) |
4573 | +// Massachusetts Institute of Technology (2007-) |
4574 | +// Woods Hole Oceanographic Institution (2007-) |
4575 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
4576 | +// |
4577 | +// |
4578 | +// This file is part of the Dynamic Compact Control Language Library |
4579 | +// ("DCCL"). |
4580 | +// |
4581 | +// DCCL is free software: you can redistribute them and/or modify |
4582 | +// them under the terms of the GNU Lesser General Public License as published by |
4583 | +// the Free Software Foundation, either version 3 of the License, or |
4584 | +// (at your option) any later version. |
4585 | +// |
4586 | +// DCCL is distributed in the hope that they will be useful, |
4587 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
4588 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4589 | +// GNU Lesser General Public License for more details. |
4590 | +// |
4591 | +// You should have received a copy of the GNU Lesser General Public License |
4592 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
4593 | + |
4594 | + |
4595 | +// tests all protobuf types with _default codecs, repeat and non repeat |
4596 | + |
4597 | +#include <fstream> |
4598 | + |
4599 | +#include <google/protobuf/descriptor.pb.h> |
4600 | + |
4601 | +#include "dccl/codec.h" |
4602 | +#include "dccl/codecs2/field_codec_default.h" |
4603 | + |
4604 | +#include "test.pb.h" |
4605 | +#include "dccl/binary.h" |
4606 | + |
4607 | + |
4608 | +int main(int argc, char* argv[]) |
4609 | +{ |
4610 | +// dccl::dlog.connect(dccl::logger::ALL, &std::cerr); |
4611 | + // check the empty messages |
4612 | + dccl::Codec codec; |
4613 | + |
4614 | + codec.info<TestMsg>(&std::cout); |
4615 | + codec.load<TestMsg>(); |
4616 | + |
4617 | + { |
4618 | + TestMsg msg_in, msg_out; |
4619 | + int i = 0; |
4620 | + |
4621 | + |
4622 | + std::cout << "Message in:\n" << msg_in.DebugString() << std::endl; |
4623 | + |
4624 | + codec.load(msg_in.GetDescriptor()); |
4625 | + |
4626 | + std::cout << "Try encode..." << std::endl; |
4627 | + std::string bytes; |
4628 | + codec.encode(&bytes, msg_in); |
4629 | + std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes) << std::endl; |
4630 | + |
4631 | + std::cout << "Try decode..." << std::endl; |
4632 | + |
4633 | + codec.decode(bytes, &msg_out); |
4634 | + |
4635 | + std::cout << "... got Message out:\n" << msg_out.DebugString() << std::endl; |
4636 | + |
4637 | + assert(!msg_out.has_msg1()); |
4638 | + assert(!msg_out.msg1_repeat_size()); |
4639 | + assert(!msg_out.has_msg2()); |
4640 | + assert(!msg_out.msg2_repeat_size()); |
4641 | + assert(msg_in.SerializeAsString() == msg_out.SerializeAsString()); |
4642 | + } |
4643 | + |
4644 | + |
4645 | + // check partially full messages |
4646 | + { |
4647 | + TestMsg msg_in, msg_out; |
4648 | + |
4649 | + msg_in.mutable_msg1()->set_val(0.1); |
4650 | + msg_in.add_msg1_repeat()->set_val(0.11); |
4651 | + msg_in.add_msg1_repeat()->set_val(0.12); |
4652 | + msg_in.add_msg1_repeat()->set_val(0.13); |
4653 | + msg_in.mutable_msg2()->set_val(0.2); |
4654 | + msg_in.add_msg2_repeat()->set_val(0.21); |
4655 | + msg_in.add_msg2_repeat()->set_val(0.22); |
4656 | + msg_in.add_msg2_repeat()->set_val(0.23); |
4657 | + |
4658 | + std::cout << "Message in:\n" << msg_in.DebugString() << std::endl; |
4659 | + |
4660 | + std::cout << "Try encode..." << std::endl; |
4661 | + std::string bytes; |
4662 | + codec.encode(&bytes, msg_in); |
4663 | + std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes) << std::endl; |
4664 | + |
4665 | + std::cout << "Try decode..." << std::endl; |
4666 | + |
4667 | + codec.decode(bytes, &msg_out); |
4668 | + |
4669 | + std::cout << "... got Message out:\n" << msg_out.DebugString() << std::endl; |
4670 | + |
4671 | + assert(msg_out.has_msg1()); |
4672 | + assert(msg_out.msg1_repeat_size() == 3); |
4673 | + assert(msg_out.has_msg2()); |
4674 | + assert(msg_out.msg2_repeat_size() == 3); |
4675 | + assert(msg_in.SerializeAsString() == msg_out.SerializeAsString()); |
4676 | + } |
4677 | + |
4678 | + |
4679 | + std::cout << "all tests passed" << std::endl; |
4680 | +} |
4681 | + |
4682 | |
4683 | === added file 'src/test/dccl_message_fix/test.proto' |
4684 | --- src/test/dccl_message_fix/test.proto 1970-01-01 00:00:00 +0000 |
4685 | +++ src/test/dccl_message_fix/test.proto 2014-08-27 16:27:22 +0000 |
4686 | @@ -0,0 +1,31 @@ |
4687 | +import "dccl/protobuf/option_extensions.proto"; |
4688 | + |
4689 | +message EmbeddedMsgOptional |
4690 | +{ |
4691 | + optional double val = 1 [(dccl.field).min=0, |
4692 | + (dccl.field).max=126, |
4693 | + (dccl.field).precision=3]; |
4694 | +} |
4695 | + |
4696 | +message EmbeddedMsgRequired |
4697 | +{ |
4698 | + required double val = 1 [(dccl.field).min=0, |
4699 | + (dccl.field).max=126, |
4700 | + (dccl.field).precision=3]; |
4701 | +} |
4702 | + |
4703 | +message TestMsg |
4704 | +{ |
4705 | + option (dccl.msg).id = 1; |
4706 | + option (dccl.msg).max_bytes = 32; |
4707 | + option (dccl.msg).codec_version = 3; |
4708 | + |
4709 | + optional EmbeddedMsgOptional msg1 = 1; |
4710 | + repeated EmbeddedMsgOptional msg1_repeat = 3 [(dccl.field).max_repeat=5]; |
4711 | + |
4712 | + // in DCCL v2, these will always be set upon receipt since it has required children. This test validates the fix in v3 |
4713 | + optional EmbeddedMsgRequired msg2 = 2; |
4714 | + repeated EmbeddedMsgRequired msg2_repeat = 4 [(dccl.field).max_repeat=5]; |
4715 | + |
4716 | +} |
4717 | + |
4718 | |
4719 | === modified file 'src/test/dccl_numeric_bounds/test.proto' |
4720 | --- src/test/dccl_numeric_bounds/test.proto 2014-03-26 17:27:11 +0000 |
4721 | +++ src/test/dccl_numeric_bounds/test.proto 2014-08-27 16:27:22 +0000 |
4722 | @@ -4,6 +4,7 @@ |
4723 | { |
4724 | option (dccl.msg).id = 10; |
4725 | option (dccl.msg).max_bytes = 32; |
4726 | + option (dccl.msg).codec_version = 3; |
4727 | |
4728 | optional double a = 1 [(dccl.field).max = 180, |
4729 | (dccl.field).min = -180, |
4730 | @@ -30,6 +31,7 @@ |
4731 | { |
4732 | option (dccl.msg).id = 10; |
4733 | option (dccl.msg).max_bytes = 32; |
4734 | + option (dccl.msg).codec_version = 3; |
4735 | |
4736 | optional double a = 1 [(dccl.field).min = -20, |
4737 | (dccl.field).max = 20, |
4738 | @@ -45,6 +47,7 @@ |
4739 | { |
4740 | option (dccl.msg).id = 11; |
4741 | option (dccl.msg).max_bytes = 32; |
4742 | + option (dccl.msg).codec_version = 3; |
4743 | |
4744 | optional double a = 1 [(dccl.field).max = 180, |
4745 | (dccl.field).min = -180, |
4746 | |
4747 | === modified file 'src/test/dccl_repeated/test.cpp' |
4748 | --- src/test/dccl_repeated/test.cpp 2014-04-22 20:13:39 +0000 |
4749 | +++ src/test/dccl_repeated/test.cpp 2014-08-27 16:27:22 +0000 |
4750 | @@ -25,7 +25,6 @@ |
4751 | |
4752 | |
4753 | #include "dccl/codec.h" |
4754 | -#include "dccl/field_codec_default.h" |
4755 | #include "dccl/binary.h" |
4756 | |
4757 | #include "test.pb.h" |
4758 | |
4759 | === modified file 'src/test/dccl_repeated/test.proto' |
4760 | --- src/test/dccl_repeated/test.proto 2012-10-23 00:46:12 +0000 |
4761 | +++ src/test/dccl_repeated/test.proto 2014-08-27 16:27:22 +0000 |
4762 | @@ -5,6 +5,7 @@ |
4763 | { |
4764 | option (dccl.msg).id = 4; |
4765 | option (dccl.msg).max_bytes = 32; |
4766 | + option (dccl.msg).codec_version = 3; |
4767 | |
4768 | optional int32 int32_val = 1 [(dccl.field).min=0, (dccl.field).max=20]; |
4769 | } |
4770 | @@ -13,6 +14,7 @@ |
4771 | { |
4772 | option (dccl.msg).id = 5; |
4773 | option (dccl.msg).max_bytes = 32; |
4774 | + option (dccl.msg).codec_version = 3; |
4775 | |
4776 | optional bool bool_val = 1; |
4777 | } |
4778 | @@ -21,6 +23,7 @@ |
4779 | { |
4780 | option (dccl.msg).id = 6; |
4781 | option (dccl.msg).max_bytes = 32; |
4782 | + option (dccl.msg).codec_version = 3; |
4783 | |
4784 | optional string string_val = 1 [(dccl.field).max_length=10]; |
4785 | } |
4786 | |
4787 | === modified file 'src/test/dccl_required_optional/test.proto' |
4788 | --- src/test/dccl_required_optional/test.proto 2012-10-19 16:41:36 +0000 |
4789 | +++ src/test/dccl_required_optional/test.proto 2014-08-27 16:27:22 +0000 |
4790 | @@ -4,6 +4,7 @@ |
4791 | { |
4792 | option (dccl.msg).id = 10; |
4793 | option (dccl.msg).max_bytes = 32; |
4794 | + option (dccl.msg).codec_version = 3; |
4795 | |
4796 | required bytes req_bytes = 1 [(dccl.field).max_length=8]; |
4797 | optional bytes opt_bytes = 2 [(dccl.field).max_length=8]; |
4798 | |
4799 | === modified file 'src/test/dccl_static_methods/test.proto' |
4800 | --- src/test/dccl_static_methods/test.proto 2012-10-23 00:46:12 +0000 |
4801 | +++ src/test/dccl_static_methods/test.proto 2014-08-27 16:27:22 +0000 |
4802 | @@ -5,6 +5,7 @@ |
4803 | { |
4804 | option (dccl.msg).id = 4; |
4805 | option (dccl.msg).max_bytes = 32; |
4806 | + option (dccl.msg).codec_version = 3; |
4807 | |
4808 | optional int32 int32_val = 1 [(dccl.field).min=0, (dccl.field).max=20]; |
4809 | } |
4810 | @@ -13,6 +14,7 @@ |
4811 | { |
4812 | option (dccl.msg).id = 5; |
4813 | option (dccl.msg).max_bytes = 32; |
4814 | + option (dccl.msg).codec_version = 3; |
4815 | |
4816 | optional bool bool_val = 1; |
4817 | } |
4818 | @@ -21,6 +23,7 @@ |
4819 | { |
4820 | option (dccl.msg).id = 6; |
4821 | option (dccl.msg).max_bytes = 32; |
4822 | + option (dccl.msg).codec_version = 3; |
4823 | |
4824 | optional string string_val = 1 [(dccl.field).max_length=10]; |
4825 | } |
4826 | |
4827 | === added directory 'src/test/dccl_v2_all_fields' |
4828 | === added file 'src/test/dccl_v2_all_fields/CMakeLists.txt' |
4829 | --- src/test/dccl_v2_all_fields/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
4830 | +++ src/test/dccl_v2_all_fields/CMakeLists.txt 2014-08-27 16:27:22 +0000 |
4831 | @@ -0,0 +1,6 @@ |
4832 | +protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS test.proto) |
4833 | + |
4834 | +add_executable(dccl_test_v2_all_fields test.cpp ${PROTO_SRCS} ${PROTO_HDRS}) |
4835 | +target_link_libraries(dccl_test_v2_all_fields dccl) |
4836 | + |
4837 | +add_test(dccl_test_v2_all_fields ${dccl_BIN_DIR}/dccl_test_v2_all_fields) |
4838 | |
4839 | === added file 'src/test/dccl_v2_all_fields/test.cpp' |
4840 | --- src/test/dccl_v2_all_fields/test.cpp 1970-01-01 00:00:00 +0000 |
4841 | +++ src/test/dccl_v2_all_fields/test.cpp 2014-08-27 16:27:22 +0000 |
4842 | @@ -0,0 +1,175 @@ |
4843 | +// Copyright 2009-2013 Toby Schneider (https://launchpad.net/~tes) |
4844 | +// Massachusetts Institute of Technology (2007-) |
4845 | +// Woods Hole Oceanographic Institution (2007-) |
4846 | +// DCCL Developers Team (https://launchpad.net/~dccl-dev) |
4847 | +// |
4848 | +// |
4849 | +// This file is part of the Dynamic Compact Control Language Library |
4850 | +// ("DCCL"). |
4851 | +// |
4852 | +// DCCL is free software: you can redistribute them and/or modify |
4853 | +// them under the terms of the GNU Lesser General Public License as published by |
4854 | +// the Free Software Foundation, either version 3 of the License, or |
4855 | +// (at your option) any later version. |
4856 | +// |
4857 | +// DCCL is distributed in the hope that they will be useful, |
4858 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
4859 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4860 | +// GNU Lesser General Public License for more details. |
4861 | +// |
4862 | +// You should have received a copy of the GNU Lesser General Public License |
4863 | +// along with DCCL. If not, see <http://www.gnu.org/licenses/>. |
4864 | + |
4865 | + |
4866 | +// tests all protobuf types with _default codecs, repeat and non repeat |
4867 | + |
4868 | +#include <fstream> |
4869 | + |
4870 | +#include <google/protobuf/descriptor.pb.h> |
4871 | + |
4872 | +#include "dccl/codec.h" |
4873 | +#include "test.pb.h" |
4874 | +#include "dccl/binary.h" |
4875 | + |
4876 | +void decode_check(const std::string& encoded); |
4877 | +dccl::Codec codec; |
4878 | +TestMsg msg_in; |
4879 | + |
4880 | +int main(int argc, char* argv[]) |
4881 | +{ |
4882 | + dccl::dlog.connect(dccl::logger::ALL, &std::cerr); |
4883 | + |
4884 | + int i = 0; |
4885 | + msg_in.set_double_default_optional(++i + 0.1); |
4886 | + msg_in.set_float_default_optional(++i + 0.2); |
4887 | + |
4888 | + msg_in.set_int32_default_optional(++i); |
4889 | + msg_in.set_int64_default_optional(-++i); |
4890 | + msg_in.set_uint32_default_optional(++i); |
4891 | + msg_in.set_uint64_default_optional(++i); |
4892 | + msg_in.set_sint32_default_optional(-++i); |
4893 | + msg_in.set_sint64_default_optional(++i); |
4894 | + msg_in.set_fixed32_default_optional(++i); |
4895 | + msg_in.set_fixed64_default_optional(++i); |
4896 | + msg_in.set_sfixed32_default_optional(++i); |
4897 | + msg_in.set_sfixed64_default_optional(-++i); |
4898 | + |
4899 | + msg_in.set_bool_default_optional(true); |
4900 | + |
4901 | + msg_in.set_string_default_optional("abc123"); |
4902 | + msg_in.set_bytes_default_optional(dccl::hex_decode("00112233aabbcc1234")); |
4903 | + |
4904 | + msg_in.set_enum_default_optional(ENUM_C); |
4905 | + msg_in.mutable_msg_default_optional()->set_val(++i + 0.3); |
4906 | + msg_in.mutable_msg_default_optional()->mutable_msg()->set_val(++i); |
4907 | + |
4908 | + msg_in.set_double_default_required(++i + 0.1); |
4909 | + msg_in.set_float_default_required(++i + 0.2); |
4910 | + |
4911 | + msg_in.set_int32_default_required(++i); |
4912 | + msg_in.set_int64_default_required(-++i); |
4913 | + msg_in.set_uint32_default_required(++i); |
4914 | + msg_in.set_uint64_default_required(++i); |
4915 | + msg_in.set_sint32_default_required(-++i); |
4916 | + msg_in.set_sint64_default_required(++i); |
4917 | + msg_in.set_fixed32_default_required(++i); |
4918 | + msg_in.set_fixed64_default_required(++i); |
4919 | + msg_in.set_sfixed32_default_required(++i); |
4920 | + msg_in.set_sfixed64_default_required(-++i); |
4921 | + |
4922 | + msg_in.set_bool_default_required(true); |
4923 | + |
4924 | + msg_in.set_string_default_required("abc123"); |
4925 | + msg_in.set_bytes_default_required(dccl::hex_decode("00112233aabbcc1234")); |
4926 | + |
4927 | + msg_in.set_enum_default_required(ENUM_C); |
4928 | + msg_in.mutable_msg_default_required()->set_val(++i + 0.3); |
4929 | + msg_in.mutable_msg_default_required()->mutable_msg()->set_val(++i); |
4930 | + |
4931 | + |
4932 | + for(int j = 0; j < 2; ++j) |
4933 | + { |
4934 | + msg_in.add_double_default_repeat(++i + 0.1); |
4935 | + msg_in.add_float_default_repeat(++i + 0.2); |
4936 | + |
4937 | + msg_in.add_int32_default_repeat(++i); |
4938 | + msg_in.add_int64_default_repeat(-++i); |
4939 | + msg_in.add_uint32_default_repeat(++i); |
4940 | + msg_in.add_uint64_default_repeat(++i); |
4941 | + msg_in.add_sint32_default_repeat(-++i); |
4942 | + msg_in.add_sint64_default_repeat(++i); |
4943 | + msg_in.add_fixed32_default_repeat(++i); |
4944 | + msg_in.add_fixed64_default_repeat(++i); |
4945 | + msg_in.add_sfixed32_default_repeat(++i); |
4946 | + msg_in.add_sfixed64_default_repeat(-++i); |
4947 | + |
4948 | + msg_in.add_bool_default_repeat(true); |
4949 | + |
4950 | + msg_in.add_string_default_repeat("abc123"); |
4951 | + |
4952 | + if(j) |
4953 | + msg_in.add_bytes_default_repeat(dccl::hex_decode("00aabbcc")); |
4954 | + else |
4955 | + msg_in.add_bytes_default_repeat(dccl::hex_decode("ffeedd12")); |
4956 | + |
4957 | + msg_in.add_enum_default_repeat(static_cast<Enum1>((++i % 3) + 1)); |
4958 | + EmbeddedMsg1* em_msg = msg_in.add_msg_default_repeat(); |
4959 | + em_msg->set_val(++i + 0.3); |
4960 | + em_msg->mutable_msg()->set_val(++i); |
4961 | + } |
4962 | + |
4963 | + codec.info(msg_in.GetDescriptor()); |
4964 | + |
4965 | + std::ofstream fout("/tmp/testmessage.pb"); |
4966 | + msg_in.SerializeToOstream(&fout); |
4967 | + |
4968 | + |
4969 | + std::cout << "Message in:\n" << msg_in.DebugString() << std::endl; |
4970 | + |
4971 | + codec.load(msg_in.GetDescriptor()); |
4972 | + |
4973 | + std::cout << "Try encode..." << std::endl; |
4974 | + std::string bytes; |
4975 | + codec.encode(&bytes, msg_in); |
4976 | + std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes) << std::endl; |
4977 | + |
4978 | + std::cout << "Try decode..." << std::endl; |
4979 | + decode_check(bytes); |
4980 | + |
4981 | + // make sure DCCL defaults stay wire compatible |
4982 | + decode_check(dccl::hex_decode("047f277b9628060000b95660c0b0188000d8c0132858800008000dc2c4c6626466024488cca8ee324bd05c3f23af0000ad9112a09509788013e0820b18e0005ed0204c6c2c4666062042644675975982c65235f10a00ad718a5801000000905f27121600000000a0170050640300309201001a0b00007d320a0000a61a0070b20100a81b00d09c6f0000a0401026361643102636160300f0dfbd5b2280ea2e330f3da59a2100aabfa55a000000000000000000000000")); |
4983 | + |
4984 | + // run a bunch of tests with random strings |
4985 | + std::string random = bytes; |
4986 | + for(unsigned i = 0; i < 10; ++i) |
4987 | + { |
4988 | + random[(rand() % (bytes.size()-1)+1)] = rand() % 256; |
4989 | + std::cout << "Using junk bytes: " << dccl::hex_encode(random) << std::endl; |
4990 | + |
4991 | + try |
4992 | + { |
4993 | + TestMsg msg_out; |
4994 | + codec.decode(random, &msg_out); |
4995 | + } |
4996 | + catch(dccl::Exception&) |
4997 | + { |
4998 | + } |
4999 | + } |
5000 | + |
Per our discussion yesterday, this seems like a reasonable approach. We discussed a few ideas that may or may not make it into the final:
1. Add a deprecation warning for people who are implicitly relying on DCCL2 behavior.
2. Allow codec groups to fall back on the standard codecs by default, so a Bluefin codec library could consist of the standard DCCL3 Codecs... "plus X".
3. Change codec group to codec library (I don't care)
4. More documentation
None of these are major or blockers.