comparison C++/Pack.h @ 266:41bdde9027c0

Pack: * TypeInfo<T>::convert does not check and is constexpr * Pack::convert does the check though * Make overloads for std::[oi]stream available for different streams
author David Demelier <markand@malikania.fr>
date Tue, 14 Oct 2014 12:59:10 +0200
parents c6513d9c696b
children bc9b5e7421a7
comparison
equal deleted inserted replaced
265:4ddc300e8998 266:41bdde9027c0
44 enum Endian { 44 enum Endian {
45 Little, //! Little endian 45 Little, //! Little endian
46 Big //! Big endian 46 Big //! Big endian
47 }; 47 };
48 48
49 private:
50 static void writeFile(std::ofstream &, Endian)
51 {
52 // dummy, stop recursion
53 }
54
55 template <typename T, typename... Args>
56 static void writeFile(std::ofstream &out, Endian endian, const T &value, Args&... args)
57 {
58 static_assert(TypeInfo<T>::supported, "unsupported type");
59
60 T ret = convert(value, endian);
61 out.write(reinterpret_cast<const char *>(&ret), TypeInfo<T>::size);
62 writeFile(out, endian, args...);
63 }
64
65 static void readFile(std::ifstream &, Endian)
66 {
67 // dummy, stop recursion
68 }
69
70 template <typename T, typename... Args>
71 static void readFile(std::ifstream &in, Endian endian, T &value, Args&&... args)
72 {
73 static_assert(TypeInfo<T>::supported, "unsupported type");
74
75 in.read(reinterpret_cast<char *>(&value), TypeInfo<T>::size);
76 value = convert(value, endian);
77 readFile(in, endian, args...);
78 }
79
80 public: 49 public:
81 /** 50 /**
82 * Host system endian mode. 51 * Host system endian mode.
83 */ 52 */
84 static const Endian mode; 53 static const Endian mode;
90 * Used for conversions. 59 * Used for conversions.
91 */ 60 */
92 template <typename T> 61 template <typename T>
93 struct TypeInfo { 62 struct TypeInfo {
94 static const bool supported = false; 63 static const bool supported = false;
95 static const size_t size = 0;
96 }; 64 };
97 65
98 /** 66 /**
99 * Convert data. 67 * Convert data only if the requested endian is different.
100 * 68 *
101 * @param value the value to convert if needed 69 * @param value the value to convert if needed
102 * @param endian the endian mode 70 * @param endian the endian mode
103 * @return the converted value 71 * @return the converted value
104 */ 72 */
105 template <typename T> 73 template <typename T>
106 static T convert(T value, Endian endian); 74 static inline T convert(T value, Endian endian)
107 75 {
108 /** 76 static_assert(TypeInfo<T>::supported, "unsupported type");
109 * Write binary data to the file 77
78 if (endian != mode)
79 return TypeInfo<T>::convert(value, endian);
80
81 return value;
82 }
83
84 /**
85 * Write nothing, stop recursion.
86 */
87 static void write(std::ostream &, Endian)
88 {
89 }
90
91 /**
92 * Write binary data to the stream.
93 *
94 * @param out the output stream
95 * @param endian the endian mode
96 * @param args the arguments
97 * @throw std::runtime_exception on error
98 */
99 template <typename T, typename... Args>
100 static void write(std::ostream &out, Endian endian, const T &value, const Args&... args)
101 {
102 T ret = convert(value, endian);
103 out.write(reinterpret_cast<const char *>(&ret), TypeInfo<T>::size);
104 write(out, endian, args...);
105 }
106
107 /**
108 * Write binary data to the file.
110 * 109 *
111 * @param path the path to the file 110 * @param path the path to the file
112 * @param endian the endian mode 111 * @param endian the endian mode
113 * @param args the arguments 112 * @param args the arguments
114 * @throw std::runtime_exception on error 113 * @throw std::runtime_exception on error
115 */ 114 */
116 template <typename... Args> 115 template <typename... Args>
117 static void write(const std::string &path, 116 static void write(const std::string &path, Endian endian, const Args&... args)
118 Endian endian,
119 Args&&... args)
120 { 117 {
121 std::ofstream out; 118 std::ofstream out;
122 119
123 out.open(path, std::ios_base::binary); 120 out.open(path, std::ios_base::binary);
124 if (!out.is_open()) 121 if (!out.is_open())
125 throw std::runtime_error("Can't open file for writing"); 122 throw std::runtime_error("Can't open file for writing");
126 123
127 writeFile(out, endian, std::forward<Args>(args)...); 124 write(out, endian, args...);
128 } 125 }
129 126
130 /** 127 /**
131 * Read binary data from the file 128 * Read nothing, stop recursion.
129 */
130 static void read(std::istream &, Endian)
131 {
132 }
133
134 /**
135 * Read binary data from the stream.
136 *
137 * @param in the input stream
138 * @param endian the endian mode
139 * @param args the arguments
140 * @throw std::runtime_exception on error
141 */
142 template <typename T, typename... Args>
143 static void read(std::istream &in, Endian endian, T &value, Args&... args)
144 {
145 in.read(reinterpret_cast<char *>(&value), TypeInfo<T>::size);
146 value = convert(value, endian);
147 read(in, endian, args...);
148 }
149
150 /**
151 * Read binary data from the file.
132 * 152 *
133 * @param path the path to the file 153 * @param path the path to the file
134 * @param endian the endian mode 154 * @param endian the endian mode
135 * @param args the arguments 155 * @param args the arguments
136 * @throw std::runtime_exception on error 156 * @throw std::runtime_exception on error
137 */ 157 */
138 template <typename... Args> 158 template <typename... Args>
139 static void read(const std::string &path, 159 static void read(const std::string &path, Endian endian, Args&&... args)
140 Endian endian,
141 Args&&... args)
142 { 160 {
143 std::ifstream in; 161 std::ifstream in;
144 162
145 in.open(path, std::ios_base::binary); 163 in.open(path, std::ios_base::binary);
146 if (!in.is_open()) 164 if (!in.is_open())
147 throw std::runtime_error("Can't open file for reading"); 165 throw std::runtime_error("Can't open file for reading");
148 166
149 readFile(in, endian, std::forward<Args>(args)...); 167 read(in, endian, args...);
150 } 168 }
151 }; 169 };
152 170
153 template <> 171 template <>
154 struct Pack::TypeInfo<uint8_t> { 172 struct Pack::TypeInfo<uint8_t> {
155 static const bool supported = true; 173 static constexpr const bool supported = true;
156 static const size_t size = 1; 174 static constexpr const size_t size = sizeof (uint8_t);
175
176 static constexpr uint8_t convert(uint8_t v, Endian endian)
177 {
178 return v;
179 }
157 }; 180 };
158 181
159 template <> 182 template <>
160 struct Pack::TypeInfo<uint16_t> { 183 struct Pack::TypeInfo<uint16_t> {
161 static const bool supported = true; 184 static constexpr const bool supported = true;
162 static const size_t size = 2; 185 static constexpr const size_t size = sizeof (uint16_t);
186
187 static constexpr uint16_t convert(uint16_t v, Endian endian)
188 {
189 return (((v >> 8) & 0x00FFL) | ((v << 8) & 0xFF00L));
190 }
163 }; 191 };
164 192
165 template <> 193 template <>
166 struct Pack::TypeInfo<uint32_t> { 194 struct Pack::TypeInfo<uint32_t> {
167 static const bool supported = true; 195 static constexpr const bool supported = true;
168 static const size_t size = 4; 196 static constexpr const size_t size = sizeof (uint32_t);
169 }; 197
170 198 static constexpr uint32_t convert(uint32_t v, Endian endian)
171 template <> 199 {
172 struct Pack::TypeInfo<uint64_t> {
173 static const bool supported = true;
174 static const size_t size = 8;
175 };
176
177 template <>
178 inline uint8_t Pack::convert(uint8_t v, Endian)
179 {
180 return v;
181 }
182
183 template <>
184 inline uint16_t Pack::convert(uint16_t v, Endian endian)
185 {
186 if (mode != endian)
187 return (((v >> 8) & 0x00FFL) | ((v << 8) & 0xFF00L));
188
189 return v;
190 }
191
192 template <>
193 inline uint32_t Pack::convert(uint32_t v, Endian endian)
194 {
195 if (mode != endian)
196 return ((((v) >> 24) & 0x000000FFL) 200 return ((((v) >> 24) & 0x000000FFL)
197 | (((v) >> 8) & 0x0000FF00L) 201 | (((v) >> 8) & 0x0000FF00L)
198 | (((v) << 8) & 0x00FF0000L) 202 | (((v) << 8) & 0x00FF0000L)
199 | (((v) << 24) & 0xFF000000L)); 203 | (((v) << 24) & 0xFF000000L));
200 204 }
201 return v; 205 };
202 } 206
203 207 template <>
204 template <> 208 struct Pack::TypeInfo<uint64_t> {
205 inline uint64_t Pack::convert(uint64_t v, Endian endian) 209 static constexpr const bool supported = true;
206 { 210 static constexpr const size_t size = sizeof (uint64_t);
207 if (mode != endian) 211
212 static constexpr uint64_t convert(uint64_t v, Endian endian)
213 {
208 return ((((v) & 0xff00000000000000ull) >> 56) 214 return ((((v) & 0xff00000000000000ull) >> 56)
209 | (((v) & 0x00ff000000000000ull) >> 40) 215 | (((v) & 0x00ff000000000000ull) >> 40)
210 | (((v) & 0x0000ff0000000000ull) >> 24) 216 | (((v) & 0x0000ff0000000000ull) >> 24)
211 | (((v) & 0x000000ff00000000ull) >> 8 ) 217 | (((v) & 0x000000ff00000000ull) >> 8 )
212 | (((v) & 0x00000000ff000000ull) << 8 ) 218 | (((v) & 0x00000000ff000000ull) << 8 )
213 | (((v) & 0x0000000000ff0000ull) << 24) 219 | (((v) & 0x0000000000ff0000ull) << 24)
214 | (((v) & 0x000000000000ff00ull) << 40) 220 | (((v) & 0x000000000000ff00ull) << 40)
215 | (((v) & 0x00000000000000ffull) << 56)); 221 | (((v) & 0x00000000000000ffull) << 56));
216 222 }
217 return v; 223 };
218 }
219 224
220 #endif // !_PACK_H_ 225 #endif // !_PACK_H_