stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
idrec.h
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2016-2022 Amebis
4*/
5
6#pragma once
7
8#include "sal.h"
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, 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
191 {
192 data = r.data;
193 return *this;
194 }
195
196
204 static std::streamoff open(_In_ std::ostream& stream)
205 {
206 return stdex::idrec::open<T_ID, T_SIZE>(stream, id());
207 }
208
209
218 static std::streamoff close(_In_ std::ostream& stream, _In_ std::streamoff start)
219 {
220 return stdex::idrec::close<T_ID, T_SIZE, ALIGN>(stream, start);
221 }
222
223
234 static bool find(_In_ std::istream& stream, _In_opt_ std::streamoff end = (std::streamoff)-1)
235 {
236 return stdex::idrec::find<T_ID, T_SIZE, ALIGN>(stream, id(), end);
237 }
238
239
240 T &data;
241 };
242 };
243};
244
245
254template <class T, class T_ID, class T_SIZE, unsigned int ALIGN>
255std::ostream& operator <<(_In_ std::ostream& stream, _In_ const stdex::idrec::record<T, T_ID, T_SIZE, ALIGN> r)
256{
257 // Parameter r does not need to be passed by reference. It has only one field (data), which is a reference itself already.
258
259 std::streamoff start = r.open(stream);
260 if (stream.fail()) return stream;
261 stream << r.data;
262 r.close(stream, start);
263
264 return stream;
265}
266
267
276template <class T, class T_ID, class T_SIZE, unsigned int ALIGN>
277std::istream& operator >>(_In_ std::istream& stream, _In_ stdex::idrec::record<T, T_ID, T_SIZE, ALIGN> r)
278{
279 // Parameter r does not need to be passed by reference. It has only one field (data), which is a reference itself already.
280
281 // Read data size.
282 T_SIZE size;
283 stream.read((char*)&size, sizeof(size));
284 if (!stream.good()) return stream;
285
286 // Read data.
287 std::streamoff start = stream.tellg();
288 stream >> r.data; // TODO: operator >> should not read past the record data! Make a size limited stream and read from it instead.
289
290 size += (T_SIZE)(ALIGN - size) % ALIGN;
291 stream.seekg(start + size);
292
293 return stream;
294}
Helper class for read/write of records to/from memory.
Definition: idrec.h:159
T & data
Record data reference.
Definition: idrec.h:240
static std::streamoff close(std::ostream &stream, std::streamoff start)
Updates record header.
Definition: idrec.h:218
static const T_ID id()
Returns record id.
static bool find(std::istream &stream, std::streamoff end=(std::streamoff) -1)
Finds record data.
Definition: idrec.h:234
static std::streamoff open(std::ostream &stream)
Writes record header.
Definition: idrec.h:204
record(const T &d)
Constructs the class.
Definition: idrec.h:174
record(T &d)
Constructs the class.
Definition: idrec.h:166
const record< T, T_ID, T_SIZE, ALIGN > & operator=(const record< T, T_ID, T_SIZE, ALIGN > &r)
Assignment operator.
Definition: idrec.h:190