FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
pack.cpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#include <kernel/util/pack.hpp>
7
8// includes, FEAT
11#include <kernel/util/math.hpp>
12#include <kernel/util/type_traits.hpp>
13
14// includes, system
15#include <array>
16#include <algorithm>
17#include <cstring>
18
19// includes, thirdparty
20#ifdef FEAT_HAVE_ZLIB
21#include <zlib.h>
22#endif // FEAT_HAVE_ZLIB
23#ifdef FEAT_HAVE_ZFP
24FEAT_DISABLE_WARNINGS
25#include "zfp.h"
26FEAT_RESTORE_WARNINGS
27#endif // FEAT_HAVE_ZFP
28
29namespace FEAT::Pack
30{
32 template<int bytes_>
33 struct SwapHelper;
34
35 template<>
36 struct SwapHelper<1>
37 {
38 static void swap(void* /*unused*/)
39 {
40 // nothing to do here
41 }
42 };
43
44 template<>
45 struct SwapHelper<2>
46 {
47 static void swap(void* x)
48 {
49 u16& v = *reinterpret_cast<u16*>(x);
50 v = u16(((v & 0x00FFULL) << 8) | ((v & 0xFF00ULL) >> 8));
51 }
52 };
53
54 template<>
55 struct SwapHelper<4>
56 {
57 static void swap(void* x)
58 {
59 u32& v = *reinterpret_cast<u32*>(x);
60 v = u32(((v & 0x000000FFULL) << 24) | ((v & 0x0000FF00ULL) << 8) |
61 ((v & 0x00FF0000ULL) >> 8) | ((v & 0xFF000000ULL) >> 24));
62 }
63 };
64
65 template<>
66 struct SwapHelper<8>
67 {
68 static void swap(void* x)
69 {
70 u64& v = *reinterpret_cast<u64*>(x);
71 v = ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) |
72 ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) |
73 ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) |
74 ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56);
75 }
76 };
77
78 template<>
79 struct SwapHelper<16>
80 {
81 static void swap(void* x)
82 {
83 // swap two 64-bit ints
84 u64* vv = reinterpret_cast<u64*>(x);
85 u64 t = vv[0];
86 vv[0] = vv[1];
87 vv[1] = t;
88 // the the bytes within
89 SwapHelper<8>::swap(&vv[0]);
90 SwapHelper<8>::swap(&vv[1]);
91 }
92 };
93
97 template<typename X_>
98 inline X_ xswap(X_ x)
99 {
100 SwapHelper<int(sizeof(X_))>::swap(&x);
101 return x;
102 }
103
112 #ifdef FEAT_HAVE_ZFP
113 static constexpr uint zfp_header_mask = 7u;
114 #endif // FEAT_HAVE_ZFP
115
146 template<typename X_, typename T_>
147 static std::size_t xencode(void* buf, const T_* src, const std::size_t count, bool swap_bytes)
148 {
149 X_* x = reinterpret_cast<X_*>(buf);
150 if(swap_bytes)
151 {
152 for(std::size_t i(0); i < count; ++i)
153 {
154 x[i] = xswap(static_cast<X_>(src[i]));
155 }
156 }
157 else
158 {
159 for(std::size_t i(0); i < count; ++i)
160 {
161 x[i] = static_cast<X_>(src[i]);
162 }
163 }
164 return count * sizeof(X_);
165 }
166
197 template<typename X_, typename T_>
198 static std::size_t xdecode(T_* dest, const void* buf, const std::size_t count, bool swap_bytes)
199 {
200 const X_* x = reinterpret_cast<const X_*>(buf);
201 if(swap_bytes)
202 {
203 for(std::size_t i(0); i < count; ++i)
204 {
205 dest[i] = static_cast<T_>(xswap(x[i]));
206 }
207 }
208 else
209 {
210 for(std::size_t i(0); i < count; ++i)
211 {
212 dest[i] = static_cast<T_>(x[i]);
213 }
214 }
215 return count * sizeof(X_);
216 }
217
218 template<typename Tclass_, bool signed_>
220 {
221 template<typename T_>
222 static Pack::Type deduct()
223 {
224 return Pack::Type::None;
225 }
226 };
227
228 // specialization for floating point types
229 template<>
231 {
232 template<typename T_>
233 static Pack::Type deduct()
234 {
235 switch(sizeof(T_))
236 {
237 // case 1: return Pack::Type::F8;
238 case 2: return Pack::Type::F16;
239 case 4: return Pack::Type::F32;
240 case 8: return Pack::Type::F64;
241 case 16: return Pack::Type::F128;
242 default: return Pack::Type::None;
243 }
244 }
245
246 template<typename T_>
247 static std::size_t
248 encode(void* buf, const T_* t, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
249 {
250 switch(pack_type)
251 {
252#ifdef FEAT_HAVE_PACK_TYPE_F16
253 case Pack::Type::F16: return xencode<Pack::f16>(buf, t, count, swap_bytes);
254#endif
255 case Pack::Type::F32: return xencode<Pack::f32>(buf, t, count, swap_bytes);
256 case Pack::Type::F64: return xencode<Pack::f64>(buf, t, count, swap_bytes);
257#ifdef FEAT_HAVE_PACK_TYPE_F128
258 case Pack::Type::F128: return xencode<Pack::f128>(buf, t, count, swap_bytes);
259#endif
260 default: XABORTM("invalid data type conversion");
261 }
262 }
263
264 template<typename T_>
265 static std::size_t
266 decode(T_* t, const void* buf, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
267 {
268 switch(pack_type)
269 {
270#ifdef FEAT_HAVE_PACK_TYPE_F16
271 case Pack::Type::F16: return xdecode<Pack::f16>(t, buf, count, swap_bytes);
272#endif
273 case Pack::Type::F32: return xdecode<Pack::f32>(t, buf, count, swap_bytes);
274 case Pack::Type::F64: return xdecode<Pack::f64>(t, buf, count, swap_bytes);
275#ifdef FEAT_HAVE_PACK_TYPE_F128
276 case Pack::Type::F128: return xdecode<Pack::f128>(t, buf, count, swap_bytes);
277#endif
278 default: XABORTM("invalid data type conversion");
279 }
280 }
281 };
282
283 // specialization for signed integer types
284 template<>
286 {
287 template<typename T_>
288 static Pack::Type deduct()
289 {
290 switch(sizeof(T_))
291 {
292 case 1: return Pack::Type::I8;
293 case 2: return Pack::Type::I16;
294 case 4: return Pack::Type::I32;
295 case 8: return Pack::Type::I64;
296 default: return Pack::Type::None;
297 }
298 }
299
300 template<typename T_>
301 static std::size_t
302 encode(void* buf, const T_* t, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
303 {
304 switch(pack_type)
305 {
306 case Pack::Type::I8: return xencode<Pack::i8>(buf, t, count, swap_bytes);
307 case Pack::Type::I16: return xencode<Pack::i16>(buf, t, count, swap_bytes);
308 case Pack::Type::I32: return xencode<Pack::i32>(buf, t, count, swap_bytes);
309 case Pack::Type::I64: return xencode<Pack::i64>(buf, t, count, swap_bytes);
310 default: XABORTM("invalid data type conversion");
311 }
312 }
313
314 template<typename T_>
315 static std::size_t
316 decode(T_* t, const void* buf, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
317 {
318 switch(pack_type)
319 {
320 case Pack::Type::I8: return xdecode<Pack::i8>(t, buf, count, swap_bytes);
321 case Pack::Type::I16: return xdecode<Pack::i16>(t, buf, count, swap_bytes);
322 case Pack::Type::I32: return xdecode<Pack::i32>(t, buf, count, swap_bytes);
323 case Pack::Type::I64: return xdecode<Pack::i64>(t, buf, count, swap_bytes);
324 default: XABORTM("invalid data type conversion");
325 }
326 }
327 };
328
329 // specialization for unsigned integer types
330 template<>
332 {
333 template<typename T_>
334 static Pack::Type deduct()
335 {
336 switch(sizeof(T_))
337 {
338 case 1: return Pack::Type::U8;
339 case 2: return Pack::Type::U16;
340 case 4: return Pack::Type::U32;
341 case 8: return Pack::Type::U64;
342 default: return Pack::Type::None;
343 }
344 }
345
346 template<typename T_>
347 static std::size_t
348 encode(void* buf, const T_* t, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
349 {
350 switch(pack_type)
351 {
352 case Pack::Type::U8: return xencode<Pack::u8>(buf, t, count, swap_bytes);
353 case Pack::Type::U16: return xencode<Pack::u16>(buf, t, count, swap_bytes);
354 case Pack::Type::U32: return xencode<Pack::u32>(buf, t, count, swap_bytes);
355 case Pack::Type::U64: return xencode<Pack::u64>(buf, t, count, swap_bytes);
356 default: XABORTM("invalid data type conversion");
357 }
358 }
359
360 template<typename T_>
361 static std::size_t
362 decode(T_* t, const void* buf, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
363 {
364 switch(pack_type)
365 {
366 case Pack::Type::U8: return xdecode<Pack::u8>(t, buf, count, swap_bytes);
367 case Pack::Type::U16: return xdecode<Pack::u16>(t, buf, count, swap_bytes);
368 case Pack::Type::U32: return xdecode<Pack::u32>(t, buf, count, swap_bytes);
369 case Pack::Type::U64: return xdecode<Pack::u64>(t, buf, count, swap_bytes);
370 default: XABORTM("invalid data type conversion");
371 }
372 }
373 };
374
375 template<typename T_>
377 {
378 using TypeTraits = typename FEAT::Type::Traits<T_>;
380 }
381
406 template<typename T_>
407 static std::size_t
408 encode_raw(void* buf, const T_* src, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
409 {
410 if(count <= std::size_t(0))
411 {
412 return std::size_t(0);
413 }
414
415 XASSERT(buf != nullptr);
416 XASSERT(src != nullptr);
417
418 XASSERTM((pack_type & Pack::Type::Mask_T) != Pack::Type::None, "invalid pack type");
419 XASSERTM((pack_type & Pack::Type::Mask_Z) != Pack::Type::Mask_Z, "cannot encode compressed type");
420
421 using TypeTraits = typename FEAT::Type::Traits<T_>;
422
424 buf,
425 src,
426 count,
427 pack_type,
428 swap_bytes);
429 }
430
455 template<typename T_>
456 static std::size_t
457 decode_raw(T_* dst, const void* buf, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
458 {
459 if(count <= std::size_t(0))
460 {
461 return std::size_t(0);
462 }
463
464 XASSERT(dst != nullptr);
465 XASSERT(buf != nullptr);
466
467 XASSERTM((pack_type & Pack::Type::Mask_T) != Pack::Type::None, "invalid pack type");
468 XASSERTM((pack_type & Pack::Type::Mask_Z) != Pack::Type::Mask_Z, "cannot decode compressed type");
469
470 using TypeTraits = typename FEAT::Type::Traits<T_>;
471
473 dst,
474 buf,
475 count,
476 pack_type,
477 swap_bytes);
478 }
479
500 static std::size_t lossy_estimate_size(const std::size_t count, const Pack::Type type, const double tolerance)
501 {
502 if(count <= std::size_t(0))
503 {
504 return std::size_t(0);
505 }
506#ifdef FEAT_HAVE_ZFP
507 // get type T_, int would be handleable... but why lossy save an int array?:
508 zfp_type t = zfp_type::zfp_type_none;
509 switch(type)
510 {
511 case Pack::Type::PF32: t = zfp_type::zfp_type_float; break;
512 case Pack::Type::PF64: t = zfp_type::zfp_type_double; break;
513 default: XABORTM("cannot encode compressed type; data typ not available");
514 }
515 XASSERT(t != zfp_type::zfp_type_none);
516
517 // declare needed zfp internal variables:
518 zfp_field* field;
519 zfp_stream* zfp;
520 std::size_t bytes;
521 std::size_t x_size, y_size;
522 void* temp_arr = nullptr;
523
524 // calculate needed representation size, e.g. 4 times (size/4 +1):
525 x_size = 4u;
526 y_size = count / x_size + 1;
527
528 // check if we lose significant bits through type conversion...
529 if((sizeof(std::size_t) > sizeof(uint)) && (count > std::numeric_limits<uint>::max()))
530 XABORTM("cannot encode compressed type; array size to big for internal data");
531
532 // initialize zfp field as 2D variant, that src is not right type does not
533 // matter at this point...( memory has to be freed in the end):
534 field = zfp_field_2d(temp_arr, t, (uint)x_size, (uint)y_size);
535 // open stream(has to be freed)
536 zfp = zfp_stream_open(NULL);
537 // set error tolerance of stream:
538 zfp_stream_set_accuracy(zfp, tolerance);
539 // get a conservativ estimate for the buffer size(header size included)
540 bytes = zfp_stream_maximum_size(zfp, field);
541
542 // free allocated data:
543 zfp_field_free(field);
544 zfp_stream_close(zfp);
545
546 // return compression size
547 return bytes;
548
549#else // no FEAT_HAVE_ZFP
550 (void)type;
551 (void)tolerance;
552 XABORTM("cannot encode compressed type; zfp not available");
553 return std::size_t(0);
554#endif // FEAT_HAVE_ZFP*/
555 }
556
557 std::size_t estimate_size(const std::size_t count, const Pack::Type type, const double tolerance)
558 {
559 if((type & Pack::Type::Mask_P) != Pack::Type::None)
560 {
561 return lossy_estimate_size(count, type, tolerance);
562 }
563 // compute raw element size
564 std::size_t raw_size = count * Pack::element_size(type & Pack::Type::Mask_T);
565
566#ifdef FEAT_HAVE_ZLIB
567 if((type & Pack::Type::Mask_Z) != Pack::Type::None)
568 {
569 return std::size_t(::compressBound(uLong(raw_size)));
570 }
571#else // no FEAT_HAVE_ZLIB
572 XASSERTM((type & Pack::Type::Mask_Z) == Pack::Type::None, "cannot estimate compressed size; zlib not available");
573#endif // FEAT_HAVE_ZLIB
574
575 // return raw size
576 return raw_size;
577 }
578
579 template<typename T_>
580 std::size_t encode(
581 void* buf,
582 const T_* src,
583 const std::size_t buf_size,
584 const std::size_t count,
585 const Pack::Type pack_type,
586 bool swap_bytes,
587 double tolerance)
588 {
589 if(count <= std::size_t(0))
590 {
591 return std::size_t(0);
592 }
593
594 XASSERT(buf != nullptr);
595 XASSERT(src != nullptr);
596
597 // get raw type
598 const Pack::Type raw_type = pack_type & Pack::Type::Mask_T;
599
600 // no compression required?
601 if((pack_type & (Pack::Type::Mask_Z | Pack::Type::Mask_P)) == Pack::Type::None)
602 {
603 return encode_raw(buf, src, count, raw_type, swap_bytes);
604 }
605
606 // zlib compression?
607 if((pack_type & Pack::Type::Mask_Z) == Pack::Type::Mask_Z)
608 {
609 return lossless_encode(buf, src, buf_size, count, pack_type, swap_bytes);
610 }
611
612 // zfp compression?
613 if((pack_type & Pack::Type::Mask_P) == Pack::Type::Mask_P)
614 {
615 return lossy_encode(buf, src, buf_size, count, pack_type, swap_bytes, tolerance);
616 }
617
618 return std::size_t(0);
619 }
620
646 template<typename T_>
647 static std::size_t lossless_encode(
648 void* buf,
649 const T_* src,
650 const std::size_t buf_size,
651 const std::size_t count,
652 const Pack::Type pack_type,
653 bool swap_bytes)
654 {
655 // get raw type
656 const Pack::Type raw_type = pack_type & Pack::Type::Mask_T;
657
658#ifdef FEAT_HAVE_ZLIB
659 // ensure that the temporary buffer is large enough
660 std::size_t raw_size = element_size(raw_type) * count;
661 std::vector<char> tmp(raw_size);
662
663 // encode into temporary buffer
664 encode_raw(tmp.data(), src, count, raw_type, swap_bytes);
665
666 // cast buffer lengths to zlib types
667 uLongf dl = static_cast<uLongf>(buf_size);
668 uLong sl = static_cast<uLong>(raw_size);
669
670 // cast buffer pointers to zlib types
671 Bytef* dbuf = reinterpret_cast<Bytef*>(buf);
672 const Bytef* sbuf = reinterpret_cast<const Bytef*>(tmp.data());
673
674 // compress via zlib
675 if(::compress(dbuf, &dl, sbuf, sl) != Z_OK)
676 XABORTM("zlib compression error");
677
678 // return final destination buffer usage as reported by zlib
679 return static_cast<std::size_t>(dl);
680#else // no FEAT_HAVE_ZLIB
681 (void)buf_size;
682 (void)buf;
683 (void)src;
684 (void)raw_type;
685 (void)swap_bytes;
686 (void)pack_type;
687 (void)count;
688 XABORTM("cannot encode compressed type; zlib not available");
689 return std::size_t(0);
690#endif // FEAT_HAVE_ZLIB
691 }
692
693 template<typename T_>
694 std::size_t decode(
695 T_* dst,
696 void* buf,
697 const std::size_t count,
698 const std::size_t buf_size,
699 const Pack::Type pack_type,
700 bool swap_bytes)
701 {
702 if(count <= std::size_t(0))
703 {
704 return std::size_t(0);
705 }
706
707 XASSERT(dst != nullptr);
708 XASSERT(buf != nullptr);
709
710 // get raw type
711 const Pack::Type raw_type = pack_type & Pack::Type::Mask_T;
712
713 // no compression required?
714 if((pack_type & (Pack::Type::Mask_Z | Pack::Type::Mask_P)) == Pack::Type::None)
715 {
716 return decode_raw(dst, buf, count, raw_type, swap_bytes);
717 }
718
719 // zlib compression?
720 if((pack_type & Pack::Type::Mask_Z) == Pack::Type::Mask_Z)
721 {
722 return lossless_decode(dst, buf, count, buf_size, pack_type, swap_bytes);
723 }
724
725 // zfp compression?
726 if((pack_type & Pack::Type::Mask_P) == Pack::Type::Mask_P)
727 {
728 return lossy_decode(dst, buf, count, buf_size, pack_type, swap_bytes);
729 }
730
731 return std::size_t(0);
732 }
733
758 template<typename T_>
759 static std::size_t lossless_decode(
760 T_* dst,
761 const void* buf,
762 const std::size_t count,
763 const std::size_t buf_size,
764 const Pack::Type pack_type,
765 bool swap_bytes)
766 {
767 // get raw type
768 const Pack::Type raw_type = pack_type & Pack::Type::Mask_T;
769
770#ifdef FEAT_HAVE_ZLIB
771 // ensure that the temporary buffer is large enough
772 std::size_t raw_size = element_size(raw_type) * count + 1024u; // + 1KB
773 std::vector<char> tmp(raw_size);
774
775 // cast buffer lengths to zlib types
776 uLongf dl = static_cast<uLongf>(raw_size);
777 uLong sl = static_cast<uLong>(buf_size);
778
779 // cast buffer pointers to zlib types
780 Bytef* dbuf = reinterpret_cast<Bytef*>(tmp.data());
781 const Bytef* sbuf = reinterpret_cast<const Bytef*>(buf);
782
783 // decompress via zlib
784 if(::uncompress2(dbuf, &dl, sbuf, &sl) != Z_OK)
785 XABORTM("zlib decompression error");
786
787 // decode from temporary buffer
788 decode_raw(dst, tmp.data(), count, raw_type, swap_bytes);
789
790 // return final source buffer usage as reported by zlib
791 return static_cast<std::size_t>(sl);
792#else // no FEAT_HAVE_ZLIB
793 (void)buf_size;
794 (void)buf;
795 (void)dst;
796 (void)raw_type;
797 (void)swap_bytes;
798 (void)pack_type;
799 (void)count;
800 XABORTM("cannot decode compressed type; zlib not available");
801 return std::size_t(0);
802#endif // FEAT_HAVE_ZLIB
803 }
804
838 template<typename T_>
839 static std::size_t lossy_encode(
840 void* buf,
841 T_* src,
842 const std::size_t buf_size,
843 const std::size_t count,
844 const Pack::Type pack_type,
845 bool swap_bytes,
846 const double tolerance)
847 {
848 // get raw type
849 const Pack::Type raw_type = pack_type & Pack::Type::Mask_T;
850 // Test if zfp is loaded:
851#ifdef FEAT_HAVE_ZFP
852 // get type T_ :
853 zfp_type t = zfp_type::zfp_type_none;
854 switch(pack_type)
855 {
856 case Pack::Type::PF32: t = zfp_type::zfp_type_float; break;
857 case Pack::Type::PF64: t = zfp_type::zfp_type_double; break;
858 default: XABORTM("cannot encode compressed type; data typ not available");
859 }
860 XASSERT(t != zfp_type::zfp_type_none);
861 // check if header can hold size of the array, in case it cant (more than 1
862 // petabyte of double data) give out error for now limitation is only for the
863 // header, not for the underlying zfp_array, so there could be a workaround if
864 // needed...
865 XASSERT(count <= u64(2e14));
866
867 // cast src to the needed type:
868 // ensure that the temporary buffer is large enough
869 std::size_t raw_size = element_size(raw_type) * count + 3 * element_size(raw_type);
870 std::vector<char> tmp(raw_size);
871
872 // encode into temporary buffer
873 encode_raw(tmp.data(), src, count, raw_type, swap_bytes);
874
875 // declare needed zfp internal variables:
876 zfp_field* field;
877 zfp_stream* zfp;
878 std::size_t real_bytes;
879 bitstream* stream;
880 std::size_t x_size, y_size;
881
882 // check if we lose significant bits through type conversion...
883 if((sizeof(std::size_t) > sizeof(uint)) && (count > std::numeric_limits<uint>::max()))
884 XABORTM("cannot encode compressed type; array size to big for internal "
885 "data structure");
886 // calculate needed representation size and rest:
887 x_size = 4u;
888 if(count % 4u == 0)
889 y_size = count / x_size;
890 else
891 y_size = count / x_size + 1;
892
893 // initialize zfp structures:
894 field = zfp_field_2d(tmp.data(), t, (uint)x_size, (uint)y_size);
895 zfp = zfp_stream_open(NULL);
896 zfp_stream_set_accuracy(zfp, tolerance);
897 stream = stream_open(buf, buf_size);
898 zfp_stream_set_bit_stream(zfp, stream);
899 stream_rewind(stream);
900 // write header to stream
901 zfp_write_header(zfp, field, zfp_header_mask);
902 // compress
903 real_bytes = zfp_compress(zfp, field);
904
905 // free allocated data:
906 zfp_field_free(field);
907 zfp_stream_close(zfp);
908 stream_close(stream);
909
910 return real_bytes;
911#else
912 (void)buf_size;
913 (void)buf;
914 (void)src;
915 (void)raw_type;
916 (void)swap_bytes;
917 (void)pack_type;
918 (void)count;
919 (void)tolerance;
920 XABORTM("cannot encode compressed type; zfp not available");
921 return std::size_t(0);
922#endif // FEAT_HAVE_ZFP
923 }
924
950 template<typename T_>
951 static std::size_t lossy_decode(
952 T_* dst,
953 void* buf,
954 const std::size_t count,
955 const std::size_t buf_size,
956 const Pack::Type pack_type,
957 bool swap_bytes)
958 {
959 // get raw type
960 const Pack::Type raw_type = pack_type & Pack::Type::Mask_T;
961#ifdef FEAT_HAVE_ZFP
962 // get type T_ :
963 zfp_type t = zfp_type::zfp_type_none;
964 switch(pack_type)
965 {
966 case Pack::Type::PF32: t = zfp_type::zfp_type_float; break;
967 case Pack::Type::PF64: t = zfp_type::zfp_type_double; break;
968 default: XABORTM("cannot encode compressed type; data typ not available");
969 }
970 XASSERT(t != zfp_type::zfp_type_none);
971
972 // ensure that the temporary buffer is large enough
973 std::size_t raw_size = element_size(raw_type) * count + 1024u; // + 1KB
974 std::vector<char> tmp(raw_size);
975
976 // declare intern zfp variables
977 zfp_field* field;
978 zfp_stream* zfp;
979 bitstream* stream;
980 std::size_t array_size;
981 std::size_t real_bytes;
982 // allocating memory
983 field = zfp_field_alloc();
984 zfp = zfp_stream_open(NULL);
985 // aligning stream with buf:
986 stream = stream_open(buf, buf_size);
987 // read in Codec:
988 stream_rseek(stream, 24u);
989 uint codec = (uint)stream_read_bits(stream, 8u);
990 XASSERTM(
991 codec == zfp_codec_version,
992 "cannot decode compressed type; zfp version not compatible \n "
993 "zfp_Systemcodec: " +
994 stringify(zfp_codec_version) + "\n zfp_Compressed codec: " + stringify(codec));
995 stream_rewind(stream);
996 // aligning zfp_stream with bitsream
997 zfp_stream_set_bit_stream(zfp, stream);
998 // read header
999 zfp_read_header(zfp, field, zfp_header_mask);
1000 array_size = zfp_field_size(field, NULL);
1001 // check if T_ and type to be decompressed is same:
1002 if(t != field->type)
1003 XABORTM("cannot decode compressed type; given array and saved data do not "
1004 "have the same type");
1005 // checking if buffersize of given array is enough to take up saved array....
1006 if(array_size - 3 > count)
1007 XABORTM("cannot decode compressed data; given count is too small for "
1008 "decompressed data!");
1009 // alligning field and tmp
1010 field->data = tmp.data();
1011 // decompress data
1012 real_bytes = zfp_decompress(zfp, field);
1013
1014 // decode from temporary buffer
1015 decode_raw(dst, tmp.data(), count, raw_type, swap_bytes);
1016
1017 // free memory
1018 zfp_field_free(field);
1019 zfp_stream_close(zfp);
1020 stream_close(stream);
1021
1022 return real_bytes;
1023#else
1024 (void)buf_size;
1025 (void)buf;
1026 (void)dst;
1027 (void)count;
1028 (void)raw_type;
1029 (void)swap_bytes;
1030 (void)pack_type;
1031 XABORTM("cannot decode compressed type; zfp not available");
1032 return std::size_t(0);
1033#endif // FEAT_HAVE_ZFP
1034 }
1035
1037 // Base64 handling
1039
1040 static constexpr std::string_view base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1041 static constexpr char base64_padding = '=';
1042
1044 static bool is_valid_base64_char(const char c)
1045 {
1046 return (std::isalnum(c) != 0) || c == '+' || c == '/' || c == base64_padding;
1047 }
1048
1050 static void encode_base64_quantum(const std::array<Pack::u8, 3>& quantum, std::array<Pack::u8, 4>& chars)
1051 {
1052 // +--first octet--+-second octet--+--third octet--+
1053 // |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
1054 // +-----------+---+-------+-------+---+-----------+
1055 // |5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|
1056 // +--1.index--+--2.index--+--3.index--+--4.index--+
1057
1058 // Leftmost 6 bits of first octet
1059 chars[0] = static_cast<Pack::u8>((quantum[0] & 0b11111100U) >> 2U);
1060
1061 // Rightmost 2 bits of first octet and leftmost 4 bits of second octet
1062 chars[1] = static_cast<Pack::u8>(((quantum[0] & 0b00000011U) << 4U) | ((quantum[1] & 0b11110000U) >> 4U));
1063
1064 // Rightmost 4 bits of second octet and leftmost 2 bits of third octet
1065 chars[2] = static_cast<Pack::u8>(((quantum[1] & 0b00001111U) << 2U) | ((quantum[2] & 0b11000000U) >> 6U));
1066
1067 // Rightmost 6 bits of third octet
1068 chars[3] = static_cast<Pack::u8>(quantum[2] & 0b00111111U);
1069 }
1070
1072 static void decode_base64_quantum(std::array<Pack::u8, 3>& quantum, const std::array<Pack::u8, 4>& chars)
1073 {
1074 // +--first octet--+-second octet--+--third octet--+
1075 // |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
1076 // +-----------+---+-------+-------+---+-----------+
1077 // |5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|
1078 // +--1.index--+--2.index--+--3.index--+--4.index--+
1079
1080 // First char and leftmost two bits of second char
1081 // NOTE: Useless mask for first operand silences warning about promotion to int
1082 quantum[0] = static_cast<Pack::u8>(((chars[0] & 0b11111111U) << 2U) | ((chars[1] & 0b00110000U) >> 4U));
1083
1084 // Rightmost four bits of second char and leftmost four bits of third char
1085 quantum[1] = static_cast<Pack::u8>(((chars[1] & 0b00001111U) << 4U) | ((chars[2] & 0b00111100U) >> 2U));
1086
1087 // Rightmost two bits of third char and fourth char
1088 quantum[2] = static_cast<Pack::u8>(((chars[2] & 0b00000011U) << 6U) | (chars[3] & 0b00111111U));
1089 }
1090
1099 {
1100 return std::all_of(s.begin(), s.end(), [](char c) { return is_valid_base64_char(c); });
1101 }
1102
1115 String base64_encode(const Pack::u8* begin, const Pack::u8* end)
1116 {
1117 // Groups of three bytes are split into 6-bit groups,
1118 // which are used as indices into the base64 alphabet
1119
1120 // We call each non-overlapping group of 3 bytes a "quantum" of data
1121
1122 // Depending on the input, there might be a partial quantum left
1123 // after processing the final complete quantum.
1124 // If there are no bits left, then encoding is done
1125 // If there are 8 bits left, then the final bytes
1126 // are encoded into two characters followed by two padding characters
1127 // If there are 16 bits left, then the final bytes
1128 // are encoded into three characters follow by a padding character
1129
1130 // Group of three bytes
1131 std::array<Pack::u8, 3> quantum{};
1132
1133 // Group of four characters
1134 std::array<Pack::u8, 4> chars{};
1135
1136 // Allocate outpuly 4 chars for at
1137 // 4 chars per full quantum plus potentially 4 chars for a partial quantum
1138 const auto num_bytes = static_cast<Index>(std::distance(begin, end));
1139 const Index full_quantums = num_bytes / Index(3);
1140 String output((full_quantums * 4) + (num_bytes % 3 == 0 ? 0 : 4), '=');
1141
1142 // Index into the current quantum of three bytes.
1143 // Used to determine when a quantum is full and to
1144 // determine the size of the partial quantum at the end
1145 Index quantum_idx(0);
1146
1147 // Current position in output string
1148 Index output_pos(0);
1149
1150 // Pointer to next byte of input
1151 const Pack::u8* next_byte = begin;
1152
1153 while(next_byte != end)
1154 {
1155 quantum[quantum_idx++] = *next_byte++;
1156
1157 // Quantum is full. Encode it and write it to the output
1158 if(quantum_idx == 3)
1159 {
1160 encode_base64_quantum(quantum, chars);
1161
1162 for(Pack::u8 idx : chars)
1163 {
1164 output[output_pos++] = base64_alphabet[idx];
1165 }
1166
1167 // Reset quantum index
1168 quantum_idx = 0;
1169 }
1170 }
1171
1172 // Check for partial quantum
1173 if(quantum_idx > 0)
1174 {
1175 // Zero pad quantum
1176 for(Index j = quantum_idx; j < 3; j++)
1177 {
1178 quantum[j] = 0;
1179 }
1180
1181 encode_base64_quantum(quantum, chars);
1182
1183 // One byte in quantum => two chars in ouput
1184 // Two bytes in quamtum => three chars in output
1185 for(Index j(0); j < (quantum_idx + 1); j++)
1186 {
1187 output[output_pos++] = base64_alphabet[chars[j]];
1188 }
1189 // String is automatically padded by initialization
1190 }
1191
1192 return output;
1193 }
1194
1204 std::vector<Pack::u8> base64_decode(const String& s)
1205 {
1206 // Groups of four characters are split into three bytes.
1207 // We call each group of 3 bytes a "quantum" of data
1208
1209 // The input string might be padded with '=' characters.
1210 // These are treated as zeros for the purposes of decoding a 3-byte
1211 // quantum. Bytes that consist solely of padding bits are discarded.
1212
1213 // Group of three bytes
1214 std::array<Pack::u8, 3> quantum{};
1215 // Group of four Base64 chars
1216 std::array<Pack::u8, 4> chars{};
1217
1218 std::vector<Pack::u8> output;
1219
1220 // Index into the current group of four chars.
1221 // Used to determine when a group is full and to
1222 // determine the size of the partial group at the end
1223 Index char_idx(0);
1224
1225 // Pointer to next input char
1226 auto next_char = s.begin();
1227
1228 while(next_char != s.end() && is_valid_base64_char(*next_char) && *next_char != base64_padding)
1229 {
1230 // Cast is safe because we know the char is a valid base64 char
1231 chars[char_idx++] = static_cast<Pack::u8>(base64_alphabet.find(*next_char++));
1232
1233 if(char_idx == 4)
1234 {
1235 decode_base64_quantum(quantum, chars);
1236
1237 for(Pack::u8 byte : quantum)
1238 {
1239 output.push_back(byte);
1240 }
1241
1242 char_idx = 0;
1243 }
1244 }
1245
1246 if(char_idx > 0)
1247 {
1248 // Zero pad chars
1249 for(Index j = char_idx; j < 4; j++)
1250 {
1251 chars[j] = 0;
1252 }
1253
1254 decode_base64_quantum(quantum, chars);
1255
1256 // Two chars in string => one byte in output
1257 // Three chars in string => two bytes in output
1258 for(Index j(0); j < (char_idx - 1); j++)
1259 {
1260 output.push_back(quantum[j]);
1261 }
1262 }
1263
1264 return output;
1265 }
1266
1268 // Explicit template instantiations for supported data types
1270
1271 template Pack::Type deduct_type<i8>();
1272 template Pack::Type deduct_type<i16>();
1273 template Pack::Type deduct_type<i32>();
1274 template Pack::Type deduct_type<i64>();
1275
1276 template Pack::Type deduct_type<u8>();
1277 template Pack::Type deduct_type<u16>();
1278 template Pack::Type deduct_type<u32>();
1279 template Pack::Type deduct_type<u64>();
1280
1281#if defined(FEAT_HAVE_PACK_TYPE_F16)
1282 template Pack::Type deduct_type<f16>();
1283#endif
1284 template Pack::Type deduct_type<f32>();
1285 template Pack::Type deduct_type<f64>();
1286
1287#if defined(FEAT_HAVE_PACK_TYPE_F128)
1288 template Pack::Type deduct_type<f128>();
1289#endif
1290
1291 template Pack::Type deduct_type<long long>();
1292
1293 template std::size_t encode<i8>(void*, const i8*, std::size_t, std::size_t, Pack::Type, bool, double);
1294 template std::size_t encode<i16>(void*, const i16*, std::size_t, std::size_t, Pack::Type, bool, double);
1295 template std::size_t encode<i32>(void*, const i32*, std::size_t, std::size_t, Pack::Type, bool, double);
1296 template std::size_t encode<i64>(void*, const i64*, std::size_t, std::size_t, Pack::Type, bool, double);
1297
1298 template std::size_t encode<u8>(void*, const u8*, std::size_t, std::size_t, Pack::Type, bool, double);
1299 template std::size_t encode<u16>(void*, const u16*, std::size_t, std::size_t, Pack::Type, bool, double);
1300 template std::size_t encode<u32>(void*, const u32*, std::size_t, std::size_t, Pack::Type, bool, double);
1301 template std::size_t encode<u64>(void*, const u64*, std::size_t, std::size_t, Pack::Type, bool, double);
1302
1303#if defined(FEAT_HAVE_PACK_TYPE_F16)
1304 template std::size_t encode<f16>(void*, const f16*, std::size_t, std::size_t, Pack::Type, bool, double);
1305#endif
1306 template std::size_t encode<f32>(void*, const f32*, std::size_t, std::size_t, Pack::Type, bool, double);
1307 template std::size_t encode<f64>(void*, const f64*, std::size_t, std::size_t, Pack::Type, bool, double);
1308
1309#if defined(FEAT_HAVE_PACK_TYPE_F128)
1310 template std::size_t encode<f128>(void*, const f128*, std::size_t, std::size_t, Pack::Type, bool, double);
1311#endif
1312
1313 template std::size_t encode<long long>(void*, const long long*, std::size_t, std::size_t, Pack::Type, bool, double);
1314
1315 template std::size_t decode<i8>(i8*, void*, std::size_t, std::size_t, Pack::Type, bool);
1316 template std::size_t decode<i16>(i16*, void*, std::size_t, std::size_t, Pack::Type, bool);
1317 template std::size_t decode<i32>(i32*, void*, std::size_t, std::size_t, Pack::Type, bool);
1318 template std::size_t decode<i64>(i64*, void*, std::size_t, std::size_t, Pack::Type, bool);
1319
1320 template std::size_t decode<u8>(u8*, void*, std::size_t, std::size_t, Pack::Type, bool);
1321 template std::size_t decode<u16>(u16*, void*, std::size_t, std::size_t, Pack::Type, bool);
1322 template std::size_t decode<u32>(u32*, void*, std::size_t, std::size_t, Pack::Type, bool);
1323 template std::size_t decode<u64>(u64*, void*, std::size_t, std::size_t, Pack::Type, bool);
1324
1325#if defined(FEAT_HAVE_PACK_TYPE_F16)
1326 template std::size_t decode<f16>(f16*, void*, std::size_t, std::size_t, Pack::Type, bool);
1327#endif
1328 template std::size_t decode<f32>(f32*, void*, std::size_t, std::size_t, Pack::Type, bool);
1329 template std::size_t decode<f64>(f64*, void*, std::size_t, std::size_t, Pack::Type, bool);
1330
1331#if defined(FEAT_HAVE_PACK_TYPE_F128)
1332 template std::size_t decode<f128>(f128*, void*, std::size_t, std::size_t, Pack::Type, bool);
1333#endif
1334
1335 template std::size_t decode<long long>(long long*, void*, std::size_t, std::size_t, Pack::Type, bool);
1336
1337#if defined(_WIN32)
1338 template Pack::Type deduct_type<unsigned long>();
1339 template std::size_t encode<unsigned long>(void*, const unsigned long*, std::size_t, std::size_t, Pack::Type, bool, double);
1340 template std::size_t decode<unsigned long>(unsigned long*, void*, std::size_t, std::size_t, Pack::Type, bool);
1341#endif
1342} // namespace FEAT::Pack
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
String class implementation.
Definition: string.hpp:47
Tag class for floating data types.
Definition: type_traits.hpp:62
Tag class for integral data types.
Definition: type_traits.hpp:60
Data Array Pack namespace.
Definition: pack.cpp:30
static std::size_t xdecode(T_ *dest, const void *buf, const std::size_t count, bool swap_bytes)
Encodes an array by converting each of its elements to a desired type.
Definition: pack.cpp:198
static std::size_t lossy_estimate_size(const std::size_t count, const Pack::Type type, const double tolerance)
Computes the estimated (upper bound) pack buffer size for an array for lossy compression.
Definition: pack.cpp:500
std::int32_t i32
32-bit signed integer type
Definition: pack.hpp:31
std::size_t encode(void *buf, const T_ *src, const std::size_t buf_size, const std::size_t count, const Pack::Type pack_type, bool swap_bytes, double tolerance)
Encodes an array into a packed buffer.
Definition: pack.cpp:580
std::uint64_t u64
64-bit unsigned integer type
Definition: pack.hpp:42
static std::size_t lossless_encode(void *buf, const T_ *src, const std::size_t buf_size, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
Encodes an array into a packed buffer.
Definition: pack.cpp:647
std::size_t element_size(const Pack::Type type)
Returns the size of a Pack::Type element in bytes.
Definition: pack.hpp:256
std::size_t estimate_size(const std::size_t count, const Pack::Type type, const double tolerance)
Computes the estimated (upper bound) pack buffer size for an array.
Definition: pack.cpp:557
static std::size_t lossless_decode(T_ *dst, const void *buf, const std::size_t count, const std::size_t buf_size, const Pack::Type pack_type, bool swap_bytes)
Decodes an array from a packed buffer.
Definition: pack.cpp:759
String base64_encode(const Pack::u8 *begin, const Pack::u8 *end)
Encodes bytes into a Base64 string.
Definition: pack.cpp:1115
static void decode_base64_quantum(std::array< Pack::u8, 3 > &quantum, const std::array< Pack::u8, 4 > &chars)
Decodes a group of four Base64 characters into a group of three bytes.
Definition: pack.cpp:1072
static std::size_t decode_raw(T_ *dst, const void *buf, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
Decodes an array from a packed buffer without compression support.
Definition: pack.cpp:457
static bool is_valid_base64_char(const char c)
Checks if the given characters is a valid Base64 character.
Definition: pack.cpp:1044
Half f16
16-bit floating point type
Definition: pack.hpp:47
float f32
32-bit floating point type
Definition: pack.hpp:54
Type
Type enumeration.
Definition: pack.hpp:70
static void encode_base64_quantum(const std::array< Pack::u8, 3 > &quantum, std::array< Pack::u8, 4 > &chars)
Encodes a group of three bytes into four Base64 characters.
Definition: pack.cpp:1050
std::int16_t i16
16-bit signed integer type
Definition: pack.hpp:29
std::uint32_t u32
32-bit unsigned integer type
Definition: pack.hpp:40
std::int64_t i64
64-bit signed integer type
Definition: pack.hpp:33
std::uint16_t u16
16-bit unsigned integer type
Definition: pack.hpp:38
static std::size_t lossy_decode(T_ *dst, void *buf, const std::size_t count, const std::size_t buf_size, const Pack::Type pack_type, bool swap_bytes)
Decodes an array from a packed buffer with lossy saved compression data.
Definition: pack.cpp:951
static std::size_t encode_raw(void *buf, const T_ *src, const std::size_t count, const Pack::Type pack_type, bool swap_bytes)
Encodes an array into a packed buffer without compression support.
Definition: pack.cpp:408
std::int8_t i8
8-bit signed integer type
Definition: pack.hpp:27
static std::size_t lossy_encode(void *buf, T_ *src, const std::size_t buf_size, const std::size_t count, const Pack::Type pack_type, bool swap_bytes, const double tolerance)
Encodes an array into a packed buffer.
Definition: pack.cpp:839
double f64
64-bit floating point type
Definition: pack.hpp:56
std::size_t decode(T_ *dst, void *buf, const std::size_t count, const std::size_t buf_size, const Pack::Type pack_type, bool swap_bytes)
Decodes an array from a packed buffer.
Definition: pack.cpp:694
std::uint8_t u8
8-bit unsigned integer type
Definition: pack.hpp:36
Pack::Type deduct_type()
Deduct the (raw) Pack::Type from a given data type T_.
Definition: pack.cpp:376
bool is_valid_base64_string(const String &s)
Definition: pack.cpp:1098
std::vector< Pack::u8 > base64_decode(const String &s)
Decodes a Base64 string into bytes.
Definition: pack.cpp:1204
X_ xswap(X_ x)
Swaps the bytes of an object.
Definition: pack.cpp:98
static std::size_t xencode(void *buf, const T_ *src, const std::size_t count, bool swap_bytes)
bitmask for zfp header
Definition: pack.cpp:147
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:993
std::uint64_t Index
Index data type.
auxiliary helper class: swaps the bytes of an 8/16/32/64/128 byte type
Definition: pack.cpp:33
basic Type Traits struct
Definition: type_traits.hpp:73