Skip to content

Instantly share code, notes, and snippets.

@chertov
Created July 13, 2020 17:58
Show Gist options
  • Save chertov/1c13584e27f05ffcfb99b5a537b9c3cb to your computer and use it in GitHub Desktop.
Save chertov/1c13584e27f05ffcfb99b5a537b9c3cb to your computer and use it in GitHub Desktop.
#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