├── CMakeLists.txt ├── License.txt ├── README.md ├── all.hpp ├── amsg.hpp ├── example ├── CMakeLists.txt ├── sfix │ ├── CMakeLists.txt │ └── main.cpp ├── size_of │ ├── CMakeLists.txt │ └── main.cpp └── smax │ ├── CMakeLists.txt │ └── main.cpp ├── test ├── CMakeLists.txt ├── main.cpp └── test_base.hpp └── zerocopy.hpp /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of the CMake build system for Amsg 3 | # 4 | # CMake auto-generated configuration options. 5 | # Do not check in modified versions of this file. 6 | # 7 | # Copyright (c) 2012 Ning Ding(lordoffox,lordoffox@gmail.com) 8 | # 9 | # Distributed under the Boost Software License, Version 1.0. (See accompanying 10 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 11 | # 12 | # See https://github.com/lordoffox/amsg for latest version. 13 | # 14 | 15 | cmake_minimum_required (VERSION 2.8.6 FATAL_ERROR) 16 | project (amsg) 17 | 18 | # The version number. 19 | set (AMSG_VERSION_MAJOR 1) 20 | set (AMSG_VERSION_MINOR 0) 21 | 22 | # Provide user options to customise the build process. 23 | option (AMSG_BUILD_EXAMPLE "Build Amsg examples" ON) 24 | option (AMSG_BUILD_TEST "Build Amsg tests" ON) 25 | option (AMSG_STD_CXX11 "Build Amsg using C++11" OFF) 26 | 27 | if (AMSG_BUILD_TEST OR AMSG_BUILD_EXAMPLE) 28 | if (UNIX) 29 | option (AMSG_STATIC "AMSG test and example runtime static" OFF) 30 | endif () 31 | 32 | if (AMSG_STD_CXX11) 33 | add_definitions (-DAMSG_STD_CXX11) 34 | endif () 35 | 36 | if (WIN32) 37 | set (AMSG_WINVER "0x0501" CACHE STRING "Windows version maro. Default is 0x0501 - winxp, user can reset") 38 | add_definitions (-D_WIN32_WINNT=${AMSG_WINVER}) 39 | endif () 40 | 41 | # Add the source and build tree to the search path for include gce header files. 42 | include_directories (${CMAKE_CURRENT_SOURCE_DIR}/../) 43 | 44 | # Set glibc for static runtime. 45 | if (AMSG_STATIC) 46 | set (GLIBC_INCLUDEDIR "" CACHE PATH "Path to glibc include directory") 47 | set (GLIBC_LIBRARYDIR "" CACHE PATH "Path to glibc libraries directory") 48 | if (GLIBC_INCLUDEDIR) 49 | include_directories (${GLIBC_INCLUDEDIR}) 50 | endif () 51 | if (GLIBC_LIBRARYDIR) 52 | link_directories (${GLIBC_LIBRARYDIR}) 53 | endif () 54 | endif () 55 | 56 | # Boost headers only search. 57 | find_package (Boost 1.55.0) 58 | if (Boost_FOUND) 59 | include_directories (${Boost_INCLUDE_DIRS}) 60 | else () 61 | message (FATAL_ERROR "Boost not found! Please set BOOST_ROOT and rerun cmake.") 62 | endif () 63 | 64 | set (CMAKE_VERBOSE_MAKEFILE true) 65 | 66 | if (AMSG_STATIC) 67 | set (AMSG_LINK_PROP "-static -static-libgcc -static-libstdc++") 68 | endif () 69 | 70 | if (AMSG_STD_CXX11 AND NOT WIN32) 71 | set (AMSG_COMPILE_PROP "-std=c++11") 72 | if (APPLE) 73 | set (AMSG_COMPILE_PROP "${AMSG_COMPILE_PROP} -stdlib=libc++") 74 | endif () 75 | endif () 76 | 77 | if (WIN32) 78 | if (${CMAKE_GENERATOR} MATCHES "Visual Studio 11 *" OR ${CMAKE_GENERATOR} MATCHES "Visual Studio 12 *") 79 | set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") 80 | endif () 81 | endif () 82 | 83 | # Build examples. 84 | if (AMSG_BUILD_EXAMPLE) 85 | add_subdirectory (example) 86 | endif () 87 | 88 | # Build tests. 89 | if (AMSG_BUILD_TEST) 90 | add_subdirectory (test) 91 | endif () 92 | endif () 93 | 94 | file (GLOB AMSG_HEADER_FILES "${PROJECT_SOURCE_DIR}/*.hpp") 95 | install ( 96 | FILES ${AMSG_HEADER_FILES} DESTINATION include/amsg 97 | ) 98 | 99 | # Build a CPack driven installer package. 100 | include (InstallRequiredSystemLibraries) 101 | set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt") 102 | set (CPACK_PACKAGE_VERSION_MAJOR "${AMSG_VERSION_MAJOR}") 103 | set (CPACK_PACKAGE_VERSION_MINOR "${AMSG_VERSION_MINOR}") 104 | set (CPACK_PACKAGE_CONTACT "Ning Ding: lordoffox@gmail.com") 105 | include (CPack) 106 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AMSG v2.0 2 | ======= 3 | 4 | AMSG is an C++ serialization library. 5 | 6 | Features Overview 7 | --------------- 8 | 9 | * Lightweight, fast and efficient serialization implementations 10 | * Only one macro to register C++ struct, one line code that's all 11 | * Header only, no need to build library, just three hpp files 12 | * Support C++11 13 | * Default support C++ built-in types and all std containters 14 | 15 | What is AMSG? 16 | --------------- 17 | 18 | ```cpp 19 | struct person 20 | { 21 | std::string name; 22 | int age; 23 | 24 | bool operator==(person const& rhs) const 25 | { 26 | return name == rhs.name && age == rhs.age; 27 | } 28 | }; 29 | 30 | AMSG(person, (name)(age)); 31 | 32 | #define ENOUGH_SIZE 4096 33 | unsigned char buf[ENOUGH_SIZE]; 34 | 35 | // serialize 36 | person src; 37 | src.name = "lordoffox" 38 | src.age = 33 39 | 40 | amsg::zero_copy_buffer writer; 41 | writer.set_write(buf, ENOUGH_SIZE); 42 | amsg::write(writer, src); 43 | assert(!writer.bad()); 44 | 45 | // deserialize 46 | person des; 47 | 48 | amsg::zero_copy_buffer reader; 49 | reader.set_read(buf, ENOUGH_SIZE); 50 | amsg::read(reader, des); 51 | assert(!reader.bad()); 52 | 53 | assert(src == des); 54 | ``` 55 | 56 | Dependencies 57 | ------------ 58 | 59 | * CMake 2.8 and newer 60 | * Boost 1.55.0 and newer (Header only) 61 | 62 | Supported Compilers 63 | ------------------- 64 | 65 | * GCC >= 4.8 66 | * VC >= 12.0 (sp1) 67 | 68 | Require C++11 69 | ------------------- 70 | 71 | ```cpp 72 | #include 73 | 74 | // C++11's forward_list 75 | #include 76 | 77 | std::forward_list fwd_list = {1,2,3,4,5}; 78 | unsigned char buf[4096]; 79 | amsg::zero_copy_buffer writer; 80 | writer.set_write(buf, 4096); 81 | amsg::write(writer, fwd_list); 82 | assert(!writer.bad()); 83 | ``` 84 | 85 | amsg::size_of 86 | ------------------- 87 | 88 | Using amsg::size_of to get object's serialize size 89 | 90 | ```cpp 91 | struct person 92 | { 93 | std::string name; 94 | int age; 95 | 96 | bool operator==(person const& rhs) const 97 | { 98 | return name == rhs.name && age == rhs.age; 99 | } 100 | }; 101 | 102 | AMSG(person, (name)(age)); 103 | 104 | person obj; 105 | std::size_t size = amsg::size_of(obj); 106 | std::cout << "person's serialize size: " << size << std::endl; 107 | ``` 108 | 109 | smax 110 | ------------------- 111 | 112 | Sometimes you want limit max size of an array of string: 113 | 114 | ```cpp 115 | struct person 116 | { 117 | std::string name; 118 | int age; 119 | 120 | bool operator==(person const& rhs) const 121 | { 122 | return name == rhs.name && age == rhs.age; 123 | } 124 | }; 125 | 126 | AMSG(person, (name&smax(30))(age)); // smax(30) limit name string max size is 30 bytes 127 | ``` 128 | 129 | sfix 130 | ------------------- 131 | 132 | Sometimes you want serialization size to be fixed: 133 | 134 | ```cpp 135 | struct person 136 | { 137 | std::string name; 138 | boost::int32_t age; 139 | 140 | bool operator==(person const& rhs) const 141 | { 142 | return name == rhs.name && age == rhs.age; 143 | } 144 | }; 145 | 146 | AMSG(person, (name)(age&sfix)); // sfix enforce age (int32_t) to be 4bytes after serialization 147 | ``` 148 | 149 | If no sfix, age will dependence its value: 150 | -128 to 127 --> 1byte 151 | -32,768 to 32,767 --> 2byte 152 | -2,147,483,648 to 2,147,483,647 --> 4byte 153 | 154 | note: sfix only effect built-in types(int, short, long, char, float, double and so on). 155 | 156 | Change list: 157 | V2.0: 158 | 159 | 1.refact with C++11, less and clean code for human readable. 160 | 161 | 2.add forwards and backwards compatibility. 162 | 163 | -------------------------------------------------------------------------------- /all.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2012 Ning Ding (lordoffox@gmail.com) 3 | /// 4 | /// Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | /// 7 | /// See https://github.com/lordoffox/amsg for latest version. 8 | /// 9 | 10 | #ifndef AMSG_ALL_HPP 11 | #define AMSG_ALL_HPP 12 | 13 | #include "amsg.hpp" 14 | #include "zerocopy.hpp" 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /amsg.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2012 - 2015 Ning Ding (lordoffox@gmail.com) 3 | /// 4 | /// Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | /// 7 | /// See https://github.com/lordoffox/amsg for latest version. 8 | /// 9 | 10 | #ifndef AMSG_AMSG_HPP 11 | #define AMSG_AMSG_HPP 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #ifndef AMSG_INLINE 32 | # ifdef _MSC_VER 33 | # pragma inline_recursion(on) 34 | # define AMSG_INLINE __forceinline 35 | # elif defined(_GUNC_) 36 | # define AMSG_INLINE inline __attribute__((always_inline)) 37 | # else 38 | # define AMSG_INLINE inline 39 | # endif 40 | #endif 41 | 42 | namespace amsg 43 | { 44 | #if _MSC_VER > 1300 45 | #include 46 | 47 | #define byte_swap_16(x) _byteswap_ushort(x) 48 | #define byte_swap_32(x) _byteswap_ulong(x) 49 | #define byte_swap_64(x) _byteswap_uint64(x) 50 | 51 | #elif __GNUC__ >= 3 52 | #include 53 | 54 | #define byte_swap_16(x) bswap_16(x) 55 | #define byte_swap_32(x) bswap_32(x) 56 | #define byte_swap_64(x) bswap_64(x) 57 | #else 58 | template 59 | AMSG_INLINE _ty byte_swap_16(_ty value) 60 | { 61 | value = (value >> 8) | (value << 8); 62 | return value; 63 | } 64 | 65 | template 66 | AMSG_INLINE _ty byte_swap_32(_ty value) 67 | { 68 | value = ((value << 8) & 0xFF00FF00) | ((value >> 8) & 0x00FF00FF); 69 | value = (value >> 16) | (value << 16); 70 | return value; 71 | } 72 | 73 | template 74 | AMSG_INLINE _ty byte_swap_64(_ty value) 75 | { 76 | value = ((value << 8) & 0xFF00FF00FF00FF00ULL) | ((value >> 8) & 0x00FF00FF00FF00FFULL); 77 | value = ((value << 16) & 0xFFFF0000FFFF0000ULL) | ((value >> 16) & 0x0000FFFF0000FFFFULL); 78 | return (value >> 32) | (value << 32); 79 | } 80 | 81 | #endif 82 | 83 | //define endian check macro 84 | 85 | #ifdef _WIN32 86 | #else 87 | #include /* __BYTE_ORDER */ 88 | #endif 89 | 90 | # if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) 91 | # if __BYTE_ORDER == __LITTLE_ENDIAN 92 | # define __LITTLE_ENDIAN__ 93 | # elif __BYTE_ORDER == __BIG_ENDIAN 94 | # define __BIG_ENDIAN__ 95 | # elif _WIN32 96 | # define __LITTLE_ENDIAN__ 97 | # endif 98 | # endif 99 | 100 | #if defined(__LITTLE_ENDIAN__) 101 | #define host_to_little_endian16(value) (value) 102 | #define host_to_little_endian32(value) (value) 103 | #define host_to_little_endian64(value) (value) 104 | #define little_endian_to_host16(value) (value) 105 | #define little_endian_to_host32(value) (value) 106 | #define little_endian_to_host64(value) (value) 107 | #else 108 | #define host_to_little_endian16(value) byte_swap_16(value) 109 | #define host_to_little_endian32(value) byte_swap_32(value) 110 | #define host_to_little_endian64(value) byte_swap_64(value) 111 | #define little_endian_to_host16(value) byte_swap_16(value) 112 | #define little_endian_to_host32(value) byte_swap_32(value) 113 | #define little_endian_to_host64(value) byte_swap_64(value) 114 | #endif 115 | 116 | template 117 | AMSG_INLINE 118 | typename ::std::enable_if::type 119 | le_to_host(const value_type& value) 120 | { 121 | return value; 122 | } 123 | 124 | template 125 | AMSG_INLINE 126 | typename ::std::enable_if::type 127 | le_to_host(const value_type& value) 128 | { 129 | return (value_type)little_endian_to_host16(value); 130 | } 131 | 132 | template 133 | AMSG_INLINE 134 | typename ::std::enable_if::type 135 | le_to_host(const value_type& value) 136 | { 137 | return (value_type)little_endian_to_host32((uint32_t)value); 138 | } 139 | 140 | template 141 | AMSG_INLINE 142 | typename ::std::enable_if::type 143 | le_to_host(const value_type& value) 144 | { 145 | return (value_type)little_endian_to_host64((uint64_t)value); 146 | } 147 | 148 | AMSG_INLINE float le_to_host(const float& value) 149 | { 150 | union { uint32_t uv; float fv; }u; 151 | u.fv = value; 152 | u.uv = little_endian_to_host32(u.uv); 153 | return u.fv; 154 | } 155 | 156 | AMSG_INLINE double le_to_host(const double& value) 157 | { 158 | union { uint32_t uv; double fv; }u; 159 | u.fv = value; 160 | u.uv = little_endian_to_host64(u.uv); 161 | return u.fv; 162 | } 163 | 164 | template::type = 0 166 | > 167 | AMSG_INLINE value_type host_to_le(const value_type& value) 168 | { 169 | return value; 170 | } 171 | 172 | template::type = 0 174 | > 175 | AMSG_INLINE value_type host_to_le(const value_type& value) 176 | { 177 | return (value_type)host_to_little_endian16(value); 178 | } 179 | 180 | template::type = 0 182 | > 183 | AMSG_INLINE value_type host_to_le(const value_type& value) 184 | { 185 | return (value_type)host_to_little_endian32((uint32_t)value); 186 | } 187 | 188 | template::type = 0 190 | > 191 | AMSG_INLINE value_type host_to_le(const value_type& value) 192 | { 193 | return (value_type)host_to_little_endian64((uint64_t)value); 194 | } 195 | 196 | AMSG_INLINE float host_to_le(const float& value) 197 | { 198 | union { uint32_t uv; float fv; }u; 199 | u.fv = value; 200 | u.uv = host_to_little_endian32(u.uv); 201 | return u.fv; 202 | } 203 | 204 | AMSG_INLINE double host_to_le(const double& value) 205 | { 206 | union { uint32_t uv; double fv; }u; 207 | u.fv = value; 208 | u.uv = host_to_little_endian64(u.uv); 209 | return u.fv; 210 | } 211 | 212 | static size_t to_str(const uint32_t& Value, char * resultbuffer, size_t len) 213 | { 214 | uint32_t temp = Value; 215 | resultbuffer[len - 1] = 0; 216 | size_t pos = len - 2; 217 | if (temp == 0) 218 | { 219 | resultbuffer[pos--] = '0'; 220 | } 221 | while (temp) 222 | { 223 | resultbuffer[pos--] = (char)((temp % 10) + '0'); 224 | temp = temp / 10; 225 | } 226 | ++pos; 227 | memmove(resultbuffer, resultbuffer + pos, (len - pos)); 228 | return len - pos; 229 | } 230 | 231 | enum error_code_t 232 | { 233 | success = 0, 234 | negative_assign_to_unsigned_integer_number, 235 | value_too_large_to_integer_number, 236 | sequence_length_overflow, 237 | stream_buffer_overflow, 238 | number_of_element_not_macth 239 | }; 240 | 241 | struct basic_store 242 | { 243 | 244 | basic_store() 245 | : m_error_code(success) 246 | { 247 | 248 | } 249 | 250 | AMSG_INLINE error_code_t error_code() const 251 | { 252 | return m_error_code; 253 | } 254 | 255 | AMSG_INLINE void set_error_code(error_code_t value) 256 | { 257 | m_error_code = value; 258 | } 259 | 260 | AMSG_INLINE const char * message() 261 | { 262 | switch (m_error_code) 263 | { 264 | case success: 265 | break; 266 | case negative_assign_to_unsigned_integer_number: 267 | return "can't assign negative number to unsigned integer number."; 268 | case value_too_large_to_integer_number: 269 | return "value too large to integer number"; 270 | case sequence_length_overflow: 271 | return "sequence length overflow"; 272 | case stream_buffer_overflow: 273 | return "stream buffer overflow"; 274 | case number_of_element_not_macth: 275 | return "number of element not macth"; 276 | default: 277 | break; 278 | } 279 | return ""; 280 | } 281 | 282 | AMSG_INLINE bool error() const // true if error 283 | { 284 | return m_error_code != success; 285 | } 286 | 287 | AMSG_INLINE void clear() 288 | { 289 | m_error_code = success; 290 | } 291 | 292 | error_code_t m_error_code; 293 | }; 294 | 295 | template< typename stream_ty, typename error_string_ty = ::std::string > 296 | struct store : public basic_store 297 | { 298 | public: 299 | store(stream_ty& stream) 300 | : basic_store() 301 | , m_stream(stream) 302 | { 303 | } 304 | 305 | AMSG_INLINE const error_string_ty& info() const { return this->m_error_info; } 306 | 307 | AMSG_INLINE void append_debug_info(const char * info) 308 | { 309 | this->m_error_info.append(info); 310 | } 311 | 312 | AMSG_INLINE bool bad()const { return this->m_stream.bad(); } 313 | 314 | AMSG_INLINE ::std::size_t read(char * buffer, ::std::size_t len) 315 | { 316 | return this->m_stream.read(buffer, len); 317 | } 318 | 319 | AMSG_INLINE ::std::size_t write(const char * buffer, ::std::size_t len) 320 | { 321 | return this->m_stream.write(buffer, len); 322 | } 323 | 324 | AMSG_INLINE void skip_read(::std::size_t len) 325 | { 326 | this->m_stream.seekg(len); 327 | } 328 | 329 | AMSG_INLINE ::std::size_t read_length() 330 | { 331 | return this->m_stream.tellg(); 332 | } 333 | 334 | AMSG_INLINE ::std::size_t write_length() 335 | { 336 | return this->m_stream.tellp(); 337 | } 338 | 339 | AMSG_INLINE void clear() 340 | { 341 | basic_store::clear(); 342 | this->m_stream.clear(); 343 | this->m_error_info.clear(); 344 | } 345 | 346 | private: 347 | stream_ty& m_stream; 348 | error_string_ty m_error_info; 349 | }; 350 | 351 | template 352 | AMSG_INLINE store make_store(stream_ty& stream) 353 | { 354 | return store(stream); 355 | } 356 | 357 | enum 358 | { 359 | const_interger_byte_msak = 0x3f, 360 | const_negative_bit_value = 0x40, 361 | const_tag_as_value = 0x7f, 362 | const_tag_as_type, 363 | const_store_postive_integer_byte_mask = 0x80 - 2, 364 | const_store_negative_integer_byte_mask = 0x80 + const_negative_bit_value - 2 365 | }; 366 | 367 | template 368 | struct sfix_op 369 | { 370 | value_type& val; 371 | sfix_op(value_type& value) 372 | :val(value) 373 | {} 374 | sfix_op(const sfix_op& rv) 375 | :val(rv.val) 376 | {} 377 | 378 | sfix_op& operator = (const sfix_op& rv) 379 | { 380 | val = rv.val; 381 | } 382 | }; 383 | 384 | struct sfix_def{}; 385 | 386 | namespace 387 | { 388 | static sfix_def sfix = sfix_def(); 389 | } 390 | 391 | template 392 | AMSG_INLINE sfix_op operator & (ty& value, const sfix_def&) 393 | { 394 | sfix_op op(value); 395 | return op; 396 | } 397 | 398 | template 399 | struct smax_valid 400 | { 401 | uint32_t size; 402 | value_type & val; 403 | smax_valid(uint32_t max, value_type& value) 404 | :size(max), val(value) 405 | {} 406 | smax_valid(smax_valid& rv) 407 | :size(rv.size), val(rv.val) 408 | {} 409 | 410 | smax_valid& operator = (const smax_valid& rv) 411 | { 412 | size = rv.size; 413 | val = rv.val; 414 | } 415 | }; 416 | 417 | struct smax 418 | { 419 | uint32_t size; 420 | smax(uint32_t max = 0) 421 | :size(max) 422 | {} 423 | }; 424 | 425 | template 426 | AMSG_INLINE smax_valid operator & (ty& value, const smax& sm) 427 | { 428 | smax_valid valid(sm.size, value); 429 | return valid; 430 | } 431 | 432 | template 433 | AMSG_INLINE bool can_skip(const value_type&) 434 | { 435 | return false; 436 | } 437 | 438 | AMSG_INLINE uint32_t size_of(bool) 439 | { 440 | return 1; 441 | } 442 | 443 | template 444 | AMSG_INLINE void skip_read(store_ty& store_data, bool*) 445 | { 446 | store_data.skip_read(1); 447 | if (store_data.bad()) 448 | { 449 | store_data.set_error_code(stream_buffer_overflow); 450 | return; 451 | } 452 | return; 453 | } 454 | 455 | template 456 | AMSG_INLINE void read(store_ty& store_data, bool& value) 457 | { 458 | store_data.read((char*)&value, 1); 459 | if (store_data.bad()) 460 | { 461 | store_data.set_error_code(stream_buffer_overflow); 462 | return; 463 | } 464 | return; 465 | } 466 | 467 | template 468 | AMSG_INLINE void write(store_ty& store_data, const bool& value) 469 | { 470 | uint8_t val = value ? 1 : 0; 471 | store_data.write((char*)&value, 1); 472 | if (store_data.bad()) 473 | { 474 | store_data.set_error_code(stream_buffer_overflow); 475 | return; 476 | } 477 | return; 478 | } 479 | 480 | template 481 | AMSG_INLINE 482 | typename ::std::enable_if<::std::is_signed::value && ::std::is_integral::value, uint32_t>::type 483 | size_of(const value_type& value) 484 | { 485 | if (0 <= value && value < const_tag_as_type) 486 | { 487 | return 1; 488 | } 489 | else 490 | { 491 | value_type temp = value; 492 | if (value < 0) 493 | { 494 | temp = -value; 495 | } 496 | if (temp < 0x100) 497 | { 498 | return 2; 499 | } 500 | else if (temp < 0x10000) 501 | { 502 | return 3; 503 | } 504 | else if (temp < 0x1000000) 505 | { 506 | return 4; 507 | } 508 | else if (temp < 0x100000000) 509 | { 510 | return 5; 511 | } 512 | else if (temp < 0x10000000000LL) 513 | { 514 | return 6; 515 | } 516 | else if (temp < 0x1000000000000LL) 517 | { 518 | return 7; 519 | } 520 | else if (temp < 0x100000000000000LL) 521 | { 522 | return 8; 523 | } 524 | } 525 | return 9; 526 | } 527 | 528 | template 529 | AMSG_INLINE 530 | typename ::std::enable_if<::std::is_integral::value, void>::type 531 | skip_read(store_ty& store_data, value_type *) 532 | { 533 | uint8_t tag; 534 | store_data.read((char*)&tag, 1); 535 | if (store_data.bad()) 536 | { 537 | store_data.set_error_code(stream_buffer_overflow); 538 | return; 539 | } 540 | if (tag > const_tag_as_value) 541 | { 542 | int read_bytes = (tag & const_interger_byte_msak) + 1; 543 | store_data.skip_read(read_bytes); 544 | if (store_data.bad()) 545 | { 546 | store_data.set_error_code(stream_buffer_overflow); 547 | return; 548 | } 549 | } 550 | } 551 | 552 | template 553 | AMSG_INLINE 554 | typename ::std::enable_if<::std::is_signed::value && ::std::is_integral::value, void>::type 555 | read(store_ty& store_data, value_type& value) 556 | { 557 | const int bytes = sizeof(value_type); 558 | value_type read_value[2] = { 0 }; 559 | uint8_t * ptr = (uint8_t *)read_value; 560 | store_data.read((char*)ptr, 1); 561 | if (store_data.bad()) 562 | { 563 | store_data.set_error_code(stream_buffer_overflow); 564 | return; 565 | } 566 | value = *ptr; 567 | if (value > const_tag_as_value) 568 | { 569 | int sign = 1; 570 | if ((long)value & const_negative_bit_value) 571 | { 572 | sign = -1; 573 | } 574 | int read_bytes = (value & const_interger_byte_msak) + 1; 575 | if (bytes < read_bytes) 576 | { 577 | store_data.set_error_code(value_too_large_to_integer_number); 578 | return; 579 | } 580 | ptr = (uint8_t *)&read_value[1]; 581 | store_data.read((char*)ptr, read_bytes); 582 | if (store_data.bad()) 583 | { 584 | store_data.set_error_code(stream_buffer_overflow); 585 | return; 586 | } 587 | if (sign < 0) 588 | { 589 | value = -(value_type)le_to_host(read_value[1]); 590 | } 591 | else 592 | { 593 | value = le_to_host(read_value[1]); 594 | } 595 | } 596 | } 597 | 598 | template 599 | AMSG_INLINE 600 | typename ::std::enable_if<::std::is_signed::value && ::std::is_integral::value, void>::type 601 | write(store_ty& store_data, const value_type& value) 602 | { 603 | value_type write_value[2] = { 0 }; 604 | int write_bytes = 0; 605 | uint8_t * ptr = (uint8_t *)write_value; 606 | uint8_t tag = static_cast(value); 607 | write_bytes = 1; 608 | if (0 <= value && value < const_tag_as_type) 609 | { 610 | write_value[0] = tag; 611 | } 612 | else 613 | { 614 | uint8_t negative_bit = 0; 615 | value_type temp = value; 616 | if (value < 0) 617 | { 618 | negative_bit = const_negative_bit_value; 619 | temp = -value; 620 | } 621 | write_value[1] = host_to_le(temp); 622 | ptr = (uint8_t *)(&write_value[1]) - 1; 623 | if (temp < 0x100) 624 | { 625 | write_bytes = 2; 626 | } 627 | else if (temp < 0x10000) 628 | { 629 | write_bytes = 3; 630 | } 631 | else if (temp < 0x1000000) 632 | { 633 | write_bytes = 4; 634 | } 635 | else if (temp < 0x100000000) 636 | { 637 | write_bytes = 5; 638 | } 639 | else if (temp < 0x10000000000LL) 640 | { 641 | write_bytes = 6; 642 | } 643 | else if (temp < 0x1000000000000LL) 644 | { 645 | write_bytes = 7; 646 | } 647 | else if (temp < 0x100000000000000LL) 648 | { 649 | write_bytes = 8; 650 | } 651 | else 652 | { 653 | write_bytes = 9; 654 | } 655 | *ptr = const_store_postive_integer_byte_mask + negative_bit + write_bytes; 656 | } 657 | store_data.write((const char *)ptr, write_bytes); 658 | if (store_data.bad()) 659 | { 660 | store_data.set_error_code(stream_buffer_overflow); 661 | return; 662 | } 663 | } 664 | 665 | template 666 | AMSG_INLINE 667 | typename ::std::enable_if<::std::is_unsigned::value && ::std::is_integral::value, uint32_t>::type 668 | size_of(const value_type& value) 669 | { 670 | if (value < const_tag_as_type) 671 | { 672 | return 1; 673 | } 674 | else 675 | { 676 | if (value < 0x100) 677 | { 678 | return 2; 679 | } 680 | else if (value < 0x10000) 681 | { 682 | return 3; 683 | } 684 | else if (value < 0x1000000) 685 | { 686 | return 4; 687 | } 688 | else if (value < 0x100000000) 689 | { 690 | return 5; 691 | } 692 | else if (value < 0x10000000000LL) 693 | { 694 | return 6; 695 | } 696 | else if (value < 0x1000000000000LL) 697 | { 698 | return 7; 699 | } 700 | else if (value < 0x100000000000000LL) 701 | { 702 | return 8; 703 | } 704 | } 705 | return 9; 706 | } 707 | 708 | template 709 | AMSG_INLINE 710 | typename ::std::enable_if<::std::is_unsigned::value && ::std::is_integral::value, void>::type 711 | read(store_ty& store_data, value_type& value) 712 | { 713 | const int bytes = sizeof(value_type); 714 | value_type read_value[2] = { 0 }; 715 | uint8_t * ptr = (uint8_t *)read_value; 716 | store_data.read((char*)ptr, 1); 717 | if (store_data.bad()) 718 | { 719 | store_data.set_error_code(stream_buffer_overflow); 720 | return; 721 | } 722 | value = *ptr; 723 | if (value > const_tag_as_value) 724 | { 725 | if ((long)value & const_negative_bit_value) 726 | { 727 | store_data.set_error_code(negative_assign_to_unsigned_integer_number); 728 | return; 729 | 730 | } 731 | int read_bytes = int(value & const_interger_byte_msak) + 1; 732 | if (bytes < read_bytes) 733 | { 734 | store_data.set_error_code(value_too_large_to_integer_number); 735 | return; 736 | } 737 | ptr = (uint8_t *)&read_value[1]; 738 | store_data.read((char*)ptr, read_bytes); 739 | if (store_data.bad()) 740 | { 741 | store_data.set_error_code(stream_buffer_overflow); 742 | return; 743 | } 744 | value = le_to_host(read_value[1]); 745 | } 746 | } 747 | 748 | template 749 | AMSG_INLINE 750 | typename ::std::enable_if<::std::is_unsigned::value && ::std::is_integral::value, void>::type 751 | write(store_ty& store_data, const value_type& value) 752 | { 753 | value_type write_value[2] = { 0 }; 754 | int write_bytes = 0; 755 | uint8_t * ptr = (uint8_t *)write_value; 756 | uint8_t tag = static_cast(value); 757 | write_bytes = 1; 758 | if (value < const_tag_as_type) 759 | { 760 | write_value[0] = tag; 761 | } 762 | else 763 | { 764 | write_value[1] = host_to_le(value); 765 | ptr = (uint8_t *)(&write_value[1]) - 1; 766 | if (value < 0x100) 767 | { 768 | write_bytes = 2; 769 | } 770 | else if (value < 0x10000) 771 | { 772 | write_bytes = 3; 773 | } 774 | else if (value < 0x1000000) 775 | { 776 | write_bytes = 4; 777 | } 778 | else if (value < 0x100000000) 779 | { 780 | write_bytes = 5; 781 | } 782 | else if (value < 0x10000000000LL) 783 | { 784 | write_bytes = 6; 785 | } 786 | else if (value < 0x1000000000000LL) 787 | { 788 | write_bytes = 7; 789 | } 790 | else if (value < 0x100000000000000LL) 791 | { 792 | write_bytes = 8; 793 | } 794 | else 795 | { 796 | write_bytes = 9; 797 | } 798 | *ptr = (uint8_t)(const_store_postive_integer_byte_mask + write_bytes); 799 | } 800 | store_data.write((const char *)ptr, write_bytes); 801 | if (store_data.bad()) 802 | { 803 | store_data.set_error_code(stream_buffer_overflow); 804 | return; 805 | } 806 | } 807 | 808 | template 809 | AMSG_INLINE 810 | typename ::std::enable_if<::std::is_enum::value, uint32_t>::type 811 | size_of(const value_type& value) 812 | { 813 | return size_of((int64_t)value); 814 | } 815 | 816 | template 817 | AMSG_INLINE 818 | typename ::std::enable_if<::std::is_enum::value, void>::type 819 | read(store_ty& store_data, value_type& value) 820 | { 821 | int64_t data; 822 | read(store_data, data); 823 | value = static_cast(data); 824 | } 825 | 826 | template 827 | AMSG_INLINE 828 | typename ::std::enable_if<::std::is_enum::value, void>::type 829 | write(store_ty& store_data, const value_type& value) 830 | { 831 | int64_t data = static_cast(value); 832 | write(store_data, data); 833 | } 834 | 835 | AMSG_INLINE uint32_t size_of(const float&) 836 | { 837 | return sizeof(float); 838 | } 839 | 840 | template 841 | AMSG_INLINE void skip_read(store_ty& store_data, float *) 842 | { 843 | store_data.skip_read(sizeof(float)); 844 | if (store_data.bad()) 845 | { 846 | store_data.set_error_code(stream_buffer_overflow); 847 | } 848 | } 849 | 850 | template 851 | AMSG_INLINE void read(store_ty& store_data, float& value) 852 | { 853 | store_data.read((char*)&value, sizeof(float)); 854 | if (store_data.bad()) 855 | { 856 | store_data.set_error_code(stream_buffer_overflow); 857 | } 858 | value = le_to_host(value); 859 | } 860 | 861 | template 862 | AMSG_INLINE void write(store_ty& store_data, const float& value) 863 | { 864 | float data = host_to_le(value); 865 | store_data.write((char*)&data, sizeof(double)); 866 | if (store_data.bad()) 867 | { 868 | store_data.set_error_code(stream_buffer_overflow); 869 | } 870 | } 871 | 872 | AMSG_INLINE uint32_t size_of(const double&) 873 | { 874 | return sizeof(double); 875 | } 876 | 877 | template 878 | AMSG_INLINE void skip_read(store_ty& store_data, double *) 879 | { 880 | store_data.skip_read(sizeof(double)); 881 | if (store_data.bad()) 882 | { 883 | store_data.set_error_code(stream_buffer_overflow); 884 | } 885 | } 886 | 887 | template 888 | AMSG_INLINE void read(store_ty& store_data, double& value) 889 | { 890 | store_data.read((char*)&value, sizeof(double)); 891 | if (store_data.bad()) 892 | { 893 | store_data.set_error_code(stream_buffer_overflow); 894 | } 895 | value = le_to_host(value); 896 | } 897 | 898 | template 899 | AMSG_INLINE void write(store_ty& store_data, const double& value) 900 | { 901 | double data = host_to_le(value); 902 | store_data.write((char*)&data, sizeof(double)); 903 | if (store_data.bad()) 904 | { 905 | store_data.set_error_code(stream_buffer_overflow); 906 | } 907 | } 908 | 909 | template 910 | AMSG_INLINE uint32_t size_of(const ::std::basic_string, alloc_ty>& value, uint32_t max = 0) 911 | { 912 | (max); 913 | uint32_t len = (uint32_t)value.length(); 914 | return size_of(len) + len; 915 | } 916 | 917 | template 918 | AMSG_INLINE bool can_skip(const ::std::basic_string, alloc_ty>& value) 919 | { 920 | return value.empty(); 921 | } 922 | 923 | template 924 | AMSG_INLINE void skip_read(store_ty& store_data, ::std::basic_string, alloc_ty>*, uint32_t max = 0) 925 | { 926 | (max); 927 | uint32_t len; 928 | read(store_data, len); 929 | if (store_data.error()) 930 | { 931 | return; 932 | } 933 | store_data.skip_read(len); 934 | } 935 | 936 | template 937 | AMSG_INLINE void read(store_ty& store_data, ::std::basic_string, alloc_ty>& value, uint32_t max = 0) 938 | { 939 | uint32_t len; 940 | read(store_data, len); 941 | if (store_data.bad()) 942 | { 943 | store_data.set_error_code(stream_buffer_overflow); 944 | return; 945 | } 946 | if (max > 0 && max < len) 947 | { 948 | store_data.set_error_code(sequence_length_overflow); 949 | return; 950 | } 951 | value.resize(len); 952 | store_data.read((char*)value.data(), len); 953 | if (store_data.bad()) 954 | { 955 | store_data.set_error_code(stream_buffer_overflow); 956 | return; 957 | } 958 | } 959 | 960 | template 961 | void write(store_ty& store_data, const ::std::basic_string, alloc_ty>& value, uint32_t max = 0) 962 | { 963 | uint32_t len = (uint32_t)value.length(); 964 | if (max > 0 && max < len) 965 | { 966 | store_data.set_error_code(sequence_length_overflow); 967 | return; 968 | } 969 | write(store_data, len); 970 | if (store_data.bad()) 971 | { 972 | store_data.set_error_code(stream_buffer_overflow); 973 | return; 974 | } 975 | store_data.write(value.data(), len); 976 | if (store_data.bad()) 977 | { 978 | store_data.set_error_code(stream_buffer_overflow); 979 | return; 980 | } 981 | } 982 | 983 | template 984 | struct is_sequence_container : public ::std::false_type{}; 985 | 986 | template 987 | struct is_sequence_container< ::std::deque > : public ::std::true_type{}; 988 | 989 | template 990 | struct is_sequence_container< ::std::list > : public ::std::true_type{}; 991 | 992 | template 993 | struct is_sequence_container< ::std::vector > : public ::std::true_type{}; 994 | 995 | template 996 | struct is_sequence_container< ::std::forward_list > : public ::std::true_type{}; 997 | 998 | template 999 | AMSG_INLINE 1000 | typename ::std::enable_if::value, uint32_t>::type 1001 | size_of(const value_type& value, uint32_t max = 0) 1002 | { 1003 | (max); 1004 | uint32_t len = 0; 1005 | uint32_t size = 0; 1006 | for (typename value_type::const_iterator i = value.begin(); i != value.end(); ++i, ++len) 1007 | { 1008 | size += size_of(*i); 1009 | } 1010 | return size + size_of(len); 1011 | } 1012 | 1013 | // template 1014 | // AMSG_INLINE 1015 | // typename ::std::enable_if::value, bool>::type 1016 | // can_skip(const value_type& value) 1017 | // { 1018 | // return value.empty(); 1019 | // } 1020 | 1021 | template 1022 | AMSG_INLINE bool can_skip(const ::std::deque& value) 1023 | { 1024 | return value.empty(); 1025 | } 1026 | 1027 | template 1028 | AMSG_INLINE bool can_skip(const ::std::list& value) 1029 | { 1030 | return value.empty(); 1031 | } 1032 | 1033 | template 1034 | AMSG_INLINE bool can_skip(const ::std::vector& value) 1035 | { 1036 | return value.empty(); 1037 | } 1038 | 1039 | template 1040 | AMSG_INLINE bool can_skip(const ::std::forward_list& value) 1041 | { 1042 | return value.empty(); 1043 | } 1044 | 1045 | template 1046 | AMSG_INLINE 1047 | typename ::std::enable_if::value, void>::type 1048 | skip_read(store_ty& store_data, value_type*, uint32_t max = 0) 1049 | { 1050 | (max); 1051 | uint32_t len; 1052 | read(store_data, len); 1053 | if (store_data.error()) 1054 | { 1055 | return; 1056 | } 1057 | for (uint32_t i = 0; i < len; ++i) 1058 | { 1059 | typename value_type::value_type* elem_value = nullptr; 1060 | skip_read(elem_value); 1061 | } 1062 | } 1063 | 1064 | template 1065 | AMSG_INLINE 1066 | typename ::std::enable_if::value, void>::type 1067 | read(store_ty& store_data, value_type& value, uint32_t max = 0) 1068 | { 1069 | uint32_t len; 1070 | read(store_data, len); 1071 | if (store_data.bad()) 1072 | { 1073 | store_data.set_error_code(stream_buffer_overflow); 1074 | return; 1075 | } 1076 | if (max > 0 && max < len) 1077 | { 1078 | store_data.set_error_code(sequence_length_overflow); 1079 | return; 1080 | } 1081 | value.resize(len); 1082 | uint32_t c = 0; 1083 | for (typename value_type::iterator i = value.begin(); i != value.end(); ++i, ++c) 1084 | { 1085 | typename value_type::value_type& elem_value = *i; 1086 | read(store_data, elem_value); 1087 | if (store_data.error()) 1088 | { 1089 | char buffer[64]; 1090 | to_str(c, buffer, 64); 1091 | store_data.append_debug_info("["); 1092 | store_data.append_debug_info(buffer); 1093 | store_data.append_debug_info("]"); 1094 | return; 1095 | } 1096 | } 1097 | } 1098 | 1099 | template 1100 | AMSG_INLINE 1101 | typename ::std::enable_if::value, void>::type 1102 | write(store_ty& store_data, const value_type& value, uint32_t max = 0) 1103 | { 1104 | uint32_t len = (uint32_t)value.size(); 1105 | if (max > 0 && max < len) 1106 | { 1107 | store_data.set_error_code(sequence_length_overflow); 1108 | return; 1109 | } 1110 | write(store_data, len); 1111 | if (store_data.bad()) 1112 | { 1113 | store_data.set_error_code(stream_buffer_overflow); 1114 | return; 1115 | } 1116 | uint32_t c = 0; 1117 | for (typename value_type::const_iterator i = value.begin(); i != value.end(); ++i, ++c) 1118 | { 1119 | const typename value_type::value_type& elem_value = *i; 1120 | write(store_data, elem_value); 1121 | if (store_data.error()) 1122 | { 1123 | char buffer[64]; 1124 | to_str(c, buffer, 64); 1125 | store_data.append_debug_info("["); 1126 | store_data.append_debug_info(buffer); 1127 | store_data.append_debug_info("]"); 1128 | return; 1129 | } 1130 | } 1131 | } 1132 | 1133 | template 1134 | struct is_array : public ::std::false_type{}; 1135 | 1136 | template 1137 | struct is_array< ::std::array > : public ::std::true_type{}; 1138 | 1139 | template 1140 | AMSG_INLINE 1141 | typename ::std::enable_if::value, uint32_t>::type 1142 | size_of(const value_type& value, uint32_t max = 0) 1143 | { 1144 | (max); 1145 | uint32_t size = (uint32_t)value.size(); 1146 | size = size_of(size); 1147 | for (typename value_type::const_iterator i = value.begin(); i != value.end(); ++i) 1148 | { 1149 | size += size_of(*i); 1150 | } 1151 | return size; 1152 | } 1153 | 1154 | template 1155 | AMSG_INLINE 1156 | typename ::std::enable_if::value, void>::type 1157 | skip_read(store_ty& store_data, value_type*, uint32_t max = 0) 1158 | { 1159 | (max); 1160 | uint32_t len; 1161 | read(store_data, len); 1162 | if (store_data.error()) 1163 | { 1164 | return; 1165 | } 1166 | for (uint32_t i = 0; i < len; ++i) 1167 | { 1168 | typename value_type::value_type* elem_value = nullptr; 1169 | skip_read(elem_value); 1170 | } 1171 | } 1172 | 1173 | template 1174 | AMSG_INLINE 1175 | typename ::std::enable_if::value, void>::type 1176 | read(store_ty& store_data, value_type& value, uint32_t max = 0) 1177 | { 1178 | uint32_t len; 1179 | read(store_data, len); 1180 | if (store_data.bad()) 1181 | { 1182 | store_data.set_error_code(stream_buffer_overflow); 1183 | return; 1184 | } 1185 | if (max > 0 && max < len) 1186 | { 1187 | store_data.set_error_code(sequence_length_overflow); 1188 | return; 1189 | } 1190 | uint32_t c = 0; 1191 | for (typename value_type::iterator i = value.begin(); i != value.end(); ++i, ++c) 1192 | { 1193 | typename value_type::value_type& elem_value = *i; 1194 | read(store_data, elem_value); 1195 | if (store_data.error()) 1196 | { 1197 | char buffer[64]; 1198 | to_str(c, buffer, 64); 1199 | store_data.append_debug_info("["); 1200 | store_data.append_debug_info(buffer); 1201 | store_data.append_debug_info("]"); 1202 | return; 1203 | } 1204 | } 1205 | for (; c < len; ++c) 1206 | { 1207 | typename value_type::value_type* elem_value = nullptr; 1208 | skip_read(store_data, elem_value); 1209 | } 1210 | } 1211 | 1212 | template 1213 | AMSG_INLINE 1214 | typename ::std::enable_if::value, void>::type 1215 | write(store_ty& store_data, const value_type& value, uint32_t max = 0) 1216 | { 1217 | uint32_t len = (uint32_t)value.size(); 1218 | if (max > 0 && max < len) 1219 | { 1220 | store_data.set_error_code(sequence_length_overflow); 1221 | return; 1222 | } 1223 | write(store_data, len); 1224 | if (store_data.bad()) 1225 | { 1226 | store_data.set_error_code(stream_buffer_overflow); 1227 | return; 1228 | } 1229 | uint32_t c = 0; 1230 | for (typename value_type::const_iterator i = value.begin(); i != value.end(); ++i, ++c) 1231 | { 1232 | const typename value_type::value_type& elem_value = *i; 1233 | write(store_data, elem_value); 1234 | if (store_data.error()) 1235 | { 1236 | char buffer[64]; 1237 | to_str(c, buffer, 64); 1238 | store_data.append_debug_info("["); 1239 | store_data.append_debug_info(buffer); 1240 | store_data.append_debug_info("]"); 1241 | return; 1242 | } 1243 | } 1244 | } 1245 | 1246 | template 1247 | struct is_unordered_container : public ::std::false_type{}; 1248 | 1249 | template 1250 | struct is_unordered_container< ::std::map > : public ::std::true_type{}; 1251 | 1252 | template 1253 | struct is_unordered_container< ::std::unordered_map > : public ::std::true_type{}; 1254 | 1255 | template 1256 | AMSG_INLINE 1257 | typename ::std::enable_if::value, uint32_t>::type 1258 | size_of(const value_type& value, uint32_t max = 0) 1259 | { 1260 | (max); 1261 | uint32_t len = 0; 1262 | uint32_t size = 0; 1263 | for (typename value_type::const_iterator i = value.begin(); i != value.end(); ++i, ++len) 1264 | { 1265 | size += size_of(i->first); 1266 | size += size_of(i->second); 1267 | } 1268 | return size + size_of(len); 1269 | } 1270 | 1271 | // template 1272 | // AMSG_INLINE 1273 | // typename ::std::enable_if::value, bool>::type 1274 | // can_skip(const value_type value) 1275 | // { 1276 | // return value.empty(); 1277 | // } 1278 | 1279 | template 1280 | AMSG_INLINE bool can_skip(const ::std::map& value) 1281 | { 1282 | return value.empty(); 1283 | } 1284 | 1285 | template 1286 | AMSG_INLINE bool can_skip(const ::std::unordered_map& value) 1287 | { 1288 | return value.empty(); 1289 | } 1290 | 1291 | template 1292 | AMSG_INLINE 1293 | typename ::std::enable_if::value, void>::type 1294 | skip_read(store_ty& store_data, value_type*, uint32_t max = 0) 1295 | { 1296 | (max); 1297 | uint32_t len; 1298 | read(store_data, len); 1299 | if (store_data.error()) 1300 | { 1301 | return; 1302 | } 1303 | for (uint32_t i = 0; i < len; ++i) 1304 | { 1305 | typename value_type::value_type::first_type* value1 = nullptr; 1306 | typename value_type::value_type::second_type* value2 = nullptr; 1307 | skip_read(value1); 1308 | skip_read(value2); 1309 | } 1310 | } 1311 | 1312 | template 1313 | AMSG_INLINE 1314 | typename ::std::enable_if::value, void>::type 1315 | read(store_ty& store_data, value_type& value, uint32_t max = 0) 1316 | { 1317 | uint32_t len; 1318 | read(store_data, len); 1319 | if (store_data.bad()) 1320 | { 1321 | store_data.set_error_code(stream_buffer_overflow); 1322 | return; 1323 | } 1324 | if (max > 0 && max < len) 1325 | { 1326 | store_data.set_error_code(sequence_length_overflow); 1327 | return; 1328 | } 1329 | for (uint32_t c = 0; c < len; ++c) 1330 | { 1331 | typename ::std::remove_const::type value1; 1332 | typename value_type::value_type::second_type value2; 1333 | read(store_data, value1); 1334 | if (!store_data.error()) 1335 | { 1336 | read(store_data, value2); 1337 | if (!store_data.error()) 1338 | { 1339 | value.insert(std::make_pair(value1, value2)); 1340 | } 1341 | } 1342 | if (store_data.error()) 1343 | { 1344 | char buffer[64]; 1345 | to_str(c, buffer, 64); 1346 | store_data.append_debug_info("["); 1347 | store_data.append_debug_info(buffer); 1348 | store_data.append_debug_info("]"); 1349 | return; 1350 | } 1351 | } 1352 | } 1353 | 1354 | template 1355 | AMSG_INLINE 1356 | typename ::std::enable_if::value, void>::type 1357 | write(store_ty& store_data, const value_type& value, uint32_t max = 0) 1358 | { 1359 | uint32_t len = (uint32_t)value.size(); 1360 | if (max > 0 && max < len) 1361 | { 1362 | store_data.set_error_code(sequence_length_overflow); 1363 | return; 1364 | } 1365 | write(store_data, len); 1366 | if (store_data.bad()) 1367 | { 1368 | store_data.set_error_code(stream_buffer_overflow); 1369 | return; 1370 | } 1371 | uint32_t c = 0; 1372 | for (typename value_type::const_iterator i = value.begin(); i != value.end(); ++i, ++c) 1373 | { 1374 | const typename value_type::value_type::first_type& value1 = i->first; 1375 | const typename value_type::value_type::second_type& value2 = i->second; 1376 | write(store_data, value1); 1377 | if (!store_data.error()) 1378 | { 1379 | write(store_data, value2); 1380 | } 1381 | if (store_data.error()) 1382 | { 1383 | char buffer[64]; 1384 | to_str(c, buffer, 64); 1385 | store_data.append_debug_info("["); 1386 | store_data.append_debug_info(buffer); 1387 | store_data.append_debug_info("]"); 1388 | return; 1389 | } 1390 | } 1391 | } 1392 | 1393 | template 1394 | AMSG_INLINE 1395 | typename ::std::enable_if<::std::is_integral::value, uint32_t>::type 1396 | size_of(const sfix_op& value) 1397 | { 1398 | (value); 1399 | return sizeof(value.val); 1400 | } 1401 | 1402 | template 1403 | AMSG_INLINE 1404 | typename ::std::enable_if<::std::is_integral::value, void>::type 1405 | skip_read(store_ty& store_data, sfix_op&) 1406 | { 1407 | store_data.skip_read(sizeof(value_type)); 1408 | if (store_data.bad()) 1409 | { 1410 | store_data.set_error_code(stream_buffer_overflow); 1411 | } 1412 | } 1413 | 1414 | template 1415 | AMSG_INLINE 1416 | typename ::std::enable_if<::std::is_integral::value, void>::type 1417 | read(store_ty& store_data, const sfix_op& value) 1418 | { 1419 | store_data.read((char*)&(value.val), sizeof(value_type)); 1420 | value.val = le_to_host(value.val); 1421 | if (store_data.bad()) 1422 | { 1423 | store_data.set_error_code(stream_buffer_overflow); 1424 | } 1425 | } 1426 | 1427 | template 1428 | AMSG_INLINE 1429 | typename ::std::enable_if<::std::is_integral::value, void>::type 1430 | write(store_ty& store_data, const sfix_op& value) 1431 | { 1432 | value_type data = host_to_le(value.val); 1433 | store_data.write((char*)&data, sizeof(value_type)); 1434 | if (store_data.bad()) 1435 | { 1436 | store_data.set_error_code(stream_buffer_overflow); 1437 | } 1438 | } 1439 | 1440 | template 1441 | AMSG_INLINE uint32_t size_of(const smax_valid& value) 1442 | { 1443 | return size_of(value.val); 1444 | } 1445 | 1446 | template 1447 | AMSG_INLINE bool can_skip(const smax_valid& value) 1448 | { 1449 | return can_skip(value.val); 1450 | } 1451 | 1452 | template 1453 | AMSG_INLINE void skip_read(store_ty& store_data, const smax_valid& value) 1454 | { 1455 | skip_read(store_data, &value.val); 1456 | } 1457 | 1458 | template 1459 | AMSG_INLINE void read(store_ty& store_data, const smax_valid& value) 1460 | { 1461 | smax_valid * ptr = (smax_valid*)&value; 1462 | read(store_data, ptr->val, ptr->size); 1463 | } 1464 | 1465 | template 1466 | AMSG_INLINE void write(store_ty& store_data, const smax_valid& value) 1467 | { 1468 | write(store_data, value.val, value.size); 1469 | } 1470 | 1471 | } 1472 | 1473 | #define AMSG_TAG_MEMBER_X( r ,v , elem ) \ 1474 | if(!can_skip(v.elem)) \ 1475 | {\ 1476 | tag |= mask;\ 1477 | }\ 1478 | mask <<= 1; 1479 | 1480 | #define AMSG_SIZE_MEMBER_X( r ,v , elem ) \ 1481 | if(!can_skip(v.elem)) \ 1482 | {\ 1483 | tag |= mask;\ 1484 | size += ::amsg::size_of(v.elem);\ 1485 | }\ 1486 | mask <<= 1; 1487 | 1488 | #define AMSG_READ_MEMBER( r , v , elem ) \ 1489 | if(tag&mask)\ 1490 | {\ 1491 | ::amsg::read(store_data,v.elem);\ 1492 | if(store_data.error())\ 1493 | {\ 1494 | store_data.append_debug_info(".");\ 1495 | store_data.append_debug_info(BOOST_PP_STRINGIZE(elem));\ 1496 | return;\ 1497 | }\ 1498 | }\ 1499 | mask <<= 1; 1500 | 1501 | #define AMSG_WRITE_MEMBER( r ,v , elem ) \ 1502 | if(tag&mask)\ 1503 | {\ 1504 | ::amsg::write(store_data, v.elem); \ 1505 | if (store_data.error())\ 1506 | {\ 1507 | store_data.append_debug_info("."); \ 1508 | store_data.append_debug_info(BOOST_PP_STRINGIZE(elem)); \ 1509 | return; \ 1510 | }\ 1511 | }\ 1512 | mask <<= 1; 1513 | 1514 | #define AMSG(TYPE, MEMBERS)\ 1515 | namespace amsg {\ 1516 | AMSG_INLINE uint32_t size_of(const TYPE& value)\ 1517 | {\ 1518 | uint32_t size = 0;\ 1519 | uint64_t tag = 0;\ 1520 | uint64_t mask = 1;\ 1521 | BOOST_PP_SEQ_FOR_EACH( AMSG_SIZE_MEMBER_X , value , MEMBERS ) \ 1522 | size += size_of(tag);\ 1523 | size += size_of(size + size_of(size));\ 1524 | return size;\ 1525 | }\ 1526 | \ 1527 | template \ 1528 | AMSG_INLINE void read(store_ty& store_data, TYPE& value)\ 1529 | {\ 1530 | ::std::size_t offset = store_data.read_length();\ 1531 | uint32_t len_tag = 0;\ 1532 | uint64_t tag = 0;\ 1533 | uint64_t mask = 1;\ 1534 | read(store_data, len_tag);\ 1535 | if(store_data.error()){return;}\ 1536 | read(store_data,tag);\ 1537 | if (store_data.error()){return;}\ 1538 | BOOST_PP_SEQ_FOR_EACH( AMSG_READ_MEMBER , value , MEMBERS ) \ 1539 | if(len_tag >= 0)\ 1540 | {\ 1541 | ::std::size_t read_len = store_data.read_length() - offset;\ 1542 | ::std::size_t len = (::std::size_t)len_tag;\ 1543 | if (len > read_len) store_data.skip_read(len - read_len);\ 1544 | }\ 1545 | }\ 1546 | \ 1547 | template \ 1548 | AMSG_INLINE void write(store_ty& store_data, const TYPE& value)\ 1549 | {\ 1550 | uint32_t size = size_of(value);\ 1551 | uint64_t tag = 0;\ 1552 | uint64_t mask = 1;\ 1553 | BOOST_PP_SEQ_FOR_EACH( AMSG_TAG_MEMBER_X , value , MEMBERS ) \ 1554 | write(store_data, size);\ 1555 | if(store_data.error()){return;}\ 1556 | write(store_data,tag);\ 1557 | if(store_data.error()){return;}\ 1558 | mask = 1;\ 1559 | BOOST_PP_SEQ_FOR_EACH( AMSG_WRITE_MEMBER , value , MEMBERS ) \ 1560 | }\ 1561 | } 1562 | 1563 | #define AMSGF(TYPE,X) \ 1564 | template friend uint32_t ::amsg::size_of(ty&);\ 1565 | template friend void ::amsg::read(store_ty&,ty&);\ 1566 | template friend void ::amsg::write(store_ty&,const ty&); 1567 | 1568 | #endif 1569 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lordoffox/amsg/811c4a0a5aecfe7fbaab8839707d619f576e4a93/example/CMakeLists.txt -------------------------------------------------------------------------------- /example/sfix/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lordoffox/amsg/811c4a0a5aecfe7fbaab8839707d619f576e4a93/example/sfix/CMakeLists.txt -------------------------------------------------------------------------------- /example/sfix/main.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2012 Ning Ding (lordoffox@gmail.com) 3 | /// 4 | /// Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | /// 7 | /// See https://github.com/lordoffox/amsg for latest version. 8 | /// 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace usr 15 | { 16 | struct msg_header_fix 17 | { 18 | boost::int32_t size; 19 | boost::int32_t type; 20 | }; 21 | 22 | struct msg_header 23 | { 24 | boost::int32_t size; 25 | boost::int32_t type; 26 | }; 27 | } 28 | 29 | AMSG(usr::msg_header_fix, (size&sfix)(type&sfix)); 30 | AMSG(usr::msg_header, (size)(type)); 31 | 32 | int main() 33 | { 34 | try 35 | { 36 | usr::msg_header_fix src_fix; 37 | src_fix.size = 4; 38 | src_fix.type = 1; 39 | 40 | std::size_t size = amsg::size_of(src_fix); 41 | BOOST_ASSERT(size == sizeof(boost::int32_t) * 2); 42 | 43 | usr::msg_header src; 44 | src.size = 4; 45 | src.type = 1; 46 | 47 | size = amsg::size_of(src); 48 | BOOST_ASSERT(size == sizeof(boost::int8_t) * 2); 49 | } 50 | catch (std::exception& ex) 51 | { 52 | std::cerr << ex.what() << std::endl; 53 | } 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /example/size_of/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lordoffox/amsg/811c4a0a5aecfe7fbaab8839707d619f576e4a93/example/size_of/CMakeLists.txt -------------------------------------------------------------------------------- /example/size_of/main.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2012 Ning Ding (lordoffox@gmail.com) 3 | /// 4 | /// Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | /// 7 | /// See https://github.com/lordoffox/amsg for latest version. 8 | /// 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace usr 15 | { 16 | struct person 17 | { 18 | std::string name; 19 | boost::int32_t age; 20 | bool married; 21 | 22 | bool operator==(person const& rhs) const 23 | { 24 | return name == rhs.name && age == rhs.age && married == rhs.married; 25 | } 26 | }; 27 | } 28 | 29 | AMSG(usr::person, (name)(age)(married)); 30 | 31 | int main() 32 | { 33 | try 34 | { 35 | usr::person src; 36 | src.name = "my name"; 37 | src.age = 33; 38 | src.married = true; 39 | 40 | std::size_t size = amsg::size_of(src); 41 | std::cout << size << std::endl; 42 | } 43 | catch (std::exception& ex) 44 | { 45 | std::cerr << ex.what() << std::endl; 46 | } 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /example/smax/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lordoffox/amsg/811c4a0a5aecfe7fbaab8839707d619f576e4a93/example/smax/CMakeLists.txt -------------------------------------------------------------------------------- /example/smax/main.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2012 Ning Ding (lordoffox@gmail.com) 3 | /// 4 | /// Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | /// 7 | /// See https://github.com/lordoffox/amsg for latest version. 8 | /// 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace usr 15 | { 16 | struct person 17 | { 18 | std::string name; 19 | boost::int32_t age; 20 | bool married; 21 | 22 | bool operator==(person const& rhs) const 23 | { 24 | return name == rhs.name && age == rhs.age && married == rhs.married; 25 | } 26 | }; 27 | 28 | struct person2 29 | { 30 | std::string name; 31 | boost::int32_t age; 32 | bool married; 33 | 34 | bool operator==(person const& rhs) const 35 | { 36 | return name == rhs.name && age == rhs.age && married == rhs.married; 37 | } 38 | }; 39 | } 40 | 41 | AMSG(usr::person, (name&smax(5))(age)(married)); 42 | AMSG(usr::person2, (name)(age)(married)); 43 | 44 | #define ENOUGH_SIZE 4096 45 | 46 | int main() 47 | { 48 | try 49 | { 50 | unsigned char buf[ENOUGH_SIZE]; 51 | 52 | // serialize 53 | usr::person src; 54 | src.name = "lordoffox"; 55 | src.age = 33; 56 | src.married = true; 57 | 58 | amsg::zero_copy_buffer writer; 59 | writer.set_write(buf, ENOUGH_SIZE); 60 | amsg::write(writer, src); 61 | BOOST_ASSERT(writer.bad()); 62 | 63 | writer.clear(); 64 | usr::person2 src2; 65 | src2.name = "lordoffox"; 66 | src2.age = 33; 67 | src2.married = true; 68 | amsg::write(writer, src2); 69 | BOOST_ASSERT(!writer.bad()); 70 | 71 | usr::person des; 72 | 73 | amsg::zero_copy_buffer reader; 74 | reader.set_read(buf, ENOUGH_SIZE); 75 | amsg::read(reader, des); 76 | BOOST_ASSERT(reader.bad()); 77 | } 78 | catch (std::exception& ex) 79 | { 80 | std::cerr << ex.what() << std::endl; 81 | } 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lordoffox/amsg/811c4a0a5aecfe7fbaab8839707d619f576e4a93/test/CMakeLists.txt -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2012 Ning Ding (lordoffox@gmail.com) 3 | /// 4 | /// Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | /// 7 | /// See https://github.com/lordoffox/amsg for latest version. 8 | /// 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | static std::size_t const test_count = 1; 15 | 16 | #include "test_base.hpp" 17 | 18 | int main() 19 | { 20 | try 21 | { 22 | amsg::base_ut::run(); 23 | } 24 | catch (std::exception& ex) 25 | { 26 | std::cerr << ex.what() << std::endl; 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/test_base.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2012 Ning Ding (lordoffox@gmail.com) 3 | /// 4 | /// Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | /// 7 | /// See https://github.com/lordoffox/amsg for latest version. 8 | /// 9 | 10 | namespace usr 11 | { 12 | struct person 13 | { 14 | std::string name; 15 | boost::int32_t age; 16 | bool married; 17 | 18 | bool operator==(person const& rhs) const 19 | { 20 | return name == rhs.name && age == rhs.age && married == rhs.married; 21 | } 22 | }; 23 | } 24 | 25 | AMSG(usr::person, (name&smax(30))(age&sfix)(married)); 26 | 27 | #define ENOUGH_SIZE 4096 28 | 29 | namespace amsg 30 | { 31 | class base_ut 32 | { 33 | public: 34 | static void run() 35 | { 36 | std::cout << "base_ut begin." << std::endl; 37 | for (std::size_t i=0; i 1) std::cout << "\r" << i; 42 | } 43 | if (test_count > 1) std::cout << std::endl; 44 | std::cout << "base_ut end." << std::endl; 45 | } 46 | 47 | private: 48 | template 49 | static void test_basic(T src) 50 | { 51 | unsigned char buf[ENOUGH_SIZE]; 52 | amsg::zero_copy_buffer buffer; 53 | buffer.set_write(buf, ENOUGH_SIZE); 54 | 55 | // serialize 56 | amsg::write(buffer, src); 57 | BOOST_ASSERT(!buffer.bad()); 58 | 59 | // deserialize 60 | buffer.set_read(buf, ENOUGH_SIZE); 61 | T des = T(); 62 | 63 | amsg::read(buffer, des); 64 | BOOST_ASSERT(!buffer.bad()); 65 | 66 | BOOST_ASSERT(src == des); 67 | } 68 | 69 | static void test_base() 70 | { 71 | try 72 | { 73 | test_basic(true); 74 | test_basic(boost::int8_t(1)); 75 | test_basic(boost::uint8_t(2)); 76 | test_basic(boost::int16_t(3)); 77 | test_basic(boost::uint16_t(4)); 78 | test_basic(boost::int32_t(5)); 79 | test_basic(boost::uint32_t(6)); 80 | test_basic(boost::int64_t(-1003)); 81 | test_basic(boost::uint64_t(9321)); 82 | test_basic(float(3.1f)); 83 | test_basic(double(323.232f)); 84 | 85 | test_basic(std::string("hello world!")); 86 | test_basic(std::vector(5, boost::int32_t(11))); 87 | test_basic(std::deque(5, boost::int32_t(11))); 88 | test_basic(std::list(5, boost::int32_t(11))); 89 | 90 | boost::array arr; 91 | arr.assign(23); 92 | test_basic(arr); 93 | 94 | #ifdef AMSG_STD_CXX11 95 | std::array std_arr; 96 | std_arr[0] = 23; 97 | std_arr[1] = 23; 98 | test_basic(std_arr); 99 | #endif 100 | 101 | #ifdef AMSG_STD_CXX11 102 | test_basic(std::forward_list(5, boost::int32_t(11))); 103 | #endif 104 | 105 | std::map m; 106 | m.insert(std::make_pair(boost::int32_t(121234), std::string("string"))); 107 | test_basic(m); 108 | 109 | std::multimap mm; 110 | mm.insert(std::make_pair(boost::int32_t(121234), std::string("string1"))); 111 | mm.insert(std::make_pair(boost::int32_t(121234), std::string("string2"))); 112 | test_basic(mm); 113 | 114 | boost::unordered_map um; 115 | um.insert(std::make_pair(boost::int32_t(121234), std::string("string"))); 116 | test_basic(um); 117 | 118 | #ifdef AMSG_STD_CXX11 119 | std::unordered_map std_um; 120 | std_um.insert(std::make_pair(boost::int32_t(121234), std::string("string"))); 121 | test_basic(std_um); 122 | 123 | std::unordered_multimap std_umm; 124 | std_umm.insert(std::make_pair(boost::int32_t(121234), std::string("string1"))); 125 | std_umm.insert(std::make_pair(boost::int32_t(121234), std::string("string2"))); 126 | test_basic(std_umm); 127 | #endif 128 | 129 | std::set s; 130 | s.insert(std::string("string")); 131 | test_basic(s); 132 | 133 | std::multiset ms; 134 | ms.insert(std::string("string")); 135 | ms.insert(std::string("string")); 136 | test_basic(ms); 137 | 138 | boost::unordered_set us; 139 | us.insert(std::string("string")); 140 | test_basic(us); 141 | 142 | #ifdef AMSG_STD_CXX11 143 | std::unordered_set std_us; 144 | std_us.insert(std::string("string")); 145 | test_basic(std_us); 146 | 147 | std::unordered_multiset std_ums; 148 | std_ums.insert(std::string("string")); 149 | std_ums.insert(std::string("string")); 150 | test_basic(std_ums); 151 | #endif 152 | } 153 | catch (std::exception& ex) 154 | { 155 | std::cerr << "test_base: " << ex.what() << std::endl; 156 | } 157 | } 158 | 159 | static void test_common() 160 | { 161 | try 162 | { 163 | unsigned char buf[ENOUGH_SIZE]; 164 | 165 | // serialize 166 | usr::person src; 167 | src.name = "lordoffox"; 168 | src.age = 33; 169 | src.married = true; 170 | 171 | amsg::zero_copy_buffer writer; 172 | writer.set_write(buf, ENOUGH_SIZE); 173 | amsg::write(writer, src); 174 | BOOST_ASSERT(!writer.bad()); 175 | 176 | // deserialize 177 | usr::person des; 178 | 179 | amsg::zero_copy_buffer reader; 180 | reader.set_read(buf, ENOUGH_SIZE); 181 | amsg::read(reader, des); 182 | BOOST_ASSERT(!reader.bad()); 183 | 184 | BOOST_ASSERT(src == des); 185 | } 186 | catch (std::exception& ex) 187 | { 188 | std::cerr << "test_common: " << ex.what() << std::endl; 189 | } 190 | } 191 | }; 192 | } 193 | -------------------------------------------------------------------------------- /zerocopy.hpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (c) 2012 - 2015 Ning Ding (lordoffox@gmail.com) 3 | /// 4 | /// Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | /// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | /// 7 | /// See https://github.com/lordoffox/amsg for latest version. 8 | /// 9 | 10 | #ifndef AMSG_ZEROCOPY_HPP 11 | #define AMSG_ZEROCOPY_HPP 12 | 13 | #include "amsg.hpp" 14 | 15 | namespace amsg 16 | { 17 | struct zero_copy_buffer : public basic_store 18 | { 19 | private: 20 | ::std::string m_error_info; 21 | 22 | unsigned char const* m_read_header_ptr; 23 | unsigned char* m_write_header_ptr; 24 | unsigned char const* m_read_ptr; 25 | unsigned char* m_write_ptr; 26 | unsigned char const* m_read_tail_ptr; 27 | unsigned char const* m_write_tail_ptr; 28 | int m_status; 29 | 30 | public: 31 | enum { good, read_overflow, write_overflow }; 32 | 33 | zero_copy_buffer() 34 | : m_read_header_ptr(0) 35 | , m_write_header_ptr(0) 36 | , m_read_ptr(0) 37 | , m_write_ptr(0) 38 | , m_read_tail_ptr(0) 39 | , m_write_tail_ptr(0) 40 | , m_status(good) 41 | { 42 | } 43 | 44 | ~zero_copy_buffer() 45 | { 46 | } 47 | 48 | AMSG_INLINE void set_read(unsigned char const* buffer, ::std::size_t length) 49 | { 50 | this->m_read_header_ptr = buffer; 51 | this->m_read_ptr = this->m_read_header_ptr; 52 | this->m_read_tail_ptr = this->m_read_header_ptr + length; 53 | this->m_status = good; 54 | } 55 | 56 | AMSG_INLINE void set_read(char const* buffer, ::std::size_t length) 57 | { 58 | set_read((unsigned char const*)buffer, length); 59 | } 60 | 61 | AMSG_INLINE void set_write(unsigned char* buffer, ::std::size_t length) 62 | { 63 | this->m_write_header_ptr = buffer; 64 | this->m_write_ptr = this->m_write_header_ptr; 65 | this->m_write_tail_ptr = this->m_write_header_ptr + length; 66 | this->m_status = good; 67 | } 68 | 69 | AMSG_INLINE void set_write(char* buffer, ::std::size_t length) 70 | { 71 | set_write((unsigned char*)buffer, length); 72 | } 73 | 74 | void append_debug_info(const char * info) 75 | { 76 | m_error_info.append(info); 77 | } 78 | 79 | ::std::size_t read(char * buffer, ::std::size_t len) 80 | { 81 | if (this->m_read_ptr + len > this->m_read_tail_ptr) 82 | { 83 | this->m_status = read_overflow; 84 | return 0; 85 | } 86 | ::std::memcpy(buffer, this->m_read_ptr, len); 87 | this->m_read_ptr += len; 88 | return len; 89 | } 90 | 91 | unsigned char get_char() 92 | { 93 | if (this->m_read_ptr + 1 > this->m_read_tail_ptr) 94 | { 95 | m_status = read_overflow; 96 | return 0; 97 | } 98 | return *m_read_ptr++; 99 | } 100 | 101 | ::std::size_t write(const char * buffer, ::std::size_t len) 102 | { 103 | if (this->m_write_ptr + len > this->m_write_tail_ptr) 104 | { 105 | this->m_status = write_overflow; 106 | return 0; 107 | } 108 | ::std::memcpy((void*)this->m_write_ptr, buffer, len); 109 | this->m_write_ptr += len; 110 | return len; 111 | } 112 | 113 | bool bad(){ return m_status != good || basic_store::error(); } 114 | 115 | AMSG_INLINE unsigned char * append_write(::std::size_t len) 116 | { 117 | if (this->m_write_ptr + len > this->m_write_tail_ptr) 118 | { 119 | this->m_status = write_overflow; 120 | return 0; 121 | } 122 | unsigned char * append_ptr = this->m_write_ptr; 123 | this->m_write_ptr += len; 124 | return append_ptr; 125 | } 126 | 127 | AMSG_INLINE unsigned char const* skip_read(::std::size_t len) 128 | { 129 | if (this->m_read_ptr + len > this->m_read_tail_ptr) 130 | { 131 | this->m_status = read_overflow; 132 | return 0; 133 | } 134 | unsigned char const* ptr = this->m_read_ptr; 135 | this->m_read_ptr += len; 136 | return ptr; 137 | } 138 | 139 | AMSG_INLINE void clear_write() 140 | { 141 | basic_store::clear(); 142 | this->m_write_ptr = this->m_write_header_ptr; 143 | } 144 | 145 | AMSG_INLINE void clear() 146 | { 147 | basic_store::clear(); 148 | this->m_read_ptr = this->m_read_header_ptr; 149 | this->m_write_ptr = this->m_write_header_ptr; 150 | m_status = good; 151 | } 152 | 153 | AMSG_INLINE unsigned char const* read_ptr() const 154 | { 155 | return this->m_read_ptr; 156 | } 157 | 158 | AMSG_INLINE unsigned char* write_ptr() const 159 | { 160 | return this->m_write_ptr; 161 | } 162 | 163 | AMSG_INLINE unsigned char* write_data() const 164 | { 165 | return this->m_write_header_ptr; 166 | } 167 | 168 | AMSG_INLINE::std::size_t read_length() const 169 | { 170 | return this->m_read_ptr - this->m_read_header_ptr; 171 | } 172 | 173 | AMSG_INLINE::std::size_t write_length() const 174 | { 175 | return this->m_write_ptr - this->m_write_header_ptr; 176 | } 177 | }; 178 | 179 | template 180 | struct le_pos; 181 | 182 | #if defined(__LITTLE_ENDIAN__) 183 | template 184 | struct le_pos 185 | { 186 | enum 187 | { 188 | pos0, 189 | pos1, 190 | pos2, 191 | pos3, 192 | pos4, 193 | pos5, 194 | pos6, 195 | pos7, 196 | }; 197 | }; 198 | #else 199 | template<> 200 | struct le_pos < 1 > 201 | { 202 | enum 203 | { 204 | pos7, 205 | pos6, 206 | pos5, 207 | pos4, 208 | pos3, 209 | pos2, 210 | pos1, 211 | pos0 = 0, 212 | }; 213 | }; 214 | template<> 215 | struct le_pos < 2 > 216 | { 217 | enum 218 | { 219 | pos7, 220 | pos6, 221 | pos5, 222 | pos4, 223 | pos3, 224 | pos2, 225 | pos1 = 0, 226 | pos0, 227 | }; 228 | }; 229 | 230 | template<> 231 | struct le_pos < 4 > 232 | { 233 | enum 234 | { 235 | pos7, 236 | pos6, 237 | pos5, 238 | pos4, 239 | pos3 = 0, 240 | pos2, 241 | pos1, 242 | pos0, 243 | }; 244 | }; 245 | 246 | template<> 247 | struct le_pos < 8 > 248 | { 249 | enum 250 | { 251 | pos7, 252 | pos6, 253 | pos5, 254 | pos4, 255 | pos3, 256 | pos2, 257 | pos1, 258 | pos0, 259 | }; 260 | }; 261 | #endif 262 | 263 | template 264 | AMSG_INLINE 265 | typename ::std::enable_if<::std::is_signed::value && ::std::is_integral::value, void>::type 266 | read(zero_copy_buffer& stream, value_type& value) 267 | { 268 | const int bytes = sizeof(value_type); 269 | uint8_t tag = stream.get_char(); 270 | if (stream.bad()) 271 | { 272 | stream.m_error_code = stream_buffer_overflow; 273 | return; 274 | } 275 | if (tag > const_tag_as_value) 276 | { 277 | int sign = 1; 278 | if ((long)tag & const_negative_bit_value) 279 | { 280 | sign = -1; 281 | } 282 | int read_bytes = (int(tag) & const_interger_byte_msak) + 1; 283 | if (bytes < read_bytes) 284 | { 285 | stream.m_error_code = value_too_large_to_integer_number; 286 | return; 287 | } 288 | value = 0; 289 | uint8_t const* read_ptr = stream.skip_read(read_bytes); 290 | if (stream.bad()) 291 | { 292 | stream.m_error_code = stream_buffer_overflow; 293 | return; 294 | } 295 | uint8_t * value_ptr = (uint8_t *)&value; 296 | value = 0; 297 | switch (read_bytes) 298 | { 299 | case 8:value_ptr[7] = read_ptr[le_pos::pos7]; 300 | case 7:value_ptr[6] = read_ptr[le_pos::pos6]; 301 | case 6:value_ptr[5] = read_ptr[le_pos::pos5]; 302 | case 5:value_ptr[4] = read_ptr[le_pos::pos4]; 303 | case 4:value_ptr[3] = read_ptr[le_pos::pos3]; 304 | case 3:value_ptr[2] = read_ptr[le_pos::pos2]; 305 | case 2:value_ptr[1] = read_ptr[le_pos::pos1]; 306 | case 1:value_ptr[0] = read_ptr[le_pos::pos0]; 307 | } 308 | if (sign < 0) 309 | { 310 | value = -value; 311 | } 312 | } 313 | else 314 | { 315 | value = tag; 316 | } 317 | } 318 | 319 | template 320 | AMSG_INLINE 321 | typename ::std::enable_if<::std::is_signed::value && ::std::is_integral::value, void>::type 322 | write(zero_copy_buffer& stream, const value_type& value) 323 | { 324 | const int bytes = sizeof(value_type); 325 | int write_bytes = 1; 326 | uint8_t write_buff[12]; 327 | if (0 <= value && value < const_tag_as_type) 328 | { 329 | write_buff[0] = (uint8_t)value; 330 | } 331 | else 332 | { 333 | uint8_t negative_bit = 0; 334 | value_type temp = value; 335 | if (value < 0) 336 | { 337 | negative_bit = const_negative_bit_value; 338 | temp = -value; 339 | } 340 | uint8_t * ptr = (uint8_t *)&temp; 341 | if (temp < 0x100) 342 | { 343 | write_buff[1] = ptr[le_pos::pos0]; 344 | write_bytes = 2; 345 | } 346 | else if (temp < 0x10000) 347 | { 348 | write_buff[1] = ptr[le_pos::pos0]; 349 | write_buff[2] = ptr[le_pos::pos1]; 350 | write_bytes = 3; 351 | } 352 | else if (temp < 0x1000000) 353 | { 354 | write_buff[1] = ptr[le_pos::pos0]; 355 | write_buff[2] = ptr[le_pos::pos1]; 356 | write_buff[3] = ptr[le_pos::pos2]; 357 | write_bytes = 4; 358 | } 359 | else if (temp < 0x100000000) 360 | { 361 | write_buff[1] = ptr[le_pos::pos0]; 362 | write_buff[2] = ptr[le_pos::pos1]; 363 | write_buff[3] = ptr[le_pos::pos2]; 364 | write_buff[4] = ptr[le_pos::pos3]; 365 | write_bytes = 5; 366 | } 367 | else if (temp < 0x10000000000) 368 | { 369 | write_buff[1] = ptr[le_pos::pos0]; 370 | write_buff[2] = ptr[le_pos::pos1]; 371 | write_buff[3] = ptr[le_pos::pos2]; 372 | write_buff[4] = ptr[le_pos::pos3]; 373 | write_buff[5] = ptr[le_pos::pos4]; 374 | write_bytes = 6; 375 | } 376 | else if (temp < 0x1000000000000) 377 | { 378 | write_buff[1] = ptr[le_pos::pos0]; 379 | write_buff[2] = ptr[le_pos::pos1]; 380 | write_buff[3] = ptr[le_pos::pos2]; 381 | write_buff[4] = ptr[le_pos::pos3]; 382 | write_buff[5] = ptr[le_pos::pos4]; 383 | write_buff[6] = ptr[le_pos::pos5]; 384 | write_bytes = 7; 385 | } 386 | else if (temp < 0x100000000000000) 387 | { 388 | write_buff[1] = ptr[le_pos::pos0]; 389 | write_buff[2] = ptr[le_pos::pos1]; 390 | write_buff[3] = ptr[le_pos::pos2]; 391 | write_buff[4] = ptr[le_pos::pos3]; 392 | write_buff[5] = ptr[le_pos::pos4]; 393 | write_buff[6] = ptr[le_pos::pos5]; 394 | write_buff[7] = ptr[le_pos::pos6]; 395 | write_bytes = 8; 396 | } 397 | else 398 | { 399 | write_buff[1] = ptr[le_pos::pos0]; 400 | write_buff[2] = ptr[le_pos::pos1]; 401 | write_buff[3] = ptr[le_pos::pos2]; 402 | write_buff[4] = ptr[le_pos::pos3]; 403 | write_buff[5] = ptr[le_pos::pos4]; 404 | write_buff[6] = ptr[le_pos::pos5]; 405 | write_buff[7] = ptr[le_pos::pos6]; 406 | write_buff[8] = ptr[le_pos::pos7]; 407 | write_bytes = 9; 408 | } 409 | write_buff[0] = (uint8_t)(const_store_postive_integer_byte_mask + negative_bit + write_bytes); 410 | } 411 | stream.write((char*)write_buff, write_bytes); 412 | if (stream.bad()) 413 | { 414 | stream.m_error_code = stream_buffer_overflow; 415 | return; 416 | } 417 | } 418 | 419 | template 420 | AMSG_INLINE 421 | typename ::std::enable_if<::std::is_unsigned::value && ::std::is_integral::value, void>::type 422 | read(zero_copy_buffer& stream, value_type& value) 423 | { 424 | const int bytes = sizeof(value_type); 425 | value = stream.get_char(); 426 | if (stream.bad()) 427 | { 428 | stream.m_error_code = stream_buffer_overflow; 429 | return; 430 | } 431 | if (value > const_tag_as_value) 432 | { 433 | if ((long)value & const_negative_bit_value) 434 | { 435 | stream.m_error_code = negative_assign_to_unsigned_integer_number; 436 | return; 437 | } 438 | int read_bytes = (int)(value & const_interger_byte_msak) + 1; 439 | if (bytes < read_bytes) 440 | { 441 | stream.m_error_code = value_too_large_to_integer_number; 442 | return; 443 | } 444 | uint8_t const* read_ptr = stream.skip_read(read_bytes); 445 | if (stream.bad()) 446 | { 447 | stream.m_error_code = stream_buffer_overflow; 448 | return; 449 | } 450 | uint8_t * value_ptr = (uint8_t *)&value; 451 | value = 0; 452 | switch (read_bytes) 453 | { 454 | case 8:value_ptr[7] = read_ptr[le_pos::pos7]; 455 | case 7:value_ptr[6] = read_ptr[le_pos::pos6]; 456 | case 6:value_ptr[5] = read_ptr[le_pos::pos5]; 457 | case 5:value_ptr[4] = read_ptr[le_pos::pos4]; 458 | case 4:value_ptr[3] = read_ptr[le_pos::pos3]; 459 | case 3:value_ptr[2] = read_ptr[le_pos::pos2]; 460 | case 2:value_ptr[1] = read_ptr[le_pos::pos1]; 461 | case 1:value_ptr[0] = read_ptr[le_pos::pos0]; 462 | } 463 | } 464 | } 465 | 466 | template 467 | AMSG_INLINE 468 | typename ::std::enable_if<::std::is_unsigned::value && ::std::is_integral::value, void>::type 469 | write(zero_copy_buffer& stream, const value_type& value) 470 | { 471 | const int bytes = sizeof(value_type); 472 | if (value < const_tag_as_type) 473 | { 474 | uint8_t * ptr = stream.append_write(1); 475 | *ptr = (uint8_t)value; 476 | } 477 | else 478 | { 479 | uint8_t * ptr = (uint8_t *)(&value); 480 | if (value < 0x100) 481 | { 482 | uint8_t * wptr = stream.append_write(2); 483 | wptr[0] = 0x80; 484 | wptr[1] = ptr[le_pos::pos0]; 485 | } 486 | else if (value < 0x10000) 487 | { 488 | uint8_t * wptr = stream.append_write(3); 489 | wptr[0] = 0x81; 490 | wptr[1] = ptr[le_pos::pos0]; 491 | wptr[2] = ptr[le_pos::pos1]; 492 | } 493 | else if (value < 0x1000000) 494 | { 495 | uint8_t * wptr = stream.append_write(4); 496 | wptr[0] = 0x82; 497 | wptr[1] = ptr[le_pos::pos0]; 498 | wptr[2] = ptr[le_pos::pos1]; 499 | wptr[3] = ptr[le_pos::pos2]; 500 | } 501 | else if (value < 0x100000000) 502 | { 503 | uint8_t * wptr = stream.append_write(5); 504 | wptr[0] = 0x83; 505 | wptr[1] = ptr[le_pos::pos0]; 506 | wptr[2] = ptr[le_pos::pos1]; 507 | wptr[3] = ptr[le_pos::pos2]; 508 | wptr[4] = ptr[le_pos::pos3]; 509 | } 510 | else if (value < 0x10000000000LL) 511 | { 512 | uint8_t * wptr = stream.append_write(6); 513 | wptr[0] = 0x84; 514 | wptr[1] = ptr[le_pos::pos0]; 515 | wptr[2] = ptr[le_pos::pos1]; 516 | wptr[3] = ptr[le_pos::pos2]; 517 | wptr[4] = ptr[le_pos::pos3]; 518 | wptr[5] = ptr[le_pos::pos4]; 519 | } 520 | else if (value < 0x1000000000000LL) 521 | { 522 | uint8_t * wptr = stream.append_write(7); 523 | wptr[0] = 0x85; 524 | wptr[1] = ptr[le_pos::pos0]; 525 | wptr[2] = ptr[le_pos::pos1]; 526 | wptr[3] = ptr[le_pos::pos2]; 527 | wptr[4] = ptr[le_pos::pos3]; 528 | wptr[5] = ptr[le_pos::pos4]; 529 | wptr[6] = ptr[le_pos::pos5]; 530 | } 531 | else if (value < 0x100000000000000LL) 532 | { 533 | uint8_t * wptr = stream.append_write(8); 534 | wptr[0] = 0x86; 535 | wptr[1] = ptr[le_pos::pos0]; 536 | wptr[2] = ptr[le_pos::pos1]; 537 | wptr[3] = ptr[le_pos::pos2]; 538 | wptr[4] = ptr[le_pos::pos3]; 539 | wptr[5] = ptr[le_pos::pos4]; 540 | wptr[6] = ptr[le_pos::pos5]; 541 | wptr[7] = ptr[le_pos::pos6]; 542 | } 543 | else 544 | { 545 | uint8_t * wptr = stream.append_write(9); 546 | wptr[0] = 0x87; 547 | wptr[1] = ptr[le_pos::pos0]; 548 | wptr[2] = ptr[le_pos::pos1]; 549 | wptr[3] = ptr[le_pos::pos2]; 550 | wptr[4] = ptr[le_pos::pos3]; 551 | wptr[5] = ptr[le_pos::pos4]; 552 | wptr[6] = ptr[le_pos::pos5]; 553 | wptr[7] = ptr[le_pos::pos6]; 554 | wptr[8] = ptr[le_pos::pos7]; 555 | } 556 | } 557 | if (stream.bad()) 558 | { 559 | stream.m_error_code = stream_buffer_overflow; 560 | return; 561 | } 562 | } 563 | 564 | template 565 | AMSG_INLINE 566 | typename ::std::enable_if<::std::is_integral::value, void>::type 567 | read(zero_copy_buffer& store_data, const sfix_op& value) 568 | { 569 | uint8_t * read_ptr = (uint8_t *)store_data.skip_read(sizeof(value_type)); 570 | uint8_t * value_ptr = (uint8_t *)&value.val; 571 | if (store_data.bad()) 572 | { 573 | store_data.set_error_code(stream_buffer_overflow); 574 | return; 575 | } 576 | const int bytes = sizeof(value_type); 577 | switch (bytes) 578 | { 579 | case 8:value_ptr[7] = read_ptr[le_pos::pos7]; 580 | case 7:value_ptr[6] = read_ptr[le_pos::pos6]; 581 | case 6:value_ptr[5] = read_ptr[le_pos::pos5]; 582 | case 5:value_ptr[4] = read_ptr[le_pos::pos4]; 583 | case 4:value_ptr[3] = read_ptr[le_pos::pos3]; 584 | case 3:value_ptr[2] = read_ptr[le_pos::pos2]; 585 | case 2:value_ptr[1] = read_ptr[le_pos::pos1]; 586 | case 1:value_ptr[0] = read_ptr[le_pos::pos0]; 587 | } 588 | } 589 | 590 | template 591 | AMSG_INLINE 592 | typename ::std::enable_if<::std::is_integral::value, void>::type 593 | write(zero_copy_buffer& store_data, const sfix_op& value) 594 | { 595 | uint8_t * write_ptr = store_data.append_write(sizeof(value_type)); 596 | uint8_t * value_ptr = (uint8_t *)&value.val; 597 | if (store_data.bad()) 598 | { 599 | store_data.set_error_code(stream_buffer_overflow); 600 | return; 601 | } 602 | const int bytes = sizeof(value_type); 603 | switch (bytes) 604 | { 605 | case 8:write_ptr[7] = value_ptr[le_pos::pos7]; 606 | case 7:write_ptr[6] = value_ptr[le_pos::pos6]; 607 | case 6:write_ptr[5] = value_ptr[le_pos::pos5]; 608 | case 5:write_ptr[4] = value_ptr[le_pos::pos4]; 609 | case 4:write_ptr[3] = value_ptr[le_pos::pos3]; 610 | case 3:write_ptr[2] = value_ptr[le_pos::pos2]; 611 | case 2:write_ptr[1] = value_ptr[le_pos::pos1]; 612 | case 1:write_ptr[0] = value_ptr[le_pos::pos0]; 613 | } 614 | } 615 | 616 | AMSG_INLINE void read(zero_copy_buffer& stream, float& value) 617 | { 618 | typedef float value_type; 619 | uint8_t const* read_ptr = stream.skip_read(sizeof(value_type)); 620 | uint8_t * value_ptr = (uint8_t *)&value; 621 | if (stream.bad()) 622 | { 623 | stream.m_error_code = stream_buffer_overflow; 624 | return; 625 | } 626 | value_ptr[le_pos<4>::pos0] = read_ptr[0]; 627 | value_ptr[le_pos<4>::pos1] = read_ptr[1]; 628 | value_ptr[le_pos<4>::pos2] = read_ptr[2]; 629 | value_ptr[le_pos<4>::pos3] = read_ptr[3]; 630 | } 631 | 632 | AMSG_INLINE void write(zero_copy_buffer& stream, const float& value) 633 | { 634 | typedef float value_type; 635 | uint8_t * write_ptr = stream.append_write(sizeof(value_type)); 636 | if (stream.bad()) 637 | { 638 | stream.m_error_code = stream_buffer_overflow; 639 | return; 640 | } 641 | uint8_t * value_ptr = (uint8_t *)&value; 642 | write_ptr[le_pos<4>::pos0] = value_ptr[0]; 643 | write_ptr[le_pos<4>::pos1] = value_ptr[1]; 644 | write_ptr[le_pos<4>::pos2] = value_ptr[2]; 645 | write_ptr[le_pos<4>::pos3] = value_ptr[3]; 646 | } 647 | 648 | AMSG_INLINE void read(zero_copy_buffer& stream, double& value) 649 | { 650 | typedef double value_type; 651 | uint8_t const* read_ptr = stream.skip_read(sizeof(value_type)); 652 | uint8_t * value_ptr = (uint8_t *)&value; 653 | if (stream.bad()) 654 | { 655 | stream.m_error_code = stream_buffer_overflow; 656 | return; 657 | } 658 | value_ptr[le_pos<8>::pos0] = read_ptr[0]; 659 | value_ptr[le_pos<8>::pos1] = read_ptr[1]; 660 | value_ptr[le_pos<8>::pos2] = read_ptr[2]; 661 | value_ptr[le_pos<8>::pos3] = read_ptr[3]; 662 | value_ptr[le_pos<8>::pos4] = read_ptr[4]; 663 | value_ptr[le_pos<8>::pos5] = read_ptr[5]; 664 | value_ptr[le_pos<8>::pos6] = read_ptr[6]; 665 | value_ptr[le_pos<8>::pos7] = read_ptr[7]; 666 | } 667 | 668 | AMSG_INLINE void write(zero_copy_buffer& stream, const double& value) 669 | { 670 | typedef double value_type; 671 | uint8_t * write_ptr = stream.append_write(sizeof(value_type)); 672 | if (stream.bad()) 673 | { 674 | stream.m_error_code = stream_buffer_overflow; 675 | return; 676 | } 677 | uint8_t * value_ptr = (uint8_t *)&value; 678 | write_ptr[le_pos<8>::pos0] = value_ptr[0]; 679 | write_ptr[le_pos<8>::pos1] = value_ptr[1]; 680 | write_ptr[le_pos<8>::pos2] = value_ptr[2]; 681 | write_ptr[le_pos<8>::pos3] = value_ptr[3]; 682 | write_ptr[le_pos<8>::pos4] = value_ptr[4]; 683 | write_ptr[le_pos<8>::pos5] = value_ptr[5]; 684 | write_ptr[le_pos<8>::pos6] = value_ptr[6]; 685 | write_ptr[le_pos<8>::pos7] = value_ptr[7]; 686 | } 687 | 688 | } 689 | 690 | #endif 691 | --------------------------------------------------------------------------------