Branch data Line data Source code
1 : : /*
2 : : ===============================================================================
3 : :
4 : : FILE: formats.hpp
5 : :
6 : : CONTENTS:
7 : : Format support
8 : :
9 : : PROGRAMMERS:
10 : :
11 : : martin.isenburg@rapidlasso.com - http://rapidlasso.com
12 : : uday.karan@gmail.com - Hobu, Inc.
13 : :
14 : : COPYRIGHT:
15 : :
16 : : (c) 2007-2014, martin isenburg, rapidlasso - tools to catch reality
17 : : (c) 2014, Uday Verma, Hobu, Inc.
18 : :
19 : : This is free software; you can redistribute and/or modify it under the
20 : : terms of the GNU Lesser General Licence as published by the Free Software
21 : : Foundation. See the COPYING file for more information.
22 : :
23 : : This software is distributed WITHOUT ANY WARRANTY and without even the
24 : : implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25 : :
26 : : CHANGE HISTORY:
27 : :
28 : : ===============================================================================
29 : : */
30 : : #ifndef __formats_hpp__
31 : : #define __formats_hpp__
32 : :
33 : : #include <cstdint>
34 : : #include <iostream>
35 : : #include "compressor.hpp"
36 : : #include "decompressor.hpp"
37 : :
38 : : namespace laszip {
39 : : namespace formats {
40 : : template<typename T>
41 : : struct packers {
42 : : static_assert(sizeof(T) == 0,
43 : : "Only specialized instances of packers should be used");
44 : : };
45 : :
46 : : template<>
47 : : struct packers<uint32_t> {
48 : 0 : static unsigned int unpack(const char *in) {
49 : 0 : uint32_t b1 = in[0],
50 : 0 : b2 = in[1],
51 : 0 : b3 = in[2],
52 : 0 : b4 = in[3];
53 : :
54 : 0 : return (b4 << 24) |
55 : 0 : ((b3 & 0xFF) << 16) |
56 : 0 : ((b2 & 0xFF) << 8) |
57 : 0 : (b1 & 0xFF);
58 : : }
59 : :
60 : 0 : static void pack(uint32_t v, char *out) {
61 : 0 : out[3] = (v >> 24) & 0xFF;
62 : 0 : out[2] = (v >> 16) & 0xFF;
63 : 0 : out[1] = (v >> 8) & 0xFF;
64 : 0 : out[0] = v & 0xFF;
65 : 0 : }
66 : : };
67 : :
68 : : template<>
69 : : struct packers<uint16_t> {
70 : 0 : static unsigned short unpack(const char *in) {
71 : 0 : uint16_t b1 = in[0],
72 : 0 : b2 = in[1];
73 : :
74 : 0 : return (((b2 & 0xFF) << 8) | (b1 & 0xFF));
75 : : }
76 : :
77 : 0 : static void pack(uint16_t v, char *out) {
78 : 0 : out[1] = (v >> 8) & 0xFF;
79 : 0 : out[0] = v & 0xFF;
80 : 0 : }
81 : : };
82 : :
83 : : template<>
84 : : struct packers<uint8_t> {
85 : 0 : static unsigned char unpack(const char *in) {
86 : 0 : return static_cast<uint8_t>(in[0]);
87 : : }
88 : :
89 : 0 : static void pack(uint8_t c, char *out) {
90 : 0 : out[0] = static_cast<char>(c);
91 : 0 : }
92 : : };
93 : :
94 : : template<>
95 : : struct packers<int32_t> {
96 : 0 : static int unpack(const char *in) {
97 : 0 : return static_cast<int32_t>(packers<uint32_t>::unpack(in));
98 : : }
99 : :
100 : 0 : static void pack(int32_t t, char *out) {
101 : 0 : packers<uint32_t>::pack(static_cast<uint32_t>(t), out);
102 : 0 : }
103 : : };
104 : :
105 : : template<>
106 : : struct packers<int16_t> {
107 : : static short unpack(const char *in) {
108 : : return static_cast<int16_t>(packers<uint16_t>::unpack(in));
109 : : }
110 : :
111 : : static void pack(int16_t t, char *out) {
112 : : packers<uint16_t>::pack(static_cast<uint16_t>(t), out);
113 : : }
114 : : };
115 : :
116 : : template<>
117 : : struct packers<int8_t> {
118 : : static int8_t unpack(const char *in) {
119 : : return in[0];
120 : : }
121 : :
122 : : static void pack(int8_t t, char *out) {
123 : : out[0] = t;
124 : : }
125 : : };
126 : :
127 : : // Char is neither signed char nor unsigned char.
128 : : template<>
129 : : struct packers<char> {
130 : 0 : static char unpack(const char *in) {
131 : 0 : return in[0];
132 : : }
133 : :
134 : 0 : static void pack(char t, char *out) {
135 : 0 : out[0] = t;
136 : 0 : }
137 : : };
138 : :
139 : : /** A simple strategy which returns simple diffs */
140 : : template<typename T>
141 : : struct standard_diff_method {
142 : : standard_diff_method<T>()
143 : : : have_value_(false) {}
144 : :
145 : : inline void push(const T& v) {
146 : : if (!have_value_)
147 : : have_value_ = true;
148 : :
149 : : value = v;
150 : : }
151 : :
152 : : inline bool have_value() const {
153 : : return have_value_;
154 : : }
155 : :
156 : : T value;
157 : : bool have_value_;
158 : : };
159 : :
160 : 0 : struct base_field {
161 : : typedef std::shared_ptr<base_field> ptr;
162 : :
163 : 0 : virtual ~base_field() {
164 : : // hello 1996
165 : 0 : }
166 : :
167 : 0 : virtual const char *compressRaw(const char *buf)
168 : 0 : { return buf; }
169 : 0 : virtual char *decompressRaw(char *buf)
170 : 0 : { return buf; }
171 : : };
172 : :
173 : : template<typename T, typename TDiffMethod = standard_diff_method<T> >
174 : : struct field {
175 : : static_assert(std::is_integral<T>::value,
176 : : "Default implementation for field only handles integral types");
177 : :
178 : : typedef T type;
179 : :
180 : : field() :
181 : : compressor_(sizeof(T) * 8),
182 : : decompressor_(sizeof(T) * 8),
183 : : compressor_inited_(false),
184 : : decompressor_inited_(false) { }
185 : :
186 : : template<
187 : : typename TEncoder
188 : : >
189 : : inline const char *compressWith(TEncoder& encoder,
190 : : const char *buf)
191 : : {
192 : : T this_val = packers<type>::unpack(buf);
193 : : if (!compressor_inited_)
194 : : compressor_.init();
195 : :
196 : : // Let the differ decide what values we're going to push
197 : : //
198 : : if (differ_.have_value()) {
199 : : compressor_.compress(encoder, differ_.value, this_val, 0);
200 : : }
201 : : else {
202 : : // differ is not ready for us to start encoding values
203 : : // for us, so we need to write raw into
204 : : // the outputstream
205 : : //
206 : : encoder.getOutStream().putBytes((const unsigned char*)buf,
207 : : sizeof(T));
208 : : }
209 : : differ_.push(this_val);
210 : : return buf + sizeof(T);
211 : : }
212 : :
213 : : template<
214 : : typename TDecoder
215 : : >
216 : : inline char *decompressWith(TDecoder& decoder, char *buffer)
217 : : {
218 : : if (!decompressor_inited_)
219 : : decompressor_.init();
220 : :
221 : : T r;
222 : : if (differ_.have_value()) {
223 : : r = static_cast<T>(decompressor_.decompress(decoder, differ_.value, 0));
224 : : packers<T>::pack(r, buffer);
225 : : }
226 : : else {
227 : : // this is probably the first time we're reading stuff, read the record as is
228 : : decoder.getInStream().getBytes((unsigned char*)buffer, sizeof(T));
229 : :
230 : : r = packers<T>::unpack(buffer);
231 : : }
232 : : buffer += sizeof(T);
233 : :
234 : : differ_.push(r);
235 : : return buffer;
236 : : }
237 : :
238 : : laszip::compressors::integer compressor_;
239 : : laszip::decompressors::integer decompressor_;
240 : :
241 : : bool compressor_inited_, decompressor_inited_;
242 : :
243 : : TDiffMethod differ_;
244 : : };
245 : :
246 : : template<typename... TS>
247 : : struct record_compressor;
248 : :
249 : : template<typename... TS>
250 : : struct record_decompressor;
251 : :
252 : : template<>
253 : : struct record_compressor<> {
254 : : record_compressor() {}
255 : : template<
256 : : typename T
257 : : >
258 : : inline const char *compressWith(T&, const char *buf)
259 : : { return buf; }
260 : : };
261 : :
262 : : template<typename T, typename... TS>
263 : : struct record_compressor<T, TS...> {
264 : : record_compressor() {}
265 : :
266 : : template<
267 : : typename TEncoder
268 : : >
269 : : inline const char *compressWith(TEncoder& encoder,
270 : : const char *buffer)
271 : : {
272 : : buffer = field_.compressWith(encoder, buffer);
273 : :
274 : : // Move on to the next field
275 : : return next_.compressWith(encoder, buffer);
276 : : }
277 : :
278 : : // The field that we handle
279 : : T field_;
280 : :
281 : : // Our default strategy right now is to just encode diffs,
282 : : // but we would employ more advanced techniques soon
283 : : record_compressor<TS...> next_;
284 : : };
285 : :
286 : : template<>
287 : : struct record_decompressor<> {
288 : 0 : record_decompressor() : firstDecompress(true) {}
289 : : template<
290 : : typename TDecoder
291 : : >
292 : 0 : inline char *decompressWith(TDecoder& decoder, char *buf) {
293 : 0 : if (firstDecompress) {
294 : 0 : decoder.readInitBytes();
295 : 0 : firstDecompress = false;
296 : 0 : }
297 : 0 : return buf;
298 : : }
299 : :
300 : : bool firstDecompress;
301 : : };
302 : :
303 : : template<typename T, typename... TS>
304 : 0 : struct record_decompressor<T, TS...> {
305 : 0 : record_decompressor() {}
306 : :
307 : : template<
308 : : typename TDecoder
309 : : >
310 : 0 : inline char *decompressWith(TDecoder& decoder, char *buf) {
311 : 0 : buf = field_.decompressWith(decoder, buf);
312 : :
313 : : // Move on to the next field
314 : 0 : return next_.decompressWith(decoder, buf);
315 : : }
316 : :
317 : : // The field that we handle
318 : : T field_;
319 : :
320 : : // Our default strategy right now is to just encode diffs, but we would employ more advanced techniques soon
321 : : record_decompressor<TS...> next_;
322 : : };
323 : :
324 : : struct dynamic_compressor {
325 : : typedef std::shared_ptr<dynamic_compressor> ptr;
326 : :
327 : : virtual const char *compress(const char *in) = 0;
328 : : virtual ~dynamic_compressor() {}
329 : : };
330 : :
331 : 0 : struct dynamic_decompressor {
332 : : typedef std::shared_ptr<dynamic_decompressor> ptr;
333 : :
334 : : virtual char *decompress(char *in) = 0;
335 : 0 : virtual ~dynamic_decompressor() {}
336 : : };
337 : :
338 : : template<
339 : : typename TEncoder,
340 : : typename TRecordCompressor
341 : : >
342 : : struct dynamic_compressor1 : public dynamic_compressor {
343 : : dynamic_compressor1(TEncoder& enc, TRecordCompressor* compressor) :
344 : : enc_(enc), compressor_(compressor) {}
345 : :
346 : : virtual const char *compress(const char *in) {
347 : : return compressor_->compressWith(enc_, in);
348 : : }
349 : :
350 : : dynamic_compressor1(const dynamic_compressor1<TEncoder , TRecordCompressor>&) = delete;
351 : : dynamic_compressor1<TEncoder, TRecordCompressor>& operator=(dynamic_compressor1<TEncoder, TRecordCompressor>&) = delete;
352 : :
353 : : TEncoder& enc_;
354 : : std::unique_ptr<TRecordCompressor> compressor_;
355 : : };
356 : :
357 : : template<
358 : : typename TEncoder,
359 : : typename TRecordCompressor
360 : : >
361 : : static dynamic_compressor::ptr make_dynamic_compressor(TEncoder& encoder, TRecordCompressor* compressor) {
362 : : return dynamic_compressor::ptr(
363 : : new dynamic_compressor1<TEncoder, TRecordCompressor>(encoder, compressor));
364 : : }
365 : :
366 : : template<
367 : : typename TDecoder,
368 : : typename TRecordDecompressor
369 : : >
370 : 0 : struct dynamic_decompressor1 : public dynamic_decompressor {
371 : 0 : dynamic_decompressor1(TDecoder& dec, TRecordDecompressor* decompressor) :
372 : 0 : dec_(dec), decompressor_(decompressor) {}
373 : :
374 : 0 : virtual char *decompress(char *in)
375 : : {
376 : 0 : return decompressor_->decompressWith(dec_, in);
377 : : }
378 : :
379 : : dynamic_decompressor1(const dynamic_decompressor1<TDecoder, TRecordDecompressor>&) = delete;
380 : : dynamic_decompressor1<TDecoder, TRecordDecompressor>& operator=(dynamic_decompressor1<TDecoder, TRecordDecompressor>&) = delete;
381 : :
382 : : TDecoder& dec_;
383 : : std::unique_ptr<TRecordDecompressor> decompressor_;
384 : : };
385 : :
386 : : template<
387 : : typename TDecoder,
388 : : typename TRecordDecompressor
389 : : >
390 : 0 : static dynamic_decompressor::ptr make_dynamic_decompressor(TDecoder& decoder, TRecordDecompressor* decompressor) {
391 : 0 : return dynamic_decompressor::ptr(
392 : 0 : new dynamic_decompressor1<TDecoder, TRecordDecompressor>(decoder, decompressor));
393 : 0 : }
394 : :
395 : : // type-erasure stuff for fields
396 : : template<
397 : : typename TEncoderDecoder,
398 : : typename TField
399 : : >
400 : : struct dynamic_compressor_field : base_field {
401 : : dynamic_compressor_field(TEncoderDecoder& encdec) :
402 : : encdec_(encdec), field_()
403 : : {}
404 : :
405 : : dynamic_compressor_field(TEncoderDecoder& encdec, const TField& f) :
406 : : encdec_(encdec), field_(f)
407 : : {}
408 : :
409 : : virtual const char *compressRaw(const char *in) {
410 : : return field_.compressWith(encdec_, in);
411 : : }
412 : :
413 : : TEncoderDecoder& encdec_;
414 : : TField field_;
415 : : };
416 : :
417 : : template<
418 : : typename TEncoderDecoder,
419 : : typename TField
420 : : >
421 : 0 : struct dynamic_decompressor_field : base_field {
422 : 0 : dynamic_decompressor_field(TEncoderDecoder& encdec) :
423 : 0 : encdec_(encdec), field_()
424 : 0 : {}
425 : :
426 : 0 : dynamic_decompressor_field(TEncoderDecoder& encdec,
427 : 0 : const TField& f) : encdec_(encdec), field_(f)
428 : 0 : {}
429 : :
430 : 0 : virtual char *decompressRaw(char *buf) {
431 : 0 : return field_.decompressWith(encdec_, buf);
432 : : }
433 : :
434 : : TEncoderDecoder& encdec_;
435 : : TField field_;
436 : : };
437 : :
438 : : template<
439 : : typename TEncoder
440 : : >
441 : : struct dynamic_field_compressor: dynamic_compressor {
442 : : typedef dynamic_field_compressor<TEncoder> this_type;
443 : : typedef std::shared_ptr<this_type> ptr;
444 : :
445 : : dynamic_field_compressor(TEncoder& encoder) :
446 : : enc_(encoder), fields_()
447 : : {}
448 : :
449 : : template<typename TFieldType>
450 : : void add_field()
451 : : {
452 : : using TField = field<TFieldType>;
453 : :
454 : : fields_.push_back(base_field::ptr(new
455 : : dynamic_compressor_field<TEncoder, TField>(enc_)));
456 : : }
457 : :
458 : : template<typename TField>
459 : : void add_field(const TField& f)
460 : : {
461 : : fields_.push_back(base_field::ptr(new
462 : : dynamic_compressor_field<TEncoder, TField>(enc_, f)));
463 : : }
464 : :
465 : : virtual const char *compress(const char *in)
466 : : {
467 : : for (auto f: fields_)
468 : : in = f->compressRaw(in);
469 : : return in;
470 : : }
471 : :
472 : : TEncoder& enc_;
473 : : std::vector<base_field::ptr> fields_;
474 : : };
475 : :
476 : :
477 : : template<
478 : : typename TDecoder
479 : : >
480 : 0 : struct dynamic_field_decompressor : dynamic_decompressor {
481 : : typedef dynamic_field_decompressor<TDecoder> this_type;
482 : : typedef std::shared_ptr<this_type> ptr;
483 : :
484 : 0 : dynamic_field_decompressor(TDecoder& decoder) :
485 : 0 : dec_(decoder), fields_(), first_decomp_(true)
486 : 0 : {}
487 : :
488 : : template<typename TFieldType>
489 : 0 : void add_field()
490 : : {
491 : : using TField = field<TFieldType>;
492 : :
493 : 0 : fields_.push_back(base_field::ptr(new
494 : 0 : dynamic_decompressor_field<TDecoder, TField>(dec_)));
495 : 0 : }
496 : :
497 : : template<typename TField>
498 : 0 : void add_field(const TField& f)
499 : : {
500 : 0 : fields_.push_back(base_field::ptr(new
501 : 0 : dynamic_decompressor_field<TDecoder, TField>(dec_, f)));
502 : 0 : }
503 : :
504 : :
505 : 0 : virtual char *decompress(char *out)
506 : : {
507 : 0 : for (auto f: fields_)
508 : 0 : out = f->decompressRaw(out);
509 : :
510 : : // the decoder needs to be told that it should read the
511 : : // init bytes after the first record has been read
512 : : //
513 : 0 : if (first_decomp_) {
514 : 0 : first_decomp_ = false;
515 : 0 : dec_.readInitBytes();
516 : 0 : }
517 : 0 : return out;
518 : 0 : }
519 : :
520 : : TDecoder& dec_;
521 : : std::vector<base_field::ptr> fields_;
522 : : bool first_decomp_;
523 : : };
524 : :
525 : : template<
526 : : typename TEncoder
527 : : >
528 : : static typename dynamic_field_compressor<TEncoder>::ptr make_dynamic_compressor(TEncoder& encoder) {
529 : : typedef typename dynamic_field_compressor<TEncoder>::ptr ptr;
530 : : return ptr(new dynamic_field_compressor<TEncoder>(encoder));
531 : : }
532 : :
533 : :
534 : : template<
535 : : typename TDecoder
536 : : >
537 : 0 : static typename dynamic_field_decompressor<TDecoder>::ptr make_dynamic_decompressor(TDecoder& decoder) {
538 : : typedef typename dynamic_field_decompressor<TDecoder>::ptr ptr;
539 : 0 : return ptr(new dynamic_field_decompressor<TDecoder>(decoder));
540 : 0 : }
541 : :
542 : :
543 : : }
544 : : }
545 : :
546 : : #endif // __formats_hpp__
|