Created
July 13, 2020 17:58
-
-
Save chertov/1c13584e27f05ffcfb99b5a537b9c3cb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <vector> | |
#include <deque> | |
#include <map> | |
#include <string> | |
#include <google/protobuf/message.h> | |
#include <proto/common.pb.h> | |
// Endian detection macro from RapidJSON library | |
#define BYTEORDER_LITTLE_ENDIAN 0 // Little endian machine. | |
#define BYTEORDER_BIG_ENDIAN 1 // Big endian machine. | |
#ifndef BYTEORDER_ENDIAN | |
// Detect with GCC 4.6's macro. | |
# if defined(__BYTE_ORDER__) | |
# if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) | |
# define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN | |
# elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) | |
# define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN | |
# else | |
# error "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN." | |
# endif | |
// Detect with GLIBC's endian.h. | |
# elif defined(__GLIBC__) | |
# include <endian.h> | |
# if (__BYTE_ORDER == __LITTLE_ENDIAN) | |
# define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN | |
# elif (__BYTE_ORDER == __BIG_ENDIAN) | |
# define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN | |
# else | |
# error "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN." | |
# endif | |
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro. | |
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) | |
# define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN | |
# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) | |
# define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN | |
// Detect with architecture macros. | |
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) | |
# define BYTEORDER_ENDIAN BYTEORDER_BIG_ENDIAN | |
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) | |
# define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN | |
# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) | |
# define BYTEORDER_ENDIAN BYTEORDER_LITTLE_ENDIAN | |
# else | |
# error "Unknown machine byteorder endianness detected. User needs to define BYTEORDER_ENDIAN." | |
# endif | |
#endif | |
//#if defined(__cpp_exceptions) && (1 == __cpp_exceptions) | |
//#endif | |
// __EXCEPTIONS 1 | |
// __cpp_exceptions | |
namespace rpc_test { | |
#ifndef WRITE_CODE_EXISTS | |
#define WRITE_CODE_EXISTS | |
inline bool push(std::vector<uint8_t> &data, const uint8_t &val) { | |
try { data.push_back(val); return true; } catch(...) { return false; } | |
} | |
inline bool push_n(std::vector<uint8_t> &data, const uint8_t* bytes, const size_t n) { | |
#if(BYTEORDER_ENDIAN == BYTEORDER_BIG_ENDIAN) | |
for (size_t i = 0; i < n; ++i) | |
#else | |
for (ssize_t i = n-1; i >= 0; --i) | |
#endif | |
if (!push(data, bytes[i])) return false; | |
return true; | |
} | |
inline bool push_buf(std::vector<uint8_t> &data, const uint8_t* buf, const size_t size) { | |
try { data.insert(data.end(), buf, buf + size); } catch(...) { return false; } | |
return true; | |
} | |
// uint8 value 0 is false, other values is true | |
inline bool write(std::vector<uint8_t> &data, const bool &val) { | |
return push(data, val ? 1 : 0); | |
} | |
inline bool write(std::vector<uint8_t> &data, const uint8_t &val) { | |
return push(data, val); | |
} | |
inline bool write(std::vector<uint8_t> &data, const int8_t &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push(data, bytes[0]); | |
} | |
inline bool write(std::vector<uint8_t> &data, const uint16_t &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push_n(data, bytes, 2); | |
} | |
inline bool write(std::vector<uint8_t> &data, const int16_t &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push_n(data, bytes, 2); | |
} | |
inline bool write(std::vector<uint8_t> &data, const uint32_t &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push_n(data, bytes, 4); | |
} | |
inline bool write(std::vector<uint8_t> &data, const int32_t &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push_n(data, bytes, 4); | |
} | |
inline bool write(std::vector<uint8_t> &data, const uint64_t &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push_n(data, bytes, 8); | |
} | |
inline bool write(std::vector<uint8_t> &data, const int64_t &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push_n(data, bytes, 8); | |
} | |
inline bool write(std::vector<uint8_t> &data, const float &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push_n(data, bytes, 4); | |
} | |
inline bool write(std::vector<uint8_t> &data, const double &val) { | |
auto bytes = static_cast<const uint8_t*>(static_cast<const void*>(&val)); | |
return push_n(data, bytes, 8); | |
} | |
inline bool write(std::vector<uint8_t> &data, const std::vector<uint8_t> &buf) { | |
auto size = static_cast<uint32_t>(buf.size()); | |
if (!write(data, size)) return false; | |
return push_buf(data, buf.data(), buf.size()); | |
} | |
inline bool write(std::vector<uint8_t> &data, const std::string &str) { | |
auto size = static_cast<uint32_t>(str.size()); | |
if (!write(data, size)) return false; | |
if (!push_buf(data, reinterpret_cast<const uint8_t *>(str.c_str()), str.size())) return false; | |
return push(data, 0); | |
} | |
inline bool write(std::vector<uint8_t> &data, const google::protobuf::Message &message) { | |
std::string str = message.SerializeAsString(); | |
auto size = static_cast<uint32_t>(str.size()); | |
if (!write(data, size)) return false; | |
return push_buf(data, reinterpret_cast<const uint8_t *>(str.data()), str.size()); | |
} | |
template<typename Value> | |
inline bool write_arr(std::vector<uint8_t> &data, const std::vector<Value> &arr) { | |
auto size = static_cast<uint32_t>(arr.size()); | |
if (!write(data, size)) return false; | |
for (size_t i = 0; i < arr.size(); ++i) { | |
if (!write(data, static_cast<const Value &>(arr[i]))) return false; | |
} | |
return true; | |
} | |
template<typename Key, typename Value> | |
inline bool write_map(std::vector<uint8_t> &data, const std::map<Key, Value> &map) { | |
auto size = static_cast<uint32_t>(map.size()); | |
if (!write(data, size)) return false; | |
typename std::map<Key, Value>::iterator it; | |
for ( it = map.begin(); it != map.end(); it++ ) { | |
if (!write(data, static_cast<const Key &>(it->first))) return false; | |
if (!write(data, static_cast<const Value &>(it->second))) return false; | |
} | |
return true; | |
} | |
#endif | |
#ifndef READ_CODE_EXISTS | |
#define READ_CODE_EXISTS | |
inline bool pop(std::deque<uint8_t> &data, uint8_t &val) { | |
if (data.empty()) return false; | |
val = data.front(); data.pop_front(); | |
return true; | |
} | |
inline bool pop_n(std::deque<uint8_t> &data, uint8_t* bytes, const size_t n) { | |
#if(BYTEORDER_ENDIAN == BYTEORDER_BIG_ENDIAN) | |
for(size_t i = 0; i < n; ++i) | |
#else | |
for(ssize_t i = n-1; i >= 0; --i) | |
#endif | |
if (!pop(data, bytes[i])) return false; | |
return true; | |
} | |
inline bool pop_buf(std::deque<uint8_t> &data, std::vector<uint8_t> &buf, const size_t size) { | |
buf = std::vector<uint8_t>(size); | |
for(size_t i = 0; i < size; ++i) | |
if (!pop(data, buf[i])) return false; | |
return true; | |
} | |
inline bool pop_buf(std::deque<uint8_t> &data, uint8_t *buf, const size_t size) { | |
for(size_t i = 0; i < size; ++i) | |
if (!pop(data, buf[i])) return false; | |
return true; | |
} | |
// uint8 value 0 is false, other values is true | |
inline bool read(std::deque<uint8_t> &data, bool &val) { | |
uint8_t byte; | |
if (!pop(data, byte)) return false; | |
val = byte != 0; | |
return true; | |
} | |
inline bool read(std::deque<uint8_t> &data, uint8_t &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
return pop_n(data, bytes, 1); | |
} | |
inline bool read(std::deque<uint8_t> &data, int8_t &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
return pop_n(data, bytes, 1); | |
} | |
inline bool read(std::deque<uint8_t> &data, uint16_t &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
return pop_n(data, bytes, 2); | |
} | |
inline bool read(std::deque<uint8_t> &data, int16_t &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
return pop_n(data, bytes, 2); | |
} | |
inline bool read(std::deque<uint8_t> &data, uint32_t &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
if (!pop_n(data, bytes, 4)) return false; | |
return true; | |
} | |
inline bool read(std::deque<uint8_t> &data, int32_t &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
if (!pop_n(data, bytes, 4)) return false; | |
return true; | |
} | |
inline bool read(std::deque<uint8_t> &data, uint64_t &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
return pop_n(data, bytes, 8); | |
} | |
inline bool read(std::deque<uint8_t> &data, int64_t &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
return pop_n(data, bytes, 8); | |
} | |
inline bool read(std::deque<uint8_t> &data, float &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
return pop_n(data, bytes, 4); | |
} | |
inline bool read(std::deque<uint8_t> &data, double &val) { | |
auto bytes = static_cast<uint8_t*>(static_cast<void*>(&val)); | |
return pop_n(data, bytes, 8); | |
} | |
inline bool read(std::deque<uint8_t> &data, std::vector<uint8_t> &buf) { | |
uint32_t size = 0; | |
if (!read(data, size)) return false; | |
return pop_buf(data, buf, size_t(size)); | |
} | |
inline bool read(std::deque<uint8_t> &data, std::string &str) { | |
uint32_t size = 0; | |
if (!read(data, size)) return false; | |
str = std::string(size, ' '); | |
if (!pop_buf(data, reinterpret_cast<uint8_t *>(const_cast<char*>(str.data())), size_t(size))) return false; | |
uint8_t zero = 0; | |
return pop(data, zero); | |
} | |
inline bool read(std::deque<uint8_t> &data, google::protobuf::Message &message) { | |
uint32_t size = 0; | |
if (!read(data, size)) return false; | |
std::string str = std::string(size, ' '); | |
if (!pop_buf(data, reinterpret_cast<uint8_t *>(const_cast<char*>(str.data())), size_t(size))) return false; | |
if (!message.ParseFromString(str)) return false; | |
return true; | |
} | |
template<typename Value> | |
inline bool read_arr(std::deque<uint8_t> &data, std::vector<Value> &arr) { | |
uint32_t size = 0; | |
if (!read(data, size)) return false; | |
arr = std::vector<Value>(); | |
for(size_t i = 0; i < size_t(size); ++i) { | |
Value val; | |
if (!read(data, val)) return false; | |
try { arr.push_back(val); } catch(...) { return false; } | |
} | |
return true; | |
} | |
template<typename Key, typename Value> | |
inline bool read_map(std::deque<uint8_t> &data, std::map<Key, Value> &map) { | |
uint32_t size = 0; | |
if (!read(data, size)) return false; | |
map = std::map<Key, Value>(); | |
for(size_t i = 0; i < size_t(size); ++i) { | |
Key key; | |
if (!read(data, key)) return false; | |
Value value; | |
if (!read(data, value)) return false; | |
try { map[key] = value; } catch(...) { return false; } | |
} | |
return true; | |
} | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment