1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
#include <cstring>
#include <iostream>
#include <vector>
// all the different specializations
class Transformer_Copy;
class Transformer_Zero;
// abstract base class to pass around the different structures
class Wrapper {
public:
// for every transformer specialization you'll need these two functions
// Transformer_Copy
virtual void to_object(std::vector<unsigned char> bytes,
Transformer_Copy *transformer) = 0;
virtual std::vector<unsigned char>
to_bytes(Transformer_Copy *transformer) = 0;
// Transformer_Zero
virtual void to_object(std::vector<unsigned char> bytes,
Transformer_Zero *transformer) = 0;
virtual std::vector<unsigned char>
to_bytes(Transformer_Zero *transformer) = 0;
};
class Transformer {
public:
// note that it works with a Wrapper, no templates here
// all specializations will implement these two functions the same way
// so using CRTP for that
virtual void to_object(std::vector<unsigned char> bytes,
Wrapper *structure) = 0;
virtual std::vector<unsigned char> to_bytes(Wrapper *structure) = 0;
};
// CRTP
// call the appropriate function in the Wrapper class according to the template
// parameter
template <class T> class Transformer_Instance : public Transformer {
public:
virtual void to_object(std::vector<unsigned char> bytes,
Wrapper *structure) override {
structure->to_object(bytes, reinterpret_cast<T *>(this));
}
virtual std::vector<unsigned char> to_bytes(Wrapper *structure) override {
return structure->to_bytes(reinterpret_cast<T *>(this));
}
};
class Transformer_Copy : public Transformer_Instance<Transformer_Copy> {
public:
// actual work
// yes, they are template, but not virtual
template <class T> std::vector<unsigned char> to_bytes_template(T structure) {
std::vector<unsigned char> bytes{};
bytes.resize(sizeof(structure));
std::memcpy(&bytes[0], &structure, sizeof(structure));
return bytes;
}
template <class T>
void to_object_template(std::vector<unsigned char> bytes, T &structure) {
std::memcpy(&structure, &bytes[0], sizeof(structure));
}
};
// another specialization
class Transformer_Zero : public Transformer_Instance<Transformer_Zero> {
public:
// actual work
template <class T> std::vector<unsigned char> to_bytes_template(T structure) {
std::vector<unsigned char> bytes{};
bytes.resize(sizeof(structure));
return bytes;
}
template <class T>
void to_object_template(std::vector<unsigned char> bytes, T &structure) {
bzero(&structure, sizeof(bytes.size()));
}
};
// the dispatcher
template <class T> class Wrapper_Instance : public Wrapper {
public:
T value;
Wrapper_Instance(T value) : value(value) {}
// here we deal with the derived class directly, so can call their specific
// member functions
// again, note that all specializations have the same code
// Transformer_Copy
virtual void to_object(std::vector<unsigned char> bytes,
Transformer_Copy *transformer) override {
transformer->to_object_template(bytes, value);
}
virtual std::vector<unsigned char>
to_bytes(Transformer_Copy *transformer) override {
return transformer->to_bytes_template(value);
}
// Transformer_Zero
virtual void to_object(std::vector<unsigned char> bytes,
Transformer_Zero *transformer) override {
transformer->to_object_template(bytes, value);
}
virtual std::vector<unsigned char>
to_bytes(Transformer_Zero *transformer) override {
return transformer->to_bytes_template(value);
}
};
// usage example
template <typename TStructure>
void cout_bytes(Transformer *transformer, TStructure structure) {
Wrapper_Instance<TStructure> wrapper(structure); // wrapping
auto bytes = transformer->to_bytes(&wrapper);
for (auto byte : bytes) {
std::cout << (int)byte << ' ';
}
std::cout << std::endl;
}
template <typename TStructure>
void recover(Transformer *transformer, std::vector<unsigned char> v,
TStructure &structure) {
Wrapper_Instance<TStructure> wrapper(structure); // wrapping
transformer->to_object(v, &wrapper);
structure = wrapper.value;
}
int main() {
Transformer_Copy transformer_copy{};
Transformer_Zero transformer_zero{};
int integer = 5;
float someFloat = 9.79;
std::vector<unsigned char> v{215, 163, 28,
65}; // the bytes of the float in my case
std::cout << "Copy\n";
cout_bytes(&transformer_copy, integer);
cout_bytes(&transformer_copy, someFloat);
recover(&transformer_copy, v, integer);
recover(&transformer_copy, v, someFloat);
std::cout << integer << '\n' << someFloat << '\n';
std::cout << "\n\nZero\n";
cout_bytes(&transformer_zero, integer);
cout_bytes(&transformer_zero, someFloat);
recover(&transformer_zero, v, integer);
recover(&transformer_zero, v, someFloat);
std::cout << integer << '\n' << someFloat << '\n';
}
|