Mercurial > code
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_ |