|
1 | 1 | #include <BStore.h> |
2 | 2 |
|
| 3 | +#include <unordered_map> |
| 4 | + |
3 | 5 | using namespace ToolFramework; |
4 | 6 |
|
5 | 7 | //////////////////////// |
@@ -48,22 +50,23 @@ BStore::BStore(const BStore &bs):m_version(1.0){ |
48 | 50 |
|
49 | 51 | if(bs.Header){ |
50 | 52 | Header = new BStore(*bs.Header); |
51 | | - } |
| 53 | + } else |
| 54 | + Header = nullptr; |
52 | 55 |
|
53 | 56 | m_lookup = bs.m_lookup; |
54 | 57 | output = bs.output; |
55 | | - m_file_end = m_file_end; |
56 | | - m_file_name = m_file_name; |
57 | | - m_open_file_end = m_open_file_end; |
58 | | - m_previous_file_end = m_previous_file_end; |
59 | | - m_type = m_type; |
60 | | - m_type_checking = m_type_checking; |
61 | | - m_has_header = m_has_header; |
62 | | - m_header_start = m_header_start; |
63 | | - m_flags_start = m_flags_start; |
64 | | - m_lookup_start = m_lookup_start; |
65 | | - m_update = m_update; |
66 | | - m_version = m_version; |
| 58 | + m_file_end = bs.m_file_end; |
| 59 | + m_file_name = bs.m_file_name; |
| 60 | + m_open_file_end = bs.m_open_file_end; |
| 61 | + m_previous_file_end = bs.m_previous_file_end; |
| 62 | + m_type = bs.m_type; |
| 63 | + m_type_checking = bs.m_type_checking; |
| 64 | + m_has_header = bs.m_has_header; |
| 65 | + m_header_start = bs.m_header_start; |
| 66 | + m_flags_start = bs.m_flags_start; |
| 67 | + m_lookup_start = bs.m_lookup_start; |
| 68 | + m_update = bs.m_update; |
| 69 | + m_version = bs.m_version; |
67 | 70 |
|
68 | 71 | } |
69 | 72 |
|
@@ -800,7 +803,10 @@ bool BStore::Serialise(BinaryStream &bs){ // do return properly |
800 | 803 |
|
801 | 804 | bs & output; |
802 | 805 | bs & m_lookup; |
803 | | - GetEntry(0); |
| 806 | + bs & m_variables; |
| 807 | + bs & m_type_checking; |
| 808 | + if (m_type_checking) bs & m_type_info; |
| 809 | + |
804 | 810 | /* |
805 | 811 | save; |
806 | 812 |
|
@@ -949,3 +955,111 @@ BStore::~BStore(){ |
949 | 955 |
|
950 | 956 |
|
951 | 957 | } |
| 958 | + |
| 959 | +namespace ToolFramework { |
| 960 | + bool json_encode(std::ostream& output, const BStore& store) { |
| 961 | + return store.JsonEncode(output); |
| 962 | + } |
| 963 | +}; |
| 964 | + |
| 965 | +template <typename T> |
| 966 | +static bool json_encode_bs(std::ostream& output, const BinaryStream& input) { |
| 967 | + T datum; |
| 968 | + // input must be const to conform to the JSON encoders interface layed out in |
| 969 | + // Json.h (const std::vector<BStore>& must be JSON-serializable) and to the |
| 970 | + // general idea that reading an object shouldn't change it. However, reading |
| 971 | + // from BinaryStream changes its position. We have to either cast away the |
| 972 | + // constness here or declare BinaryStream::m_pos mutable. I don't know which |
| 973 | + // way is better. --- Evgenii |
| 974 | + auto& in = const_cast<BinaryStream&>(input); |
| 975 | + in.m_pos = 0; |
| 976 | + return (in >> datum) && json_encode(output, datum); |
| 977 | +} |
| 978 | + |
| 979 | +// Maps typeid().name to a function that extracts data from BinaryStream and |
| 980 | +// prints it as JSON. |
| 981 | +// |
| 982 | +// Extend as needed |
| 983 | +std::unordered_map<std::string, bool (*)(std::ostream&, const BinaryStream&)> json_encoders { |
| 984 | +#define encoder(type) { typeid(type).name(), json_encode_bs<type> } |
| 985 | + encoder(bool), |
| 986 | + encoder(int), |
| 987 | + encoder(unsigned int), |
| 988 | + encoder(double), |
| 989 | + encoder(std::string), |
| 990 | + encoder(BStore), |
| 991 | + encoder(std::vector<int>), |
| 992 | + encoder(std::vector<double>), |
| 993 | + encoder(std::vector<std::string>), |
| 994 | + encoder(std::vector<BStore>) |
| 995 | +#undef encoder |
| 996 | +}; |
| 997 | + |
| 998 | +bool (*BStore::GetJsonEncoder(const std::string& key) const)(std::ostream&, const BinaryStream&){ |
| 999 | + auto type = m_type_info.find(key); |
| 1000 | + if (type == m_type_info.end()) return nullptr; |
| 1001 | + auto encoder = json_encoders.find(type->second); |
| 1002 | + if (encoder == json_encoders.end()) { |
| 1003 | + std::clog |
| 1004 | + << "BStore::JsonEncode: encoder for type " |
| 1005 | + << type->second |
| 1006 | + << " (field " |
| 1007 | + << key |
| 1008 | + << ") is not implemented" |
| 1009 | + << std::endl; |
| 1010 | + return nullptr; |
| 1011 | + }; |
| 1012 | + return encoder->second; |
| 1013 | +} |
| 1014 | + |
| 1015 | +bool BStore::JsonEncode(std::ostream& stream) const { |
| 1016 | + if (!m_type_checking) { |
| 1017 | + std::clog |
| 1018 | + << "BStore::JsonEncode: type checking is required for JSON encoding" |
| 1019 | + << std::endl; |
| 1020 | + return false; |
| 1021 | + }; |
| 1022 | + |
| 1023 | + bool comma = false; |
| 1024 | + stream << '{'; |
| 1025 | + for (auto& kv : m_variables) { |
| 1026 | + if (comma) |
| 1027 | + stream << ','; |
| 1028 | + else |
| 1029 | + comma = true; |
| 1030 | + if (!json_encode(stream, kv.first)) return false; |
| 1031 | + stream << ':'; |
| 1032 | + auto encoder = GetJsonEncoder(kv.first); |
| 1033 | + if (!encoder || !encoder(stream, kv.second)) return false; |
| 1034 | + }; |
| 1035 | + stream << '}'; |
| 1036 | + return true; |
| 1037 | +} |
| 1038 | + |
| 1039 | +bool BStore::JsonEncode(std::string& json) const { |
| 1040 | + std::stringstream ss; |
| 1041 | + if (!JsonEncode(ss)) return false; |
| 1042 | + json = ss.str(); |
| 1043 | + return true; |
| 1044 | +} |
| 1045 | + |
| 1046 | +bool BStore::JsonEncode(const std::string& key, std::ostream& stream) const { |
| 1047 | + if (!m_type_checking) { |
| 1048 | + std::clog |
| 1049 | + << "BStore::JsonEncode: type checking is required for JSON encoding" |
| 1050 | + << std::endl; |
| 1051 | + return false; |
| 1052 | + }; |
| 1053 | + |
| 1054 | + auto kv = m_variables.find(key); |
| 1055 | + if (kv == m_variables.end()) return false; |
| 1056 | + auto encoder = GetJsonEncoder(kv->first); |
| 1057 | + return encoder && encoder(stream, kv->second); |
| 1058 | +} |
| 1059 | + |
| 1060 | +bool BStore::JsonEncode(const std::string& key, std::string& json) const { |
| 1061 | + std::stringstream ss; |
| 1062 | + if (!JsonEncode(key, ss)) return false; |
| 1063 | + json = ss.str(); |
| 1064 | + return true; |
| 1065 | +} |
0 commit comments