stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
ios.hpp
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2023 Amebis
4*/
5
6#pragma once
7
8#ifdef _WIN32
9#include <windows.h>
10#endif
11#include "endian.hpp"
12#include "internal.hpp"
13#include "string.hpp"
14#include "sal.hpp"
15#include <assert.h>
16#include <stdint.h>
17#include <stdio.h>
18#include <chrono>
19#include <fstream>
20#include <istream>
21#include <ostream>
22
23namespace stdex
24{
28 template <class _Elem, class _Traits>
30 {
31 public:
32 std::basic_ostream<_Elem, _Traits> &sp; // Write stream
33
34 inline basic_ostreamfmt(_Inout_ std::basic_ostream<_Elem, _Traits> &stream) : sp(stream) {}
35
36 using pos_type = typename _Traits::pos_type;
37 using off_type = typename _Traits::off_type;
38 inline pos_type tellp() { return sp.tellp(); }
39 inline basic_ostreamfmt<_Elem, _Traits>& seekp(pos_type pos) { sp.seekp(pos); return *this; }
40 inline basic_ostreamfmt<_Elem, _Traits>& seekp(off_type off, std::ios_base::seekdir dir) { sp.seekp(off, dir); return *this; }
41 inline bool good() const noexcept { return sp.good(); }
42 inline bool eof() const noexcept { return sp.eof(); }
43 inline bool fail() const noexcept { return sp.fail(); }
44 inline bool bad() const noexcept { return sp.bad(); }
45
46 inline basic_ostreamfmt<_Elem, _Traits>& write(_In_reads_bytes_(size) const void* data, _In_ std::streamsize size)
47 {
48 sp.write(reinterpret_cast<const _Elem*>(data), size/sizeof(_Elem));
49 return *this;
50 }
51
52 template <class T>
53 inline basic_ostreamfmt<_Elem, _Traits>& write(_In_ T value)
54 {
55 HE2LE(&value);
56 sp.write(reinterpret_cast<const _Elem*>(&value), sizeof(T)/sizeof(_Elem));
57 return *this;
58 }
59
60 inline basic_ostreamfmt<_Elem, _Traits>& write(_In_z_ const char* value)
61 {
62 size_t count = strlen(value);
63 if (count > UINT32_MAX)
64 throw std::invalid_argument("string too big");
65 sp.write(static_cast<uint32_t>(count));
66 sp.write(reinterpret_cast<const _Elem*>(value), (std::streamsize)count * sizeof(char)/sizeof(_Elem));
67 return *this;
68 }
69
70 inline basic_ostreamfmt<_Elem, _Traits>& write(_In_z_ const wchar_t* value)
71 {
72 size_t count = strlen(value);
73 if (count > UINT32_MAX)
74 throw std::invalid_argument("string too big");
75 sp.write(static_cast<uint32_t>(count));
76#ifdef BIG_ENDIAN
77 for (size_t i = 0; i < count; ++i)
78 sp.write(value[i]);
79#else
80 sp.write(reinterpret_cast<const _Elem*>(value), (std::streamsize)count * sizeof(wchar_t)/sizeof(_Elem));
81#endif
82 return *this;
83 }
84
92 template <class _Elem2>
93 void vprintf(_In_z_ _Printf_format_string_ const _Elem2 *format, _In_opt_ locale_t locale, _In_ va_list arg)
94 {
95 std::basic_string<_Elem2> str;
96 vappendf(str, format, locale, arg);
97 sp.write(reinterpret_cast<const _Elem*>(str.c_str()), str.size() * sizeof(_Elem2)/sizeof(_Elem));
98 }
99
106 template <class _Elem2>
107 void printf(_In_z_ _Printf_format_string_ const _Elem2 *format, _In_opt_ locale_t locale, ...)
108 {
109 va_list arg;
110 va_start(arg, locale);
111 vprintf(format, locale, arg);
112 va_end(arg);
113 }
114
115 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ int8_t value) { return write(value); }
116 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ int16_t value) { return write(value); }
117 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ int32_t value) { return write(value); }
118 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ int64_t value) { return write(value); }
119 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ uint8_t value) { return write(value); }
120 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ uint16_t value) { return write(value); }
121 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ uint32_t value) { return write(value); }
122 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ uint64_t value) { return write(value); }
123#ifdef _NATIVE_SIZE_T_DEFINED
124 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ size_t value) { return write(value); }
125#endif
126 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ float value) { return write(value); }
127 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ double value) { return write(value); }
128 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ char value) { return write(value); }
129#ifdef _NATIVE_WCHAR_T_DEFINED
130 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_ wchar_t value) { return write(value); }
131#endif
132 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_z_ const char* value) { return write(value); }
133 inline basic_ostreamfmt<_Elem, _Traits>& operator <<(_In_z_ const wchar_t* value) { return write(value); }
134 };
135
136 using ostreamfmt = basic_ostreamfmt<char, std::char_traits<char>>;
137 using wostreamfmt = basic_ostreamfmt<wchar_t, std::char_traits<wchar_t>>;
138
142 template <class _Elem, class _Traits>
144 {
145 public:
146 std::basic_istream<_Elem, _Traits> &sg; // Read stream
147
148 inline basic_istreamfmt(_Inout_ std::basic_istream<_Elem, _Traits> &stream) : sg(stream) {}
149
150 using pos_type = typename _Traits::pos_type;
151 using off_type = typename _Traits::off_type;
152 inline pos_type tellg() { return sg.tellg(); }
153 inline basic_istreamfmt<_Elem, _Traits>& seekg(pos_type pos) { sg.seekg(pos); return *this; }
154 inline basic_istreamfmt<_Elem, _Traits>& seekg(off_type off, std::ios_base::seekdir dir) { sg.seekg(off, dir); return *this; }
155 inline bool good() const noexcept { return sg.good(); }
156 inline bool eof() const noexcept { return sg.eof(); }
157 inline bool fail() const noexcept { return sg.fail(); }
158 inline bool bad() const noexcept { return sg.bad(); }
159 inline std::streamsize gcount() const noexcept { return sg.gcount(); }
160
161 inline basic_istreamfmt<_Elem, _Traits>& read(_Out_writes_bytes_(size) void* data, std::streamsize size)
162 {
163 sg.read(reinterpret_cast<_Elem*>(data), size/sizeof(_Elem));
164 return *this;
165 }
166
167 template <class T>
168 inline basic_istreamfmt<_Elem, _Traits>& read(_Out_ T& value)
169 {
170 sg.read(reinterpret_cast<_Elem*>(&value), sizeof(T)/sizeof(_Elem));
171 if (sg.good())
172 LE2HE(&value);
173 return *this;
174 }
175
176 template <class _Traits = std::char_traits<char>, class _Alloc = std::allocator<char>>
177 inline basic_istreamfmt<_Elem, _Traits>& read(_Inout_ std::basic_string<char, _Traits, _Alloc>& value)
178 {
179 uint32_t count;
180 sg.read(count);
181 if (sg.good()) {
182 value.resize(count);
183 sg.read(reinterpret_cast<_Elem*>(&value[0]), (std::streamsize)count * sizeof(char)/sizeof(_Elem));
184 }
185 return *this;
186 }
187
188 template <class _Traits = std::char_traits<wchar_t>, class _Alloc = std::allocator<wchar_t>>
189 inline basic_istreamfmt<_Elem, _Traits>& read(_Inout_ std::basic_string<wchar_t, _Traits, _Alloc>& value)
190 {
191 uint32_t count;
192 sg.read(count);
193 if (sg.good()) {
194 value.resize(count);
195#ifdef BIG_ENDIAN
196 for (size_t i = 0; i < count; ++i)
197 sg.read(value[i]);
198#else
199 sg.read(reinterpret_cast<_Elem*>(&value[0]), (std::streamsize)count * sizeof(wchar_t)/sizeof(_Elem));
200#endif
201 }
202 return *this;
203 }
204
205 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ int8_t& value) { return read(value); }
206 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ int16_t& value) { return read(value); }
207 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ int32_t& value) { return read(value); }
208 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ int64_t& value) { return read(value); }
209 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ uint8_t& value) { return read(value); }
210 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ uint16_t& value) { return read(value); }
211 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ uint32_t& value) { return read(value); }
212 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ uint64_t& value) { return read(value); }
213#ifdef _NATIVE_SIZE_T_DEFINED
214 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ size_t& value) { return read(value); }
215#endif
216 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ float& value) { return read(value); }
217 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ double& value) { return read(value); }
218 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ char& value) { return read(value); }
219#ifdef _NATIVE_WCHAR_T_DEFINED
220 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Out_ wchar_t& value) { return read(value); }
221#endif
222 template <class _Traits = std::char_traits<char>, class _Alloc = std::allocator<char>>
223 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Inout_ std::basic_string<char, _Traits, _Alloc>& value) { return read(value); }
224 template <class _Traits = std::char_traits<wchar_t>, class _Alloc = std::allocator<wchar_t>>
225 inline basic_istreamfmt<_Elem, _Traits>& operator >>(_Inout_ std::basic_string<wchar_t, _Traits, _Alloc>& value) { return read(value); }
226 };
227
230
234 template <class _Elem, class _Traits>
235 class basic_iostreamfmt : public basic_ostreamfmt<_Elem, _Traits>, public basic_istreamfmt<_Elem, _Traits>
236 {
237 public:
238 inline basic_iostreamfmt(_Inout_ std::basic_iostream<_Elem, _Traits> &stream) :
241 {}
242 };
243
246
250 template <class _Elem, class _Traits>
251 class basic_sharedstrbuf : public std::basic_streambuf<_Elem, _Traits>
252 {
253 public:
254 basic_sharedstrbuf(_In_reads_(size) const _Elem* data, _In_ size_t size)
255 {
256 std::basic_streambuf<_Elem, _Traits>::setg(const_cast<_Elem*>(data), const_cast<_Elem*>(data), const_cast<_Elem*>(data + size));
257 }
258
260 {
261 std::basic_streambuf<_Elem, _Traits>::setg(other.eback(), other.gptr(), other.egptr());
262 }
263
265 {
266 if (this != std::addressof(other))
267 std::basic_streambuf<_Elem, _Traits>::operator =(other);
268 return *this;
269 }
270
271 private:
274
275 protected:
276 virtual pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
277 {
278 if (which & std::ios_base::in) {
279 _Elem* target;
280 switch (way) {
281 case std::ios_base::beg: target = eback() + off; break;
282 case std::ios_base::cur: target = gptr() + off; break;
283 case std::ios_base::end: target = egptr() + off; break;
284 default: throw std::invalid_argument("invalid seek reference");
285 }
286 if (eback() <= target && target <= egptr()) {
287 gbump(static_cast<int>(target - gptr()));
288 return pos_type{ off_type{ target - eback() } };
289 }
290 }
291 return pos_type{ off_type{-1} };
292 }
293
294 virtual pos_type __CLR_OR_THIS_CALL seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out)
295 {
296 // change to specified position, according to mode
297 if (which & std::ios_base::in) {
298 _Elem* target = eback() + pos;
299 if (eback() <= target && target <= egptr()) {
300 gbump(static_cast<int>(target - gptr()));
301 return pos_type{ off_type{ target - eback() } };
302 }
303 }
304 return pos_type{ off_type{-1} };
305 }
306 };
307
308 template <class _Elem, class _Traits>
309 class basic_isharedstrstream : public std::basic_istream<_Elem, _Traits>
310 {
311 public:
312 basic_isharedstrstream(_In_reads_(size) const _Elem* data, _In_ size_t size) :
313 m_buf(data, size),
314 std::basic_istream<_Elem, _Traits>(&m_buf)
315 {}
316
317 protected:
319 };
320
323
324#ifdef _WIN32
326 template struct robber<getter<FILE*, std::filebuf>, &std::filebuf::_Myfile>;
327 template struct robber<getter<FILE*, std::wfilebuf>, &std::wfilebuf::_Myfile>;
328
329 inline FILE* filebuf_fhandle(_In_ std::filebuf* rb)
330 {
331 return (*rb).*get(getter<FILE*, std::filebuf>());
332 }
333
334 inline FILE* filebuf_fhandle(_In_ std::wfilebuf* rb)
335 {
336 return (*rb).*get(getter<FILE*, std::wfilebuf>());
337 }
339#endif
340
344 template <class _Elem, class _Traits>
345 class basic_fstream : public std::basic_fstream<_Elem, _Traits>
346 {
347 public:
348 using _Mybase = std::basic_fstream<_Elem, _Traits>;
349
350 basic_fstream() {}
351
352 explicit basic_fstream(
353 _In_z_ const char* file_name,
354 _In_ ios_base::openmode mode = ios_base::in | ios_base::out,
355 _In_ int prot = ios_base::_Default_open_prot) : _Mybase(file_name, mode, prot) {}
356
357 explicit basic_fstream(
358 _In_z_ const wchar_t* file_name,
359 _In_ ios_base::openmode mode = ios_base::in | ios_base::out,
360 _In_ int prot = ios_base::_Default_open_prot) : _Mybase(file_name, mode, prot) {}
361
362 template<class _Elem2, class _Traits2, class _Ax>
363 explicit basic_fstream(
364 _In_ const std::basic_string<_Elem2, _Traits2, _Ax>& str,
365 _In_ ios_base::openmode mode = ios_base::in | ios_base::out,
366 _In_ int prot = ios_base::_Default_open_prot) : basic_fstream(str.c_str(), mode, prot) {}
367
368 explicit basic_fstream(_In_ FILE* file) : _Mybase(file) {}
369
370 basic_fstream(_Inout_ basic_fstream&& other) : _Mybase(std::move(other)) {}
371
375 void truncate()
376 {
377 flush();
378 auto h = os_fhandle();
379#ifdef _WIN32
380 if (h == INVALID_HANDLE_VALUE)
381 throw std::runtime_error("invalid handle");
382 auto pos = tellp();
383 LONG
384 pos_lo = static_cast<LONG>(pos & 0xffffffff),
385 pos_hi = static_cast<LONG>((pos >> 32) & 0xffffffff);
386 if (SetFilePointer(h, pos_lo, &pos_hi, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
387 throw std::runtime_error("failed to seek");
388 if (!SetEndOfFile(h))
389 throw std::runtime_error("failed to truncate");
390#else
391#error Implement!
392#endif
393 }
394
395#if _HAS_CXX20
396 using time_type = std::chrono::time_point<std::chrono::file_clock>;
397#else
398 using time_type = std::chrono::time_point<std::chrono::system_clock>;
399#endif
400
406 time_type mtime() const
407 {
408 auto h = os_fhandle();
409#ifdef _WIN32
410 if (h == INVALID_HANDLE_VALUE)
411 throw std::runtime_error("invalid handle");
412 FILETIME ft;
413 if (!GetFileTime(h, NULL, NULL, &ft))
414 throw std::runtime_error("failed to get mtime");
415#if _HAS_CXX20
416 return time_type(time_type::duration(((static_cast<int64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime)));
417#else
418 // Adjust epoch to std::chrono::time_point<std::chrono::system_clock>/time_t.
419 return time_type(time_type::duration(((static_cast<int64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000ll));
420#endif
421#else
422#error Implement!
423#endif
424 }
425
426 protected:
427#ifdef _WIN32
428 HANDLE os_fhandle() const
429 {
430 FILE* f = filebuf_fhandle(rdbuf());
431 if (f == NULL)
432 return INVALID_HANDLE_VALUE;
433
434 int fd = _fileno(f);
435 if (fd == -1)
436 return INVALID_HANDLE_VALUE;
437
438 return (HANDLE)_get_osfhandle(fd);
439 }
440#else
441#error Implement!
442#endif
443 };
444
445 using fstream = basic_fstream<char, std::char_traits<char>>;
446 using wfstream = basic_fstream<wchar_t, std::char_traits<wchar_t>>;
447
451 template <class _Elem, class _Traits, class _Alloc>
452 class basic_stringstream : public std::basic_stringstream<_Elem, _Traits, _Alloc> {
453 public:
454 using _Mybase = std::basic_stringstream<_Elem, _Traits, _Alloc>;
455 using _Mystr = std::basic_string<_Elem, _Traits, _Alloc>;
456
458 explicit basic_stringstream(_In_ std::ios_base::openmode mode) : _Mybase(mode) {}
459 explicit basic_stringstream(_In_ const _Mystr& str, _In_ std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : _Mybase(str, mode) {}
460 basic_stringstream(_Inout_ basic_stringstream&& other) : _Mybase(std::move(other)) {}
461
469 template <class T>
470 explicit basic_stringstream(_In_z_ const T* filename, _In_ std::ios_base::openmode mode = std::ios_base::in, _In_ int prot = std::ios_base::_Default_open_prot) :
471 _Mybase(std::ios_base::in | std::ios_base::out | (mode & std::ios_base::bin | std::ios_base::app))
472 {
473 std::basic_ifstream<_Elem, _Traits> input(filename, mode & ~(std::ios_base::ate | std::ios_base::app), prot);
474 input.seekg(0, input.end);
475 auto size = input.tellg();
476 if (size > SIZE_MAX)
477 throw std::runtime_error("file too big to fit into memory");
478 str.reserve(static_cast<size_t>(size));
479 input.seekg(0);
480 do {
481 _Elem buf[0x1000];
482 input.read(buf, _countof(buf));
483 write(buf, input.gcount());
484 } while (!input.eof());
485 if (!(mode & (std::ios_base::ate | std::ios_base::app)))
486 seekp(0);
487 }
488
496 template <class T>
497 explicit basic_stringstream(_In_ const std::basic_string<T>& filename, _In_ std::ios_base::openmode mode = std::ios_base::in, _In_ int prot = std::ios_base::_Default_open_prot) :
498 basic_stringstream(filename.c_str(), mode, prot)
499 {}
500 };
501
502 using stringstream = basic_stringstream<char, std::char_traits<char>, std::allocator<char>>;
503 using wstringstream = basic_stringstream<wchar_t, std::char_traits<wchar_t>, std::allocator<char>>;
504}
File stream with additional std::filesystem features.
Definition ios.hpp:346
void truncate()
Sets end of file at current put position.
Definition ios.hpp:375
time_type mtime() const
Returns file modification time.
Definition ios.hpp:406
Binary stream reader/writer.
Definition ios.hpp:236
Definition ios.hpp:310
Binary stream reader.
Definition ios.hpp:144
Binary stream writer.
Definition ios.hpp:30
void vprintf(const _Elem2 *format, locale_t locale, va_list arg)
Formats string using printf() and write it to stream.
Definition ios.hpp:93
void printf(const _Elem2 *format, locale_t locale,...)
Formats string using printf() and write it to stream.
Definition ios.hpp:107
Shared-memory string buffer.
Definition ios.hpp:252
String stream.
Definition ios.hpp:452
basic_stringstream(const T *filename, std::ios_base::openmode mode=std::ios_base::in, int prot=std::ios_base::_Default_open_prot)
Initializes stream with content from file.
Definition ios.hpp:470
basic_stringstream(const std::basic_string< T > &filename, std::ios_base::openmode mode=std::ios_base::in, int prot=std::ios_base::_Default_open_prot)
Initializes stream with content from file.
Definition ios.hpp:497
Helper template to allow access to internal std C++ private members.
Definition internal.hpp:30
Helper template to allow access to internal std C++ private members.
Definition internal.hpp:18