697 lines
22 KiB
C++
697 lines
22 KiB
C++
#ifndef _HPROSE_TYPES_HPP_
|
|
#define _HPROSE_TYPES_HPP_
|
|
|
|
#include <vector>
|
|
#include <functional>
|
|
#include <cmath>
|
|
#include <map>
|
|
#include <unordered_map>
|
|
#include <atomic>
|
|
|
|
#include "hprose_ed.hpp"
|
|
|
|
template<typename T>
|
|
struct StdFuncType { using type = void; };
|
|
template<typename RET, typename CLASS, typename... ARGS>
|
|
struct StdFuncType<RET(CLASS::*)(ARGS...) const> { using type = std::function<RET(ARGS...)>; };
|
|
template<typename RET, typename CLASS, typename... ARGS>
|
|
struct StdFuncType<RET(CLASS::*)(ARGS...)> { using type = std::function<RET(ARGS...)>; };
|
|
|
|
template<typename HANDLER>
|
|
struct FunctionType { using type = typename StdFuncType<decltype(&HANDLER::operator())>::type; };
|
|
template<typename RET, typename... ARGS>
|
|
struct FunctionType<RET(*)(ARGS...)> { using type = std::function<RET(ARGS...)>; };
|
|
template<typename RET, typename CLASS, typename... ARGS>
|
|
struct FunctionType<RET(CLASS::*)(ARGS...)> { using type = RET(CLASS::*)(ARGS...); };
|
|
template<typename RET, typename CLASS, typename... ARGS>
|
|
struct FunctionType<RET(CLASS::*)(ARGS...) const> { using type = RET(CLASS::*)(ARGS...) const; };
|
|
|
|
template<int32_t INDEX, typename TYPE, typename FIRST, typename... REST>
|
|
struct IndexOfTypeHelper {
|
|
static constexpr int32_t value = std::conditional_t<std::is_same<TYPE, FIRST>::value, std::integral_constant<int32_t, INDEX>, IndexOfTypeHelper<INDEX + 1, TYPE, REST...>>::value;
|
|
};
|
|
template<int32_t INDEX, typename TYPE, typename ARG>
|
|
struct IndexOfTypeHelper<INDEX, TYPE, ARG> {
|
|
static constexpr int32_t value = std::conditional_t<std::is_same<TYPE, ARG>::value, std::integral_constant<int32_t, INDEX>, std::integral_constant<int32_t, -1>>::value;
|
|
};
|
|
template<typename T, typename... ARGS>
|
|
struct IndexOfType { static constexpr int32_t value = IndexOfTypeHelper<0, T, ARGS...>::value; };
|
|
template<typename T>
|
|
struct IndexOfType<T> { static constexpr int32_t value = -1; };
|
|
|
|
class HproseError {
|
|
public:
|
|
HproseError() : is_null(true) {}
|
|
HproseError(const std::string& msg) : is_null(false), errmsg(msg) {}
|
|
HproseError(std::string&& msg) : is_null(false), errmsg(std::move(msg)) {}
|
|
bool IsNull() const { return is_null; }
|
|
const std::string& Message() const { return errmsg; }
|
|
operator bool () { return !is_null; }
|
|
|
|
protected:
|
|
bool is_null;
|
|
std::string errmsg;
|
|
};
|
|
|
|
struct HproseValueHelperError {
|
|
HproseError FromReader(HproseReader& reader) {
|
|
reader.CheckTag(Tags::Null, true);
|
|
return HproseError();
|
|
}
|
|
bool ToWriterWithResultTag(const HproseError& err, HproseWriter& writer) {
|
|
if(err.IsNull())
|
|
writer.WriteTag(Tags::Result);
|
|
else
|
|
writer.WriteTag(Tags::Error);
|
|
ToWriter(err, writer);
|
|
return !err.IsNull();
|
|
}
|
|
void ToWriter(const HproseError& err, HproseWriter& writer) {
|
|
if(err.IsNull())
|
|
writer.WriteTag(Tags::Null);
|
|
else {
|
|
const std::string& errmsg = err.Message();
|
|
writer.WriteTag(Tags::String);
|
|
writer.WriteLength(errmsg.length());
|
|
writer.WriteTag(Tags::Quote);
|
|
writer.WriteString(errmsg);
|
|
writer.WriteTag(Tags::Quote);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct HproseValueHelperNull {
|
|
bool ToWriterWithResultTag(HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Result);
|
|
writer.WriteTag(Tags::Null);
|
|
return false;
|
|
}
|
|
void ToWriter(HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Null);
|
|
}
|
|
};
|
|
|
|
struct HproseValueHelperInteger {
|
|
int64_t FromReader(HproseReader& r) {
|
|
auto tag = r.ReadTag();
|
|
switch(tag) {
|
|
case Tags::Null: return 0;
|
|
case Tags::Empty: return 0;
|
|
case Tags::Num0: return 0;
|
|
case Tags::Num1: return 1;
|
|
case Tags::Num2: return 2;
|
|
case Tags::Num3: return 3;
|
|
case Tags::Num4: return 4;
|
|
case Tags::Num5: return 5;
|
|
case Tags::Num6: return 6;
|
|
case Tags::Num7: return 7;
|
|
case Tags::Num8: return 8;
|
|
case Tags::Num9: return 9;
|
|
case Tags::False: return 0;
|
|
case Tags::True: return 1;
|
|
case Tags::NaN: return 0;
|
|
case Tags::Infinity: {
|
|
r.ReadTag();
|
|
return 0;
|
|
}
|
|
case Tags::Integer:
|
|
case Tags::Long: { // golang use big.int to decode Long
|
|
return r.ReadInt64Raw(Tags::Semicolon);
|
|
}
|
|
case Tags::Double: {
|
|
return int64_t(strtod(r.ReadUntilAsString(Tags::Semicolon).data(), nullptr));
|
|
}
|
|
case Tags::UTF8Char: {
|
|
return strtoll(r.ReadUTF8String(1).data(), nullptr, 10);
|
|
}
|
|
case Tags::String: {
|
|
return strtoll(r.ReadUTF8String(r.ReadInt64Raw(Tags::Quote)).data(), nullptr, 10);
|
|
}
|
|
case Tags::Bytes: {
|
|
return strtoll(r.ReadBytesAsString(r.ReadInt64Raw(Tags::Quote)).data(), nullptr, 10);
|
|
}
|
|
default: {
|
|
r.SkipValue(tag);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
bool ToWriterWithResultTag(int64_t value, HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Result);
|
|
ToWriter(value, writer);
|
|
return false;
|
|
}
|
|
void ToWriter(int64_t value, HproseWriter& writer) {
|
|
if(value >= 0 && value <= 9) {
|
|
writer.WriteByte(value + '0');
|
|
return;
|
|
}
|
|
if(value >= -0xffffffff && value <= 0xffffffff)
|
|
writer.WriteTag(Tags::Integer);
|
|
else
|
|
writer.WriteTag(Tags::Long);
|
|
writer.WriteInteger(value);
|
|
writer.WriteTag(Tags::Semicolon);
|
|
}
|
|
};
|
|
|
|
struct HproseValueHelperBool {
|
|
bool FromReader(HproseReader& r) {
|
|
auto tag = r.ReadTag();
|
|
switch(tag) {
|
|
case Tags::Null:
|
|
case Tags::Empty:
|
|
case Tags::Num0: return false;
|
|
case Tags::Num1:
|
|
case Tags::Num2:
|
|
case Tags::Num3:
|
|
case Tags::Num4:
|
|
case Tags::Num5:
|
|
case Tags::Num6:
|
|
case Tags::Num7:
|
|
case Tags::Num8:
|
|
case Tags::Num9: return true;
|
|
case Tags::False: return false;
|
|
case Tags::True: return true;
|
|
case Tags::NaN: return false;
|
|
case Tags::Infinity: {
|
|
r.ReadTag();
|
|
return true;
|
|
}
|
|
case Tags::Integer:
|
|
case Tags::Long: {
|
|
return r.ReadInt64Raw(Tags::Semicolon) != 0;
|
|
}
|
|
case Tags::Double: {
|
|
return strtod(r.ReadUntilAsString(Tags::Semicolon).data(), nullptr) != 0.0;
|
|
}
|
|
case Tags::UTF8Char: {
|
|
return r.ReadUTF8String(1) != "0";
|
|
}
|
|
case Tags::String: {
|
|
return CheckString(r.ReadUTF8String(r.ReadInt64Raw(Tags::Quote)));
|
|
}
|
|
case Tags::Bytes: {
|
|
return CheckString(r.ReadBytesAsString(r.ReadInt64Raw(Tags::Quote)));
|
|
}
|
|
default: {
|
|
r.SkipValue(tag);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
bool CheckString(const std::string& str) {
|
|
return str != "";
|
|
}
|
|
bool ToWriterWithResultTag(bool value, HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Result);
|
|
ToWriter(value, writer);
|
|
return false;
|
|
}
|
|
void ToWriter(bool value, HproseWriter& writer) {
|
|
writer.WriteTag(value ? Tags::True : Tags::False);
|
|
}
|
|
};
|
|
|
|
struct HproseValueHelperDouble {
|
|
double FromReader(HproseReader& r) {
|
|
auto tag = r.ReadTag();
|
|
switch(tag) {
|
|
case Tags::Null: return 0.0;
|
|
case Tags::Empty: return 0.0;
|
|
case Tags::Num0: return 0.0;
|
|
case Tags::Num1: return 1.0;
|
|
case Tags::Num2: return 2.0;
|
|
case Tags::Num3: return 3.0;
|
|
case Tags::Num4: return 4.0;
|
|
case Tags::Num5: return 5.0;
|
|
case Tags::Num6: return 6.0;
|
|
case Tags::Num7: return 7.0;
|
|
case Tags::Num8: return 8.0;
|
|
case Tags::Num9: return 9.0;
|
|
case Tags::False: return 0.0;
|
|
case Tags::True: return 1.0;
|
|
case Tags::NaN: return std::numeric_limits<double>::quiet_NaN();
|
|
case Tags::Infinity: {
|
|
auto t = r.ReadTag();
|
|
return (t == Tags::Pos) ? std::numeric_limits<double>::infinity() : -std::numeric_limits<double>::infinity();
|
|
}
|
|
case Tags::Integer:
|
|
case Tags::Long: {
|
|
return double(r.ReadInt64Raw(Tags::Semicolon));
|
|
}
|
|
case Tags::Double: {
|
|
return strtod(r.ReadUntilAsString(Tags::Semicolon).data(), nullptr);
|
|
}
|
|
case Tags::UTF8Char: {
|
|
return strtod(r.ReadUTF8String(1).data(), nullptr);
|
|
}
|
|
case Tags::String: {
|
|
return strtod(r.ReadUTF8String(r.ReadInt64Raw(Tags::Quote)).data(), nullptr);
|
|
}
|
|
case Tags::Bytes: {
|
|
return strtod(r.ReadBytesAsString(r.ReadInt64Raw(Tags::Quote)).data(), nullptr);
|
|
}
|
|
default: {
|
|
r.SkipValue(tag);
|
|
return 0.0;
|
|
}
|
|
}
|
|
}
|
|
bool ToWriterWithResultTag(double value, HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Result);
|
|
ToWriter(value, writer);
|
|
return false;
|
|
}
|
|
void ToWriter(double value, HproseWriter& writer) {
|
|
if(std::isnan(value)) {
|
|
writer.WriteTag(Tags::NaN);
|
|
return;
|
|
}
|
|
if(std::isinf(value)) {
|
|
writer.WriteTag(Tags::Infinity);
|
|
writer.WriteTag(value > 0 ? Tags::Pos : Tags::Neg);
|
|
return;
|
|
}
|
|
writer.WriteTag(Tags::Double);
|
|
writer.WriteDouble(value);
|
|
writer.WriteTag(Tags::Semicolon);
|
|
}
|
|
};
|
|
|
|
struct HproseValueHelperString {
|
|
std::string FromReader(HproseReader& r) {
|
|
auto tag = r.ReadTag();
|
|
switch(tag) {
|
|
case Tags::Null: return "";
|
|
case Tags::Empty: return "";
|
|
case Tags::Num0: return "0";
|
|
case Tags::Num1: return "1";
|
|
case Tags::Num2: return "2";
|
|
case Tags::Num3: return "3";
|
|
case Tags::Num4: return "4";
|
|
case Tags::Num5: return "5";
|
|
case Tags::Num6: return "6";
|
|
case Tags::Num7: return "7";
|
|
case Tags::Num8: return "8";
|
|
case Tags::Num9: return "9";
|
|
case Tags::False: return "false";
|
|
case Tags::True: return "true";
|
|
case Tags::NaN: return "nan";
|
|
case Tags::Infinity: {
|
|
auto t = r.ReadTag();
|
|
return (t == Tags::Pos) ? "+inf" : "-inf";
|
|
}
|
|
case Tags::Integer:
|
|
case Tags::Long:
|
|
case Tags::Double: {
|
|
return r.ReadUntilAsString(Tags::Semicolon);
|
|
}
|
|
case Tags::UTF8Char: {
|
|
return r.ReadUTF8String(1);
|
|
}
|
|
case Tags::String: {
|
|
return r.ReadUTF8String(r.ReadInt64Raw(Tags::Quote));
|
|
}
|
|
case Tags::Bytes: {
|
|
return r.ReadBytesAsString(r.ReadInt64Raw(Tags::Quote));
|
|
}
|
|
default: {
|
|
r.SkipValue(tag);
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
bool ToWriterWithResultTag(const std::string& value, HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Result);
|
|
ToWriter(value, writer);
|
|
return false;
|
|
}
|
|
void ToWriter(const std::string& value, HproseWriter& writer) {
|
|
if(value.empty()) {
|
|
writer.WriteTag(Tags::Empty);
|
|
return;
|
|
}
|
|
if(value.length() == 1) {
|
|
writer.WriteTag(Tags::UTF8Char);
|
|
writer.WriteByte(value[0]);
|
|
return;
|
|
}
|
|
writer.WriteTag(Tags::String);
|
|
writer.WriteLength(value.length());
|
|
writer.WriteTag(Tags::Quote);
|
|
writer.WriteString(value);
|
|
writer.WriteTag(Tags::Quote);
|
|
}
|
|
|
|
std::string FromReaderRaw(HproseReader& r) {
|
|
return r.ReadUTF8String(r.ReadInt64Raw(Tags::Quote));
|
|
}
|
|
|
|
void ToWriterRaw(const std::string& value, HproseWriter& writer, bool with_tag) {
|
|
if(with_tag)
|
|
writer.WriteTag(Tags::String);
|
|
writer.WriteLength(value.length());
|
|
writer.WriteTag(Tags::Quote);
|
|
writer.WriteString(value);
|
|
writer.WriteTag(Tags::Quote);
|
|
}
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
struct HproseValueHelperStruct {
|
|
T FromReader(HproseReader& reader) {
|
|
T val;
|
|
auto tag = reader.ReadTag();
|
|
switch(tag) {
|
|
case Tags::Class: {
|
|
HproseValueHelperString().FromReaderRaw(reader);
|
|
int32_t count = reader.ReadInt64Raw(Tags::Openbrace);
|
|
std::vector<std::string> fields;
|
|
for(int32_t i = 0; i < count; ++i)
|
|
fields.emplace_back(HproseValueHelperString().FromReader(reader));
|
|
reader.PushFieldRefs(std::move(fields));
|
|
reader.CheckTag(Tags::Closebrace, true);
|
|
reader.CheckTag(Tags::Object, true);
|
|
}
|
|
case Tags::Object: {
|
|
int32_t index = reader.ReadInt64Raw(Tags::Openbrace);
|
|
auto& fields = reader.GetFieldRefs(index);
|
|
auto& refmap = val.GetFieldMaps();
|
|
for(size_t i = 0; i < fields.size(); ++i)
|
|
refmap.ReadField((uintptr_t)&val, fields[i], reader);
|
|
reader.CheckTag(Tags::Closebrace, true);
|
|
return val;
|
|
}
|
|
default: {
|
|
reader.SkipValue(tag);
|
|
return val;
|
|
}
|
|
}
|
|
}
|
|
bool ToWriterWithResultTag(const T& val, HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Result);
|
|
val.GetFieldMaps().ToWriter((uintptr_t)&val, writer);
|
|
return false;
|
|
}
|
|
void ToWriter(const T& val, HproseWriter& writer) {
|
|
val.GetFieldMaps().ToWriter((uintptr_t)&val, writer);
|
|
}
|
|
};
|
|
|
|
template<typename T> struct HproseValueHelperImpl { using type = HproseValueHelperStruct<T>; };
|
|
template<> struct HproseValueHelperImpl<int> { using type = HproseValueHelperInteger; };
|
|
template<> struct HproseValueHelperImpl<HproseError> { using type = HproseValueHelperError; };
|
|
template<> struct HproseValueHelperImpl<bool> { using type = HproseValueHelperBool; };
|
|
template<> struct HproseValueHelperImpl<float> { using type = HproseValueHelperDouble; };
|
|
template<> struct HproseValueHelperImpl<double> { using type = HproseValueHelperDouble; };
|
|
template<> struct HproseValueHelperImpl<char*> { using type = HproseValueHelperString; };
|
|
template<> struct HproseValueHelperImpl<const char*> { using type = HproseValueHelperString; };
|
|
template<> struct HproseValueHelperImpl<std::string> { using type = HproseValueHelperString; };
|
|
|
|
template<typename T>
|
|
using HproseValueHelper = typename HproseValueHelperImpl<std::remove_cv_t<std::remove_reference_t<T>>>::type;
|
|
|
|
template<typename T>
|
|
struct HproseValueHelperSlice {
|
|
std::vector<T> FromReader(HproseReader& reader) {
|
|
std::vector<T> ret;
|
|
auto tag = reader.ReadTag();
|
|
switch(tag) {
|
|
case Tags::List: {
|
|
HproseValueHelper<T> vh;
|
|
int64_t count = reader.ReadInt64Raw(Tags::Openbrace);
|
|
for(int64_t i = 0; i < count; ++i)
|
|
ret.push_back(vh.FromReader(reader));
|
|
reader.CheckTag(Tags::Closebrace, true);
|
|
return ret;
|
|
}
|
|
default: {
|
|
reader.SkipValue(tag);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
bool ToWriterWithResultTag(const std::vector<T>& value, HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Result);
|
|
ToWriter(value, writer);
|
|
return false;
|
|
}
|
|
void ToWriter(const std::vector<T>& values, HproseWriter& writer) {
|
|
HproseValueHelper<T> vh;
|
|
writer.WriteTag(Tags::List);
|
|
writer.WriteLength(values.size());
|
|
writer.WriteTag(Tags::Openbrace);
|
|
for(auto& v : values)
|
|
vh.ToWriter(v, writer);
|
|
writer.WriteTag(Tags::Closebrace);
|
|
}
|
|
};
|
|
|
|
template<typename K, typename V, typename MAP>
|
|
struct HproseValueHelperMap {
|
|
MAP FromReader(HproseReader& reader) {
|
|
MAP ret;
|
|
auto tag = reader.ReadTag();
|
|
switch(tag) {
|
|
case Tags::Map: {
|
|
HproseValueHelper<K> kvh;
|
|
HproseValueHelper<V> vvh;
|
|
int64_t count = reader.ReadInt64Raw(Tags::Openbrace);
|
|
for(int64_t i = 0; i < count; ++i) {
|
|
auto k = kvh.FromReader(reader);
|
|
auto v = vvh.FromReader(reader);
|
|
ret[k] = v;
|
|
}
|
|
reader.CheckTag(Tags::Closebrace, true);
|
|
return ret;
|
|
}
|
|
default: {
|
|
reader.SkipValue(tag);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
bool ToWriterWithResultTag(const MAP& value, HproseWriter& writer) {
|
|
writer.WriteTag(Tags::Result);
|
|
ToWriter(value, writer);
|
|
return false;
|
|
}
|
|
void ToWriter(const MAP& value, HproseWriter& writer) {
|
|
HproseValueHelper<K> kvh;
|
|
HproseValueHelper<V> vvh;
|
|
writer.WriteTag(Tags::Map);
|
|
writer.WriteLength(value.size());
|
|
writer.WriteTag(Tags::Openbrace);
|
|
for(auto& iter : value) {
|
|
kvh.ToWriter(iter.first, writer);
|
|
vvh.ToWriter(iter.second, writer);
|
|
}
|
|
writer.WriteTag(Tags::Closebrace);
|
|
}
|
|
};
|
|
|
|
template<int32_t INDEX>
|
|
struct ErrorChecker {
|
|
template<typename T>
|
|
bool IsError(T& val) {
|
|
return !std::get<INDEX>(val).IsNull();
|
|
}
|
|
template<typename T>
|
|
void WriteError(T& val, HproseWriter& writer) {
|
|
HproseValueHelperError().ToWriterWithResultTag(std::get<INDEX>(val), writer);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct ErrorChecker<-1> {
|
|
template<typename T>
|
|
bool IsError(T& val) { return false; }
|
|
template<typename T>
|
|
void WriteError(T& val, HproseWriter& writer) {}
|
|
};
|
|
|
|
template<typename ... ARGS>
|
|
struct HproseValueHelperTuple {
|
|
using helper_type = std::tuple<HproseValueHelper<ARGS>...>;
|
|
|
|
std::tuple<ARGS...> FromReader(HproseReader& reader) {
|
|
std::tuple<ARGS...> ret;
|
|
auto tag = reader.ReadTag();
|
|
switch(tag) {
|
|
case Tags::List: {
|
|
helper_type vhs;
|
|
int64_t count = reader.ReadInt64Raw(Tags::Openbrace);
|
|
FromReaderImpl(ret, vhs, reader, count, std::make_index_sequence<sizeof...(ARGS)>{});
|
|
for(int32_t i = sizeof...(ARGS); i < count; ++i)
|
|
reader.SkipValue();
|
|
reader.CheckTag(Tags::Closebrace, true);
|
|
return ret;
|
|
}
|
|
default: {
|
|
reader.SkipValue(tag);
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
void FromReaderImpl(std::tuple<ARGS...>& value, helper_type& vhs, HproseReader& reader, int64_t count, std::index_sequence<>) {}
|
|
|
|
template<size_t I, size_t... R>
|
|
void FromReaderImpl(std::tuple<ARGS...>& value, helper_type& vhs, HproseReader& reader, int64_t count, std::index_sequence<I, R...>) {
|
|
if(I < (size_t)count) {
|
|
std::get<I>(value) = std::get<I>(vhs).FromReader(reader);
|
|
FromReaderImpl(value, vhs, reader, count, std::index_sequence<R...>{});
|
|
}
|
|
}
|
|
|
|
bool ToWriterWithResultTag(const std::tuple<ARGS...>& value, HproseWriter& writer) {
|
|
ErrorChecker<IndexOfType<HproseError, ARGS...>::value> checker;
|
|
bool has_error = checker.IsError(value);
|
|
if(has_error) {
|
|
checker.WriteError(value, writer);
|
|
} else {
|
|
writer.WriteTag(Tags::Result);
|
|
ToWriter(value, writer);
|
|
}
|
|
return has_error;
|
|
}
|
|
|
|
void ToWriter(const std::tuple<ARGS...>& value, HproseWriter& writer) {
|
|
helper_type vhs;
|
|
writer.WriteTag(Tags::List);
|
|
writer.WriteLength(sizeof...(ARGS));
|
|
writer.WriteTag(Tags::Openbrace);
|
|
ToWriterImpl(value, vhs, writer, std::make_index_sequence<sizeof...(ARGS)>{});
|
|
writer.WriteTag(Tags::Closebrace);
|
|
}
|
|
|
|
void ToWriterImpl(const std::tuple<ARGS...>& value, helper_type& vhs, HproseWriter& writer, std::index_sequence<>) {}
|
|
|
|
template<size_t I, size_t... R>
|
|
void ToWriterImpl(const std::tuple<ARGS...>& value, helper_type& vhs, HproseWriter& writer, std::index_sequence<I, R...>) {
|
|
std::get<I>(vhs).ToWriter(std::get<I>(value), writer);
|
|
ToWriterImpl(value, vhs, writer, std::index_sequence<R...>{});
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
struct HproseValueHelperImpl<std::vector<T>> { using type = HproseValueHelperSlice<T>; };
|
|
template<typename K, typename V>
|
|
struct HproseValueHelperImpl<std::map<K, V>> { using type = HproseValueHelperMap<K, V, std::map<K, V>>; };
|
|
template<typename K, typename V>
|
|
struct HproseValueHelperImpl<std::unordered_map<K, V>> { using type = HproseValueHelperMap<K, V, std::unordered_map<K, V>>; };
|
|
template<typename ... ARGS>
|
|
struct HproseValueHelperImpl<std::tuple<ARGS...>> { using type = HproseValueHelperTuple<ARGS...>; };
|
|
|
|
struct HproseReflector {
|
|
virtual void FromReader(uintptr_t addr, HproseReader& r) = 0;
|
|
virtual void ToWriter(uintptr_t addr, HproseWriter& w) = 0;
|
|
virtual const std::string& GetName() = 0;
|
|
virtual ~HproseReflector() {}
|
|
};
|
|
|
|
template<typename T>
|
|
struct HproseReflectType : public HproseReflector {
|
|
HproseReflectType(uintptr_t off, const std::string& n) : offset(off), name(n) {}
|
|
virtual void FromReader(uintptr_t addr, HproseReader& r) {
|
|
T* ptr = (T*)(addr + offset);
|
|
*ptr = HproseValueHelper<T>().FromReader(r);
|
|
}
|
|
virtual void ToWriter(uintptr_t addr, HproseWriter& w) {
|
|
T* ptr = (T*)(addr + offset);
|
|
HproseValueHelper<T>().ToWriter(*ptr, w);
|
|
}
|
|
virtual const std::string& GetName() {
|
|
return name;
|
|
}
|
|
uintptr_t offset;
|
|
std::string name;
|
|
};
|
|
|
|
struct HproseReflectMap {
|
|
bool IsInited() { return inited; }
|
|
|
|
void Init(const std::string& name) {
|
|
struct_name = name;
|
|
inited = true;
|
|
}
|
|
|
|
template<typename T>
|
|
void RegisterField(T* t, const std::string& fname) {
|
|
auto reflector = new HproseReflectType<T>((uintptr_t)t, fname);
|
|
fields[fname] = std::unique_ptr<HproseReflector>(reflector);
|
|
}
|
|
|
|
void ReadField(uintptr_t struct_ptr, const std::string& name, HproseReader& reader) {
|
|
auto iter = fields.find(name);
|
|
if(iter == fields.end()) {
|
|
reader.SkipValue();
|
|
return;
|
|
}
|
|
iter->second->FromReader(struct_ptr, reader);
|
|
}
|
|
|
|
void ToWriter(uintptr_t struct_ptr, HproseWriter& writer) const {
|
|
auto idx = writer.GetStructFieldsIndex(struct_name);
|
|
if(idx == -1) {
|
|
idx = writer.PushFieldRefs(struct_name);
|
|
WriteFields(writer);
|
|
}
|
|
writer.WriteTag(Tags::Object);
|
|
HproseValueHelperInteger().ToWriter(idx, writer);
|
|
writer.WriteTag(Tags::Openbrace);
|
|
for(auto& iter : fields)
|
|
iter.second->ToWriter(struct_ptr, writer);
|
|
writer.WriteTag(Tags::Closebrace);
|
|
}
|
|
|
|
void WriteFields(HproseWriter& writer) const {
|
|
writer.WriteTag(Tags::Class);
|
|
HproseValueHelperString().ToWriterRaw(struct_name, writer, false);
|
|
HproseValueHelperInteger().ToWriter(fields.size(), writer);
|
|
writer.WriteTag(Tags::Openbrace);
|
|
for(auto& iter : fields)
|
|
HproseValueHelperString().ToWriterRaw(iter.first, writer, true);
|
|
writer.WriteTag(Tags::Closebrace);
|
|
}
|
|
|
|
bool inited = false;
|
|
std::string struct_name;
|
|
std::map<std::string, std::unique_ptr<HproseReflector>> fields;
|
|
};
|
|
|
|
#define FE_1(FUN, FIELD) FUN(FIELD)
|
|
#define FE_2(FUN, FIELD, ...) FUN(FIELD)FE_1(FUN, __VA_ARGS__)
|
|
#define FE_3(FUN, FIELD, ...) FUN(FIELD)FE_2(FUN, __VA_ARGS__)
|
|
#define FE_4(FUN, FIELD, ...) FUN(FIELD)FE_3(FUN, __VA_ARGS__)
|
|
#define FE_5(FUN, FIELD, ...) FUN(FIELD)FE_4(FUN, __VA_ARGS__)
|
|
#define FE_6(FUN, FIELD, ...) FUN(FIELD)FE_5(FUN, __VA_ARGS__)
|
|
#define FE_7(FUN, FIELD, ...) FUN(FIELD)FE_6(FUN, __VA_ARGS__)
|
|
#define FE_8(FUN, FIELD, ...) FUN(FIELD)FE_7(FUN, __VA_ARGS__)
|
|
|
|
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME
|
|
#define FOR_EACH(action,...) GET_MACRO(__VA_ARGS__,FE_8,FE_7,FE_6,FE_5,FE_4,FE_3,FE_2,FE_1)(action,__VA_ARGS__)
|
|
|
|
#define PUSH_FIELD(FIELD) ref_map.RegisterField(&ptr->FIELD, #FIELD);
|
|
|
|
#define HPROSE_REFLECT(struct_type, ...) \
|
|
public:\
|
|
static HproseReflectMap& GetFieldMaps() {\
|
|
static HproseReflectMap ref_map;\
|
|
if(ref_map.IsInited())\
|
|
return ref_map;\
|
|
static std::atomic<bool> inited(false);\
|
|
bool expected = false;\
|
|
if(inited.compare_exchange_strong(expected, true)) {\
|
|
struct_type* ptr = nullptr;\
|
|
FOR_EACH(PUSH_FIELD, __VA_ARGS__)\
|
|
ref_map.Init(#struct_type);\
|
|
} else {\
|
|
while(!ref_map.IsInited());\
|
|
}\
|
|
return ref_map;\
|
|
}
|
|
|
|
#endif
|