stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
idrec.hpp
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2016-2023 Amebis
4*/
5
6#pragma once
7
8#include "sal.hpp"
9#include <ios>
10#include <istream>
11#include <ostream>
12
13
14namespace stdex {
15 namespace idrec {
27 template <class T_ID>
28 _Success_(return) bool read_id(_In_ std::istream& stream, _Out_ T_ID &id, _In_opt_ std::streamoff end = (std::streamoff)-1)
29 {
30 if (end == (std::streamoff)-1 || stream.tellg() < end) {
31 stream.read((char*)&id, sizeof(id));
32 return stream.good();
33 } else
34 return false;
35 }
36
37
47 template <class T_SIZE, unsigned int ALIGN>
48 bool ignore(_In_ std::istream& stream)
49 {
50 // Read record size.
51 T_SIZE size;
52 stream.read((char*)&size, sizeof(size));
53 if (!stream.good()) return false;
54
55 // Skip the record data.
56 size += (T_SIZE)(ALIGN - size) % ALIGN;
57 stream.ignore(size);
58 if (!stream.good()) return false;
59
60 return true;
61 }
62
63
75 template <class T_ID, class T_SIZE, unsigned int ALIGN>
76 bool find(_In_ std::istream& stream, _In_ T_ID id, _In_opt_ std::streamoff end = (std::streamoff)-1)
77 {
78 T_ID _id;
79
80 while (end == (std::streamoff)-1 || stream.tellg() < end) {
81 stream.read((char*)&_id, sizeof(_id));
82 if (!stream.good()) return false;
83
84 if (_id == id) {
85 // The record was found.
86 return true;
87 } else
88 ignore<T_SIZE, ALIGN>(stream);
89 }
90
91 return false;
92 }
93
94
103 template <class T_ID, class T_SIZE>
104 std::streamoff open(_In_ std::ostream& stream, _In_ T_ID id)
105 {
106 std::streamoff start = stream.tellp();
107
108 // Write ID.
109 if (stream.fail()) return (std::streamoff)-1;
110 stream.write((const char*)&id, sizeof(id));
111
112 // Write 0 as a placeholder for data size.
113 if (stream.fail()) return (std::streamoff)-1;
114 T_SIZE size = 0;
115 stream.write((const char*)&size, sizeof(size));
116
117 return start;
118 }
119
120
129 template <class T_ID, class T_SIZE, unsigned int ALIGN>
130 std::streamoff close(_In_ std::ostream& stream, _In_ std::streamoff start)
131 {
132 std::streamoff end = stream.tellp();
133 T_SIZE
134 size = (T_SIZE)(end - start - sizeof(T_ID) - sizeof(T_SIZE)),
135 remainder = (T_SIZE)(ALIGN - size) % ALIGN; // Number of bytes we need to add, to keep the data integral number of ALIGN blocks long
136
137 if (remainder) {
138 // Append padding.
139 static const char padding[ALIGN] = {};
140 stream.write(padding, remainder);
141 end += remainder;
142 }
143
144 // Update the data size.
145 if (stream.fail()) return (std::streamoff)-1;
146 stream.seekp(start + sizeof(T_ID));
147 stream.write((const char*)&size, sizeof(size));
148 stream.seekp(end);
149
150 return end;
151 }
152
153
157 template <class T, class T_ID, const T_ID ID, class T_SIZE, unsigned int ALIGN>
158 class record
159 {
160 public:
166 record(_In_ T &d) : data(d) {}
167
168
174 record(_In_ const T &d) : data((T&)d) {}
175
176
180 static const T_ID id()
181 {
182 return ID;
183 }
184
185
194 {
195 data = r.data;
196 return *this;
197 }
198
199
207 static std::streamoff open(_In_ std::ostream& stream)
208 {
209 return stdex::idrec::open<T_ID, T_SIZE>(stream, ID);
210 }
211
212
221 static std::streamoff close(_In_ std::ostream& stream, _In_ std::streamoff start)
222 {
223 return stdex::idrec::close<T_ID, T_SIZE, ALIGN>(stream, start);
224 }
225
226
237 static bool find(_In_ std::istream& stream, _In_opt_ std::streamoff end = (std::streamoff)-1)
238 {
239 return stdex::idrec::find<T_ID, T_SIZE, ALIGN>(stream, ID, end);
240 }
241
242
243 T &data;
244 };
245 };
246};
247
248
257template <class T, class T_ID, T_ID ID, class T_SIZE, unsigned int ALIGN>
258std::ostream& operator <<(_In_ std::ostream& stream, _In_ const stdex::idrec::record<T, T_ID, ID, T_SIZE, ALIGN> r)
259{
260 // Parameter r does not need to be passed by reference. It has only one field (data), which is a reference itself already.
261
262 std::streamoff start = r.open(stream);
263 if (stream.fail()) return stream;
264 stream << r.data;
265 r.close(stream, start);
266
267 return stream;
268}
269
270
279template <class T, class T_ID, T_ID ID, class T_SIZE, unsigned int ALIGN>
280std::istream& operator >>(_In_ std::istream& stream, _In_ stdex::idrec::record<T, T_ID, ID, T_SIZE, ALIGN> r)
281{
282 // Parameter r does not need to be passed by reference. It has only one field (data), which is a reference itself already.
283
284 // Read data size.
285 T_SIZE size;
286 stream.read((char*)&size, sizeof(size));
287 if (!stream.good()) return stream;
288
289 // Read data.
290 std::streamoff start = stream.tellg();
291 stream >> r.data; // TODO: operator >> should not read past the record data! Make a size limited stream and read from it instead.
292
293 size += (T_SIZE)(ALIGN - size) % ALIGN;
294 stream.seekg(start + size);
295
296 return stream;
297}
Helper class for read/write of records to/from memory.
Definition idrec.hpp:159
static bool find(std::istream &stream, std::streamoff end=(std::streamoff) -1)
Finds record data.
Definition idrec.hpp:237
T & data
Record data reference.
Definition idrec.hpp:243
static const T_ID id()
Returns record id.
Definition idrec.hpp:180
static std::streamoff open(std::ostream &stream)
Writes record header.
Definition idrec.hpp:207
const record< T, T_ID, ID, T_SIZE, ALIGN > & operator=(const record< T, T_ID, ID, T_SIZE, ALIGN > &r)
Assignment operator.
Definition idrec.hpp:193
record(T &d)
Constructs the class.
Definition idrec.hpp:166
record(const T &d)
Constructs the class.
Definition idrec.hpp:174
static std::streamoff close(std::ostream &stream, std::streamoff start)
Updates record header.
Definition idrec.hpp:221