10#include "interval.hpp"
28#include <condition_variable>
35#if !defined(SET_FILE_OP_TIMES) && defined(RDAT_BELEZI_CAS_DOSTOPA_VER)
36#define SET_FILE_OP_TIMES 1
37#pragma message("RDAT_BELEZI_CAS_DOSTOPA_VER is deprecated. Use SET_FILE_OP_TIMES instead.")
38#elif !defined(SET_FILE_OP_TIMES)
39#define SET_FILE_OP_TIMES 0
41#if !defined(CHECK_STREAM_STATE) && defined(RDAT_NE_PREVERJAJ_STANJA_VER)
42#define CHECK_STREAM_STATE 0
43#pragma message("RDAT_NE_PREVERJAJ_EOF_VER is deprecated. Use CHECK_STREAM_STATE=0 instead.")
45#define CHECK_STREAM_STATE 1
64 using fsize_t = uint64_t;
65 constexpr fsize_t fsize_max = UINT64_MAX;
67 constexpr size_t iterate_count = 0x10;
68 constexpr size_t default_block_size = 0x10000;
69 constexpr wchar_t utf16_bom = L
'\ufeff';
70 constexpr const char utf8_bom[3] = {
'\xef',
'\xbb',
'\xbf' };
91 virtual _Success_(
return != 0 || length == 0) size_t
read(
92 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
95 _Unreferenced_(length);
96 m_state = state_t::fail;
109 virtual _Success_(
return != 0) size_t
write(
110 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
112 _Unreferenced_(data);
113 _Unreferenced_(length);
114 m_state = state_t::fail;
123 m_state = state_t::ok;
131 m_state = state_t::ok;
137 virtual void skip(_In_ fsize_t amount)
141 else if (amount < iterate_count) {
142 for (
size_t i = 0; i < static_cast<size_t>(amount); i++) {
144 if (!
ok()) _Unlikely_
149 size_t block =
static_cast<size_t>(std::min<fsize_t>(amount, default_block_size));
151 std::unique_ptr<uint8_t[]> dummy(
new uint8_t[block]);
153 amount -=
read_array(dummy.get(),
sizeof(uint8_t),
static_cast<size_t>(std::min<fsize_t>(amount, block)));
154 if (!
ok()) _Unlikely_
158 catch (
const std::bad_alloc&) { m_state = state_t::fail; }
165 inline state_t
state()
const {
return m_state; };
170 inline bool ok()
const {
return m_state == state_t::ok; };
181 std::vector<uint8_t> result;
182 size_t offset, length;
184 length = default_block_size;
185 while (offset < max_length) {
186 length = std::min(length, max_length);
187 try { result.resize(length); }
188 catch (
const std::bad_alloc&) {
189 m_state = state_t::fail;
192 auto num_read =
read_array(result.data() + offset,
sizeof(uint8_t), length - offset);
194 if (!
ok()) _Unlikely_
196 length += default_block_size;
198 result.resize(offset);
210 throw std::runtime_error(
"failed to read");
219 write(&
byte,
sizeof(uint8_t));
220 else if (amount < iterate_count) {
221 for (
size_t i = 0; i < static_cast<size_t>(amount); i++) {
222 write(&
byte,
sizeof(uint8_t));
223 if (!
ok()) _Unlikely_
228 size_t block =
static_cast<size_t>(std::min<fsize_t>(amount, default_block_size));
230 std::unique_ptr<uint8_t[]> dummy(
new uint8_t[block]);
231 memset(dummy.get(),
byte, block);
233 amount -=
write_array(dummy.get(),
sizeof(uint8_t),
static_cast<size_t>(std::min<fsize_t>(amount, block)));
234 if (!
ok()) _Unlikely_
238 catch (
const std::bad_alloc&) { m_state = state_t::fail; }
256 if (!
ok()) _Unlikely_ {
265 m_state = state_t::eof;
284 if (!
ok()) _Unlikely_
286#if BYTE_ORDER == BIG_ENDIAN
287 T data_le = HE2LE(data);
288 write(&data_le,
sizeof(T));
290 write(&data,
sizeof(T));
300 template<
class _Traits = std::
char_traits<
char>,
class _Ax = std::allocator<
char>>
301 inline size_t readln(_Inout_ std::basic_string<char, _Traits, _Ax>& str)
312 template<
class _Traits = std::
char_traits<
wchar_t>,
class _Ax = std::allocator<
wchar_t>>
313 inline size_t readln(_Inout_ std::basic_string<wchar_t, _Traits, _Ax>& wstr)
324 template<
class _Traits = std::
char_traits<
wchar_t>,
class _Ax = std::allocator<
wchar_t>>
325 size_t readln(_Inout_ std::basic_string<wchar_t, _Traits, _Ax>& wstr, _In_ charset_id charset)
327 if (charset == charset_id::utf16)
332 str2wstr(wstr, str, charset);
341 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
345 _Elem chr, previous = (_Elem)0;
348 if (!initial && !(previous ==
static_cast<_Elem
>(
'\r') && chr ==
static_cast<_Elem
>(
'\n')))
353 }
while (
ok() && chr !=
static_cast<_Elem
>(
'\n'));
362 template<
class _Traits = std::
char_traits<
wchar_t>,
class _Ax = std::allocator<
wchar_t>>
363 size_t readln_and_attach(_Inout_ std::basic_string<wchar_t, _Traits, _Ax>& wstr, _In_ charset_id charset)
365 if (charset == charset_id::utf16)
369 str2wstr(wstr, str, charset);
378 size_t read_array(_Out_writes_bytes_(size* count)
void* array, _In_
size_t size, _In_
size_t count)
380 for (
size_t to_read = mul(size, count);;) {
381 size_t num_read =
read(array, to_read);
385 if (!
ok()) _Unlikely_
386 return count - to_read / size;
387 reinterpret_cast<uint8_t*&
>(array) += num_read;
396 inline size_t write_array(_In_reads_bytes_opt_(size* count)
const void* array, _In_
size_t size, _In_
size_t count)
398 return write(array, mul(size, count)) / size;
409 size_t write_array(_In_z_
const wchar_t* wstr, _In_ charset_id charset)
411 if (!
ok()) _Unlikely_
413 size_t num_chars = stdex::strlen(wstr);
414 if (charset != charset_id::utf16) {
415 std::string str(wstr2str(wstr, num_chars, charset));
416 return write_array(str.data(),
sizeof(
char), str.size());
418 return write_array(wstr,
sizeof(
wchar_t), num_chars);
430 size_t write_array(_In_reads_or_z_opt_(num_chars)
const wchar_t* wstr, _In_
size_t num_chars, _In_ charset_id charset)
432 if (!
ok()) _Unlikely_
434 num_chars = stdex::strnlen(wstr, num_chars);
435 if (charset != charset_id::utf16) {
436 std::string str(wstr2str(wstr, num_chars, charset));
437 return write_array(str.data(),
sizeof(
char), str.size());
439 return write_array(wstr,
sizeof(
wchar_t), num_chars);
450 template<
class _Traits = std::
char_traits<
wchar_t>,
class _Ax = std::allocator<
wchar_t>>
451 size_t write_array(_In_
const std::basic_string<wchar_t, _Traits, _Ax>& wstr, _In_ charset_id charset)
453 if (!
ok()) _Unlikely_
455 if (charset != charset_id::utf16) {
456 std::string str(wstr2str(wstr, charset));
457 return write_array(str.data(),
sizeof(
char), str.size());
459 return write_array(wstr.data(),
sizeof(
wchar_t), wstr.size());
473 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
474 inline basic&
read_str(_Inout_ std::basic_string<_Elem, _Traits, _Ax>& data)
478 if (!
ok()) _Unlikely_ {
482 data.resize(num_chars);
483 data.resize(
read_array(data.data(),
sizeof(_Elem), num_chars));
502 size_t num_chars = stdex::strlen(data);
503 if (num_chars > UINT32_MAX)
504 throw std::invalid_argument(
"string too long");
506 if (!
ok()) _Unlikely_
518 size_t write_sa(_In_ LPSAFEARRAY sa)
520 safearray_accessor<void> a(sa);
522 if (FAILED(SafeArrayGetUBound(sa, 1, &ubound)) ||
523 FAILED(SafeArrayGetLBound(sa, 1, &lbound)))
524 throw std::invalid_argument(
"SafeArrayGet[UL]Bound failed");
525 return write(a.data(),
static_cast<size_t>(ubound) - lbound + 1);
536 std::unique_ptr<uint8_t[]> data(
new uint8_t[
static_cast<size_t>(std::min<fsize_t>(amount, default_block_size))]);
537 fsize_t num_copied = 0, to_write = amount;
538 m_state = state_t::ok;
540 size_t num_read = stream.read(data.get(),
static_cast<size_t>(std::min<fsize_t>(default_block_size, to_write)));
541 size_t num_written =
write(data.get(), num_read);
542 num_copied += num_written;
543 to_write -= num_written;
544 if (stream.m_state == state_t::eof) {
546 m_state = state_t::ok;
549 m_state = stream.m_state;
561 if (charset == charset_id::utf16)
563 else if (charset == charset_id::utf8)
572 size_t write_sprintf(_In_z_ _Printf_format_string_params_(2)
const char* format, _In_opt_ locale_t locale, ...)
575 va_start(params, locale);
586 size_t write_sprintf(_In_z_ _Printf_format_string_params_(2)
const wchar_t* format, _In_opt_ locale_t locale, ...)
589 va_start(params, locale);
600 size_t write_vsprintf(_In_z_ _Printf_format_string_params_(2)
const char* format, _In_opt_ locale_t locale, _In_ va_list params)
603 str.reserve(default_block_size);
604 vappendf(str, format, locale, params);
605 return write_array(str.data(),
sizeof(
char), str.size());
613 size_t write_vsprintf(_In_z_ _Printf_format_string_params_(2)
const wchar_t* format, _In_opt_ locale_t locale, _In_ va_list params)
616 str.reserve(default_block_size);
617 vappendf(str, format, locale, params);
618 return write_array(str.data(),
sizeof(
wchar_t), str.size());
621 inline basic& operator >>(_Out_ int8_t& data) {
return read_data(data); }
622 inline basic& operator <<(_In_
const int8_t data) {
return write_data(data); }
623 inline basic& operator >>(_Out_ int16_t& data) {
return read_data(data); }
624 inline basic& operator <<(_In_
const int16_t data) {
return write_data(data); }
625 inline basic& operator >>(_Out_ int32_t& data) {
return read_data(data); }
626 inline basic& operator <<(_In_
const int32_t data) {
return write_data(data); }
627 inline basic& operator >>(_Out_ int64_t& data) {
return read_data(data); }
628 inline basic& operator <<(_In_
const int64_t data) {
return write_data(data); }
629 inline basic& operator >>(_Out_ uint8_t& data) {
return read_data(data); }
630 inline basic& operator <<(_In_
const uint8_t data) {
return write_data(data); }
631 inline basic& operator >>(_Out_ uint16_t& data) {
return read_data(data); }
632 inline basic& operator <<(_In_
const uint16_t data) {
return write_data(data); }
633 inline basic& operator >>(_Out_ uint32_t& data) {
return read_data(data); }
634 inline basic& operator <<(_In_
const uint32_t data) {
return write_data(data); }
635 inline basic& operator >>(_Out_ uint64_t& data) {
return read_data(data); }
636 inline basic& operator <<(_In_
const uint64_t data) {
return write_data(data); }
637 inline basic& operator >>(_Out_
float& data) {
return read_data(data); }
638 inline basic& operator <<(_In_
const float data) {
return write_data(data); }
639 inline basic& operator >>(_Out_
double& data) {
return read_data(data); }
640 inline basic& operator <<(_In_
const double data) {
return write_data(data); }
641 inline basic& operator >>(_Out_
char& data) {
return read_data(data); }
642 inline basic& operator <<(_In_
const char data) {
return write_data(data); }
643#ifdef _NATIVE_WCHAR_T_DEFINED
644 inline basic& operator >>(_Out_
wchar_t& data) {
return read_data(data); }
645 inline basic& operator <<(_In_
const wchar_t data) {
return write_data(data); }
647 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
648 inline basic& operator >>(_Inout_ std::basic_string<_Elem, _Traits, _Ax>& data) {
return read_str(data); }
650 inline basic& operator <<(_In_
const T* data) {
return write_str(data); }
659 using fpos_t = uint64_t;
660 constexpr fpos_t fpos_max = UINT64_MAX;
661 constexpr fpos_t fpos_min = 0;
666 using foff_t = int64_t;
667 constexpr foff_t foff_max = INT64_MAX;
668 constexpr foff_t foff_min = INT64_MIN;
686 using clock = std::chrono::file_clock;
688 using clock = std::chrono::system_clock;
690 using time_point = std::chrono::time_point<clock>;
700 size_t length = std::min<size_t>(max_length,
static_cast<size_t>(
size() -
tell()));
701 std::vector<uint8_t> result;
702 try { result.resize(length); }
703 catch (
const std::bad_alloc&) {
704 m_state = state_t::fail;
707 result.resize(
read_array(result.data(),
sizeof(uint8_t), length));
716 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg) = 0;
723 inline fpos_t
seekbeg(_In_ fpos_t offset) {
return seek(offset, seek_t::beg); }
730 inline fpos_t
seekcur(_In_ foff_t offset) {
return seek(offset, seek_t::cur); }
737 inline fpos_t
seekend(_In_ foff_t offset) {
return seek(offset, seek_t::end); }
739 virtual void skip(_In_ fsize_t amount)
741 seek(amount, seek_t::cur);
750 virtual fpos_t
tell()
const = 0;
755 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
757 _Unreferenced_(offset);
758 _Unreferenced_(length);
759 throw std::domain_error(
"not implemented");
765 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
767 _Unreferenced_(offset);
768 _Unreferenced_(length);
769 throw std::domain_error(
"not implemented");
788 return time_point::min();
796 return time_point::min();
804 return time_point::min();
812 _Unreferenced_(date);
813 throw std::domain_error(
"not implemented");
821 _Unreferenced_(date);
822 throw std::domain_error(
"not implemented");
830 _Unreferenced_(date);
831 throw std::domain_error(
"not implemented");
838 LPSAFEARRAY read_sa()
840 assert(
size() <= SIZE_MAX);
841 size_t length =
static_cast<size_t>(
size());
842 std::unique_ptr<SAFEARRAY, SafeArrayDestroy_delete> sa(SafeArrayCreateVector(VT_UI1, 0, (ULONG)length));
844 throw std::runtime_error(
"SafeArrayCreateVector failed");
845 safearray_accessor<void> a(sa.get());
847 throw std::runtime_error(
"failed to seek");
848 if (
read_array(a.data(), 1, length) != length)
849 throw std::runtime_error(
"failed to read");
859 charset_id
read_charset(_In_ charset_id default_charset = charset_id::system)
862 throw std::runtime_error(
"failed to seek");
865 if (!
ok()) _Unlikely_
866 return default_charset;
867 if (id_utf16 == utf16_bom)
868 return charset_id::utf16;
871 throw std::runtime_error(
"failed to seek");
872 char id_utf8[3] = { 0 };
874 if (!
ok()) _Unlikely_
875 return default_charset;
876 if (strncmp(id_utf8, _countof(id_utf8), utf8_bom, _countof(utf8_bom)) == 0)
877 return charset_id::utf8;
880 throw std::runtime_error(
"failed to seek");
881 return default_charset;
892 basic(state_t::fail),
896 void init(_Inout_
basic& source)
898 m_state = source.state();
909 basic(source.state()),
913 virtual _Success_(
return != 0 || length == 0) size_t
read(
914 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
916 size_t num_read = m_source->
read(data, length);
917 m_state = m_source->
state();
921 virtual _Success_(
return != 0) size_t
write(
922 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
924 size_t num_written = m_source->
write(data, length);
925 m_state = m_source->
state();
932 m_state = m_source->
state();
938 m_state = m_source->
state();
953 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
956 const std::lock_guard<std::mutex> lk(_w->mutex);
957 _w->op = worker::op_t::quit;
961 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w)
962 w->get()->thread.join();
970 m_workers.push_back(std::unique_ptr<worker>(
new worker(source)));
978 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
980 if (_w->source == source) {
982 const std::lock_guard<std::mutex> lk(_w->mutex);
983 _w->op = worker::op_t::quit;
993 virtual _Success_(
return != 0) size_t
write(
994 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
996 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
999 const std::lock_guard<std::mutex> lk(_w->mutex);
1000 _w->op = worker::op_t::write;
1002 _w->length = length;
1004 _w->cv.notify_one();
1006 size_t num_written = length;
1007 m_state = state_t::ok;
1008 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
1010 std::unique_lock<std::mutex> lk(_w->mutex);
1011 _w->cv.wait(lk, [&] {
return _w->op == worker::op_t::noop; });
1012 if (_w->num_written < num_written)
1013 num_written = _w->num_written;
1014 if (
ok() && !_w->source->ok())
1015 m_state = _w->source->state();
1022 foreach_worker(worker::op_t::close);
1027 foreach_worker(worker::op_t::flush);
1040 thread(process_op, std::ref(*
this))
1044 static void process_op(_Inout_
worker& w)
1047 std::unique_lock<std::mutex> lk(w.mutex);
1048 w.cv.wait(lk, [&] {
return w.op != op_t::noop; });
1053 w.num_written = w.source->write(w.data, w.length);
1082 std::condition_variable cv;
1086 void foreach_worker(_In_ worker::op_t op)
1088 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
1091 const std::lock_guard<std::mutex> lk(_w->mutex);
1094 _w->cv.notify_one();
1096 m_state = state_t::ok;
1097 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
1099 std::unique_lock<std::mutex> lk(_w->mutex);
1100 _w->cv.wait(lk, [&] {
return _w->op == worker::op_t::noop; });
1102 m_state = _w->source->state();
1106 std::list<std::unique_ptr<worker>> m_workers;
1109 constexpr size_t default_async_limit = 0x100000;
1116 template <
size_t CAPACITY = default_async_limit>
1122 m_worker(process, std::ref(*
this))
1131#pragma warning(suppress: 6101)
1132 virtual _Success_(
return != 0 || length == 0) size_t
read(
1133 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1135 assert(data || !length);
1136 for (
size_t to_read = length;;) {
1137 uint8_t* ptr;
size_t num_read;
1138 std::tie(ptr, num_read) = m_ring.front();
1139 if (!ptr) _Unlikely_ {
1141 m_state = to_read < length || !length ? state_t::ok : m_source->
state();
1142 return length - to_read;
1144 if (to_read < num_read)
1146 memcpy(data, ptr, num_read);
1147 m_ring.pop(num_read);
1148 to_read -= num_read;
1150 m_state = state_t::ok;
1153 reinterpret_cast<uint8_t*&
>(data) += num_read;
1161 uint8_t* ptr;
size_t num_write;
1162 std::tie(ptr, num_write) = w.m_ring.back();
1163 if (!ptr) _Unlikely_
1165 num_write = w.m_source->read(ptr, num_write);
1166 w.m_ring.push(num_write);
1167 if (!w.m_source->ok()) {
1175 ring<uint8_t, CAPACITY> m_ring;
1176 std::thread m_worker;
1184 template <
size_t CAPACITY = default_async_limit>
1190 m_worker(process, std::ref(*
this))
1199 virtual _Success_(
return != 0) size_t
write(
1200 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1202 assert(data || !length);
1203 for (
size_t to_write = length;;) {
1204 uint8_t* ptr;
size_t num_write;
1205 std::tie(ptr, num_write) = m_ring.back();
1206 if (!ptr) _Unlikely_ {
1207 m_state = state_t::fail;
1208 return length - to_write;
1210 if (to_write < num_write)
1211 num_write = to_write;
1212 memcpy(ptr, data, num_write);
1213 m_ring.push(num_write);
1214 to_write -= num_write;
1216 m_state = state_t::ok;
1219 reinterpret_cast<const uint8_t*&
>(data) += num_write;
1233 uint8_t* ptr;
size_t num_read;
1234 std::tie(ptr, num_read) = w.m_ring.front();
1237 num_read = w.m_source->write(ptr, num_read);
1238 w.m_ring.pop(num_read);
1239 if (!w.m_source->ok()) {
1247 ring<uint8_t, CAPACITY> m_ring;
1248 std::thread m_worker;
1251 constexpr size_t default_buffer_size = 0x400;
1259 explicit buffer(_In_
size_t read_buffer_size = default_buffer_size, _In_
size_t write_buffer_size = default_buffer_size) :
1261 m_read_buffer(read_buffer_size),
1262 m_write_buffer(write_buffer_size)
1273 buffer(_Inout_
basic& source, _In_
size_t read_buffer_size = default_buffer_size, _In_
size_t write_buffer_size = default_buffer_size) :
1275 m_read_buffer(read_buffer_size),
1276 m_write_buffer(write_buffer_size)
1285 virtual _Success_(
return != 0 || length == 0) size_t
read(
1286 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1288 assert(data || !length);
1289 for (
size_t to_read = length;;) {
1290 size_t buffer_size = m_read_buffer.tail - m_read_buffer.head;
1291 if (to_read <= buffer_size) {
1292 memcpy(data, m_read_buffer.data + m_read_buffer.head, to_read);
1293 m_read_buffer.head += to_read;
1294 m_state = state_t::ok;
1298 memcpy(data, m_read_buffer.data + m_read_buffer.head, buffer_size);
1299 reinterpret_cast<uint8_t*&
>(data) += buffer_size;
1300 to_read -= buffer_size;
1302 m_read_buffer.head = 0;
1303 if (to_read > m_read_buffer.capacity) {
1305 m_read_buffer.tail = 0;
1306 to_read -= m_source->
read(data, to_read);
1307 m_state = to_read < length ? state_t::ok : m_source->
state();
1308 return length - to_read;
1310 m_read_buffer.tail = m_source->
read(m_read_buffer.data, m_read_buffer.capacity);
1311 if (m_read_buffer.tail < m_read_buffer.capacity && m_read_buffer.tail < to_read) _Unlikely_ {
1312 memcpy(data, m_read_buffer.data, m_read_buffer.tail);
1313 m_read_buffer.head = m_read_buffer.tail;
1314 to_read -= m_read_buffer.tail;
1315 m_state = to_read < length ? state_t::ok : m_source->
state();
1316 return length - to_read;
1321 virtual _Success_(
return != 0) size_t
write(
1322 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1324 assert(data || !length);
1325 if (!length) _Unlikely_ {
1328 if (!
ok()) _Unlikely_
1330 m_source->
write(
nullptr, 0);
1331 m_state = m_source->
state();
1335 for (
size_t to_write = length;;) {
1336 size_t available_buffer = m_write_buffer.capacity - m_write_buffer.tail;
1337 if (to_write <= available_buffer) {
1338 memcpy(m_write_buffer.data + m_write_buffer.tail, data, to_write);
1339 m_write_buffer.tail += to_write;
1340 m_state = state_t::ok;
1343 if (available_buffer) {
1344 memcpy(m_write_buffer.data + m_write_buffer.tail, data, available_buffer);
1345 reinterpret_cast<const uint8_t*&
>(data) += available_buffer;
1346 to_write -= available_buffer;
1347 m_write_buffer.tail += available_buffer;
1349 size_t buffer_size = m_write_buffer.tail - m_write_buffer.head;
1351 m_write_buffer.head += m_source->
write(m_write_buffer.data + m_write_buffer.head, buffer_size);
1352 m_state = m_source->
state();
1353 if (m_write_buffer.head == m_write_buffer.tail)
1354 m_write_buffer.head = m_write_buffer.tail = 0;
1356 return length - to_write;
1358 if (to_write > m_write_buffer.capacity) {
1360 to_write -= m_source->
write(data, to_write);
1361 m_state = m_source->
state();
1362 return length - to_write;
1377 size_t buffer_size = m_write_buffer.tail - m_write_buffer.head;
1379 m_write_buffer.head += m_source->
write(m_write_buffer.data + m_write_buffer.head, buffer_size);
1380 if (m_write_buffer.head == m_write_buffer.tail) {
1381 m_write_buffer.head = 0;
1382 m_write_buffer.tail = 0;
1385 m_state = m_source->
state();
1389 m_state = state_t::ok;
1394 size_t head, tail, capacity;
1396 buffer_t(_In_
size_t buffer_size) :
1399 capacity(buffer_size),
1400 data(buffer_size ?
new uint8_t[buffer_size] :
nullptr)
1408 } m_read_buffer, m_write_buffer;
1417 limiter(_Inout_
basic& source, _In_ fsize_t _read_limit = 0, _In_ fsize_t _write_limit = 0) :
1423 virtual _Success_(
return != 0 || length == 0) size_t
read(
1424 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1428 num_read = m_source->
read(data, length);
1429 m_state = m_source->
state();
1432 num_read = m_source->
read(data, length);
1433 m_state = m_source->
state();
1438 m_state = state_t::eof;
1441 num_read = m_source->
read(data,
static_cast<size_t>(
read_limit));
1442 m_state = m_source->
state();
1448 virtual _Success_(
return != 0) size_t
write(
1449 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1453 num_written = m_source->
write(data, length);
1454 m_state = m_source->
state();
1457 num_written = m_source->
write(data, length);
1458 m_state = m_source->
state();
1463 m_state = state_t::fail;
1467 m_state = m_source->
state();
1485 window(_Inout_
basic& source, _In_ fpos_t _read_offset = 0, _In_ fsize_t
read_limit = fsize_max, _In_ fpos_t _write_offset = 0, _In_ fsize_t
write_limit = fsize_max) :
1491 virtual _Success_(
return != 0 || length == 0) size_t
read(
1492 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1496 m_state = m_source->
state();
1497 if (!
ok()) _Unlikely_
1503 num_read = m_source->
read(data, length);
1504 m_state = m_source->
state();
1507 num_read = m_source->
read(data, length);
1508 m_state = m_source->
state();
1513 m_source->
skip(length);
1514 m_state = state_t::eof;
1517 num_read = m_source->
read(data,
static_cast<size_t>(
read_limit));
1518 m_state = m_source->
state();
1524 virtual _Success_(
return != 0) size_t
write(
1525 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1527 size_t num_skipped, num_written;
1530 m_state = state_t::ok;
1534 reinterpret_cast<const uint8_t*&
>(data) +=
static_cast<size_t>(
write_offset);
1542 num_written = m_source->
write(data, length);
1543 m_state = m_source->
state();
1546 num_written = m_source->
write(data, length);
1547 m_state = m_source->
state();
1551 num_skipped += length;
1553 m_state = state_t::ok;
1556 num_skipped += length -
static_cast<size_t>(
write_limit);
1558 m_state = m_source->
state();
1561 return num_skipped + num_written;
1577 basic(source.state()),
1579 m_offset(source.tell()),
1580 m_region(offset, offset + length)
1583 virtual _Success_(
return != 0 || length == 0) size_t
read(
1584 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1586 assert(data || !length);
1588 size_t num_read = m_source.
read(data,
static_cast<size_t>(std::min<fpos_t>(length, m_region.
end - m_offset)));
1589 m_state = m_source.
state();
1590 m_offset += num_read;
1593 m_state = length ? state_t::eof : state_t::ok;
1597 virtual _Success_(
return != 0) size_t
write(
1598 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1600 assert(data || !length);
1602 size_t num_written = m_source.
write(data,
static_cast<size_t>(std::min<fpos_t>(length, m_region.
end - m_offset)));
1603 m_state = m_source.
state();
1604 m_offset += num_written;
1607 m_state = state_t::fail;
1614 m_state = m_source.
state();
1620 m_state = m_source.
state();
1623 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
1625 m_offset = m_source.
seek(offset, how);
1626 m_state = m_source.
state();
1627 return ok() ? m_offset - m_region.
start : fpos_max;
1630 virtual void skip(_In_ fsize_t amount)
1632 m_source.
skip(amount);
1633 m_state = m_source.
state();
1638 fpos_t offset = m_source.
tell();
1639 return m_region.
contains(offset) ? offset - m_region.
start : fpos_max;
1642 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
1645 m_source.
lock(m_region.
start + offset, std::min<fsize_t>(length, m_region.
end - offset));
1646 m_state = m_source.
state();
1649 m_state = state_t::fail;
1652 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
1655 m_source.
unlock(m_region.
start + offset, std::min<fsize_t>(length, m_region.
end - offset));
1656 m_state = m_source.
state();
1659 m_state = state_t::fail;
1664 return m_region.
size();
1669 m_state = state_t::fail;
1678 constexpr size_t default_cache_size = 0x1000;
1686 explicit cache(_In_
size_t cache_size = default_cache_size) :
1687 basic(state_t::fail),
1689 m_cache(cache_size),
1691#if SET_FILE_OP_TIMES
1692 , m_atime(time_point::min()),
1693 m_mtime(time_point::min())
1699 m_state = source.state();
1702#if SET_FILE_OP_TIMES
1703 m_atime = source.atime();
1704 m_mtime = source.mtime();
1712 if (!
ok()) _Unlikely_
1713 throw std::runtime_error(
"cache flush failed");
1720 cache(_Inout_
basic_file& source, _In_
size_t cache_size = default_cache_size) :
1721 basic(source.state()),
1723 m_cache(cache_size),
1725#if SET_FILE_OP_TIMES
1726 , m_atime(source.atime()),
1727 m_mtime(source.mtime())
1731 virtual ~cache()
noexcept(
false)
1735 if (!
ok()) _Unlikely_
1736 throw std::runtime_error(
"cache flush failed");
1741 virtual _Success_(
return != 0 || length == 0) size_t
read(
1742 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1744 assert(data || !length);
1745#if SET_FILE_OP_TIMES
1746 m_atime = time_point::now();
1748 for (
size_t to_read = length;;) {
1749 if (m_cache.status != cache_t::cache_t::status_t::empty) {
1752 if (to_read <= remaining_cache) {
1753 memcpy(data, m_cache.data +
static_cast<size_t>(
m_offset - m_cache.
region.
start), to_read);
1755 m_state = state_t::ok;
1758 memcpy(data, m_cache.data +
static_cast<size_t>(
m_offset - m_cache.
region.
start), remaining_cache);
1759 reinterpret_cast<uint8_t*&
>(data) += remaining_cache;
1760 to_read -= remaining_cache;
1764 if (!
ok()) _Unlikely_ {
1765 if (to_read < length)
1766 m_state = state_t::ok;
1767 return length - to_read;
1771 fpos_t end_max =
m_offset + to_read;
1772 if (
m_offset / m_cache.capacity < end_max / m_cache.capacity) {
1775 if (!m_source->
ok()) _Unlikely_ {
1776 m_state = to_read < length ? state_t::ok : state_t::fail;
1777 return length - to_read;
1779 size_t num_read = m_source->
read(data, to_read -
static_cast<size_t>(end_max % m_cache.capacity));
1781 to_read -= num_read;
1783 m_state = state_t::ok;
1786 reinterpret_cast<uint8_t*&
>(data) += num_read;
1787 m_state = m_source->
state();
1789 if (to_read < length)
1790 m_state = state_t::ok;
1791 return length - to_read;
1797 m_state = to_read < length ? state_t::ok : state_t::fail;
1798 return length - to_read;
1803 virtual _Success_(
return != 0) size_t
write(
1804 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1806 assert(data || !length);
1807#if SET_FILE_OP_TIMES
1808 m_atime = m_mtime = time_point::now();
1810 for (
size_t to_write = length;;) {
1811 if (m_cache.status != cache_t::cache_t::status_t::empty) {
1812 fpos_t end_max = m_cache.
region.
start + m_cache.capacity;
1814 size_t remaining_cache =
static_cast<size_t>(end_max -
m_offset);
1815 if (to_write <= remaining_cache) {
1816 memcpy(m_cache.data +
static_cast<size_t>(
m_offset - m_cache.
region.
start), data, to_write);
1818 m_cache.status = cache_t::cache_t::status_t::dirty;
1820 m_state = state_t::ok;
1823 memcpy(m_cache.data +
static_cast<size_t>(
m_offset - m_cache.
region.
start), data, remaining_cache);
1824 reinterpret_cast<const uint8_t*&
>(data) += remaining_cache;
1825 to_write -= remaining_cache;
1827 m_cache.status = cache_t::cache_t::status_t::dirty;
1831 if (!
ok()) _Unlikely_
1832 return length - to_write;
1835 fpos_t end_max =
m_offset + to_write;
1836 if (
m_offset / m_cache.capacity < end_max / m_cache.capacity) {
1839 if (!
ok()) _Unlikely_
1840 return length - to_write;
1841 size_t num_written = m_source->
write(data, to_write -
static_cast<size_t>(end_max % m_cache.capacity));
1843 m_state = m_source->
state();
1844 to_write -= num_written;
1845 if (!to_write || !
ok())
1846 return length - to_write;
1847 reinterpret_cast<const uint8_t*&
>(data) += num_written;
1851 if (!
ok()) _Unlikely_
1852 return length - to_write;
1859 if (!
ok()) _Unlikely_
1860 throw std::runtime_error(
"cache flush failed");
1862 m_state = m_source->
state();
1867#if SET_FILE_OP_TIMES
1868 m_atime = m_mtime = time_point::min();
1871 if (!
ok()) _Unlikely_
1876 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
1878 m_state = state_t::ok;
1887 throw std::invalid_argument(
"unknown seek origin");
1896 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
1898 m_source->
lock(offset, length);
1899 m_state = m_source->
state();
1902 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
1904 m_source->
unlock(offset, length);
1905 m_state = m_source->
state();
1910 return m_cache.status != cache_t::cache_t::status_t::empty ?
1917#if SET_FILE_OP_TIMES
1918 m_atime = m_mtime = time_point::now();
1930 m_cache.status = cache_t::cache_t::status_t::empty;
1933 m_state = m_source->
state();
1938 return m_source->
ctime();
1943#if SET_FILE_OP_TIMES
1944 return std::max(m_atime, m_source->
atime());
1946 return m_source->
atime();
1952#if SET_FILE_OP_TIMES
1953 return std::max(m_mtime, m_source->
mtime());
1955 return m_source->
mtime();
1966#if SET_FILE_OP_TIMES
1974#if SET_FILE_OP_TIMES
1983 if (m_cache.status != cache_t::cache_t::status_t::dirty)
1984 m_state = state_t::ok;
1988 m_cache.status = cache_t::cache_t::status_t::loaded;
1991 m_state = state_t::ok;
1992 m_cache.status = cache_t::cache_t::status_t::loaded;
1996 void invalidate_cache()
1998 if (m_cache.status == cache_t::cache_t::status_t::dirty && !m_cache.
region.
empty()) {
2000 if (!
ok()) _Unlikely_
2003 m_state = state_t::ok;
2004 m_cache.status = cache_t::cache_t::status_t::empty;
2007 void load_cache(_In_ fpos_t start)
2009 assert(m_cache.status != cache_t::cache_t::status_t::dirty);
2010 start -= start % m_cache.capacity;
2012 if (m_source->
ok()) {
2013 m_cache.
region.
end = start + m_source->
read(m_cache.data, m_cache.capacity);
2014 m_cache.status = cache_t::cache_t::status_t::loaded;
2015 m_state = state_t::ok;
2018 m_state = state_t::fail;
2023 assert(m_cache.status == cache_t::cache_t::status_t::dirty);
2025 m_source->
write(m_cache.data,
static_cast<size_t>(m_cache.
region.
size()));
2026 m_state = m_source->
state();
2029 basic_file* m_source;
2033 enum class status_t {
2040 cache_t(_In_
size_t _capacity) :
2041 data(new uint8_t[_capacity]),
2042 capacity(_capacity),
2043 status(status_t::empty),
2053#if SET_FILE_OP_TIMES
2066 basic_sys(_In_opt_ sys_handle h = invalid_handle, _In_ state_t
state = state_t::ok) :
2071 virtual _Success_(
return != 0 || length == 0) size_t
read(
2072 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
2074 assert(data || !length);
2080 block_size = 0x1F80000;
2081#elif defined(_WIN32)
2082 block_size = 0x3f00000;
2084 block_size = SSIZE_MAX;
2086 for (
size_t to_read = length;;) {
2091 __try { succeeded = ReadFile(m_h, data,
static_cast<DWORD
>(std::min<size_t>(to_read, block_size)), &num_read,
nullptr); }
2092 __except (EXCEPTION_EXECUTE_HANDLER) { succeeded = FALSE; SetLastError(ERROR_UNHANDLED_EXCEPTION); num_read = 0; }
2093 if (!succeeded && GetLastError() == ERROR_NO_SYSTEM_RESOURCES && block_size > default_block_size) _Unlikely_ {
2096 block_size = default_block_size;
2099 if (!succeeded) _Unlikely_
2101 ssize_t num_read =
::read(m_h, data,
static_cast<ssize_t
>(std::min<size_t>(to_read, block_size)));
2102 if (num_read < 0) _Unlikely_
2105 m_state = to_read < length ? state_t::ok : state_t::fail;
2106 return length - to_read;
2108 if (!num_read) _Unlikely_ {
2109 m_state = to_read < length || !length ? state_t::ok : state_t::eof;
2110 return length - to_read;
2112 to_read -= num_read;
2114 m_state = state_t::ok;
2117 reinterpret_cast<uint8_t*&
>(data) += num_read;
2121 virtual _Success_(
return != 0) size_t
write(
2122 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
2129 block_size = 0x1F80000;
2130#elif defined(_WIN32)
2131 block_size = 0x3f00000;
2133 block_size = SSIZE_MAX;
2135 for (
size_t to_write = length;;) {
2140 __try { succeeded = WriteFile(m_h, data,
static_cast<DWORD
>(std::min<size_t>(to_write, block_size)), &num_written,
nullptr); }
2141 __except (EXCEPTION_EXECUTE_HANDLER) { succeeded = FALSE; SetLastError(ERROR_UNHANDLED_EXCEPTION); num_written = 0; }
2142 to_write -= num_written;
2144 m_state = state_t::ok;
2147 reinterpret_cast<const uint8_t*&
>(data) += num_written;
2148 if (!succeeded) _Unlikely_ {
2149 m_state = state_t::fail;
2150 return length - to_write;
2153 ssize_t num_written =
::write(m_h, data,
static_cast<ssize_t
>(std::min<size_t>(to_write, block_size)));
2154 if (num_written < 0) _Unlikely_ {
2155 m_state = state_t::fail;
2156 return length - to_write;
2158 to_write -= num_written;
2160 m_state = state_t::ok;
2163 reinterpret_cast<const uint8_t*&
>(data) += num_written;
2172 m_state = state_t::ok;
2175 m_state = state_t::fail;
2182 m_state = FlushFileBuffers(m_h) ? state_t::ok : state_t::fail;
2184 m_state = fsync(m_h) >= 0 ? state_t::ok : state_t::fail;
2195 buffered_sys(_In_opt_ sys_handle h = invalid_handle,
size_t read_buffer_size = default_buffer_size,
size_t write_buffer_size = default_buffer_size) :
2196 buffer(read_buffer_size, write_buffer_size),
2215 class sequential_stream :
public basic
2218 sequential_stream(_In_ ISequentialStream* source) : m_source(source)
2223 virtual ~sequential_stream()
2225 m_source->Release();
2228 virtual _Success_(
return != 0 || length == 0) size_t read(
2229 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
2231 assert(data || !length);
2232 for (
size_t to_read = length;;) {
2235 __try { hr = m_source->Read(data, (ULONG)std::min<size_t>(to_read, ULONG_MAX), &num_read); }
2236 __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; }
2237 if (FAILED(hr)) _Unlikely_ {
2238 m_state = to_read < length ? state_t::ok : state_t::fail;
2239 return length - to_read;
2241 to_read -= num_read;
2242 if (hr == S_FALSE) _Unlikely_ {
2243 m_state = to_read < length || !length ? state_t::ok : state_t::eof;
2244 return length - to_read;
2247 m_state = state_t::ok;
2250 reinterpret_cast<uint8_t*&
>(data) += num_read;
2254 virtual _Success_(
return != 0) size_t write(
2255 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
2257 assert(data || !length);
2258 for (
size_t to_write = length;;) {
2260 ULONG num_written = 0;
2261 __try { hr = m_source->Write(data,
static_cast<ULONG
>(std::min<size_t>(to_write, ULONG_MAX)), &num_written); }
2262 __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; }
2265 if (FAILED(hr)) _Unlikely_ {
2266 m_state = state_t::fail;
2267 return length - to_write;
2269 to_write -= num_written;
2271 m_state = state_t::ok;
2274 reinterpret_cast<const uint8_t*&
>(data) += num_written;
2279 ISequentialStream* m_source;
2285 class asp :
public basic
2288 asp(_In_opt_ IRequest* request, _In_opt_ IResponse* response) :
2290 m_response(response)
2293 m_request->AddRef();
2295 m_response->AddRef();
2301 m_request->Release();
2303 m_response->Release();
2306 virtual _Success_(
return != 0 || length == 0) size_t read(
2307 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
2309 assert(data || !length);
2310 if (!m_request) _Unlikely_ {
2311 m_state = state_t::fail;
2314 for (
size_t to_read = length;;) {
2315 VARIANT var_amount, var_data;
2316 V_VT(&var_amount) = VT_I4;
2317 V_I4(&var_amount) = (LONG)std::min<size_t>(to_read, LONG_MAX);
2318 V_VT(&var_data) = VT_EMPTY;
2319 HRESULT hr = [&]() {
2320 __try {
return m_request->BinaryRead(&var_amount, &var_data); }
2321 __except (EXCEPTION_EXECUTE_HANDLER) {
return E_FAIL; }
2323 if (FAILED(hr)) _Unlikely_ {
2324 m_state = to_read < length ? state_t::ok : state_t::fail;
2325 return length - to_read;
2327 assert(V_VT(&var_amount) == VT_I4);
2328 assert(V_VT(&var_data) == (VT_ARRAY | VT_UI1));
2329 std::unique_ptr<SAFEARRAY, SafeArrayDestroy_delete> sa(V_ARRAY(&var_data));
2330 if (!V_I4(&var_amount)) _Unlikely_ {
2331 m_state = to_read < length || !length ? state_t::ok : state_t::eof;
2332 return length - to_read;
2334 safearray_accessor<uint8_t> a(sa.get());
2335 memcpy(data, a.data(), V_I4(&var_amount));
2336 to_read -= V_I4(&var_amount);
2338 m_state = state_t::ok;
2341 reinterpret_cast<uint8_t*&
>(data) += V_I4(&var_amount);
2345 virtual _Success_(
return != 0) size_t write(
2346 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
2349 m_state = state_t::fail;
2352 for (
size_t to_write = length;;) {
2353 UINT num_written =
static_cast<UINT
>(std::min<size_t>(to_write, UINT_MAX));
2354 std::unique_ptr<OLECHAR, SysFreeString_delete> bstr_data(SysAllocStringByteLen(
reinterpret_cast<LPCSTR
>(data), num_written));
2356 V_VT(&var_data) = VT_BSTR;
2357 V_BSTR(&var_data) = bstr_data.get();
2358 HRESULT hr = [&]() {
2359 __try {
return m_response->BinaryWrite(var_data); }
2360 __except (EXCEPTION_EXECUTE_HANDLER) {
return E_FAIL; }
2362 if (FAILED(hr)) _Unlikely_ {
2363 m_state = state_t::fail;
2364 return length - to_write;
2366 to_write -= num_written;
2368 m_state = state_t::ok;
2371 reinterpret_cast<const uint8_t*&
>(data) += num_written;
2375 virtual void close()
2378 __try { m_response->End(); }
2379 __except (EXCEPTION_EXECUTE_HANDLER) {}
2381 m_state = state_t::ok;
2384 virtual void flush()
2388 __try { hr = m_response->Flush(); }
2389 __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; }
2390 m_state = SUCCEEDED(hr) ? state_t::ok : state_t::fail;
2395 IRequest* m_request;
2396 IResponse* m_response;
2405 mode_for_reading = 1 << 0,
2406 mode_for_writing = 1 << 1,
2407 mode_for_chmod = 1 << 2,
2408 mode_create = 1 << 3,
2409 mode_preserve_existing = mode_create | (1 << 4),
2410 mode_append = 1 << 5,
2412 mode_binary = 1 << 6,
2415 share_reading = 1 << 7,
2416 share_writing = 1 << 8,
2417 share_deleting = 1 << 9,
2418 share_all = share_reading | share_writing | share_deleting,
2420 inherit_handle = 1 << 10,
2422 hint_write_thru = 1 << 11,
2423 hint_no_buffering = 1 << 12,
2424 hint_random_access = 1 << 13,
2425 hint_sequential_access = 1 << 14,
2428#pragma warning(push)
2429#pragma warning(disable: 4250)
2444 file(_In_z_
const schar_t* filename, _In_
int mode)
2446 open(filename, mode);
2455 void open(_In_z_
const schar_t* filename, _In_
int mode)
2457 if (m_h != invalid_handle)
2461 DWORD dwDesiredAccess = 0;
2462 if (mode & mode_for_reading) dwDesiredAccess |= GENERIC_READ;
2463 if (mode & mode_for_writing) dwDesiredAccess |= GENERIC_WRITE;
2464 if (mode & mode_for_chmod) dwDesiredAccess |= FILE_WRITE_ATTRIBUTES;
2466 DWORD dwShareMode = 0;
2467 if (mode & share_reading) dwShareMode |= FILE_SHARE_READ;
2468 if (mode & share_writing) dwShareMode |= FILE_SHARE_WRITE;
2469 if (mode & share_deleting) dwShareMode |= FILE_SHARE_DELETE;
2471 SECURITY_ATTRIBUTES sa = {
sizeof(SECURITY_ATTRIBUTES) };
2472 sa.bInheritHandle = mode & inherit_handle ? true :
false;
2474 DWORD dwCreationDisposition;
2475 switch (mode & mode_preserve_existing) {
2476 case mode_create: dwCreationDisposition = CREATE_ALWAYS;
break;
2477 case mode_preserve_existing: dwCreationDisposition = OPEN_ALWAYS;
break;
2478 case 0: dwCreationDisposition = OPEN_EXISTING;
break;
2479 default:
throw std::invalid_argument(
"invalid mode");
2482 DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
2483 if (mode & hint_write_thru) dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
2484 if (mode & hint_no_buffering) dwFlagsAndAttributes |= FILE_FLAG_NO_BUFFERING;
2485 if (mode & hint_random_access) dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
2486 if (mode & hint_sequential_access) dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
2488 m_h = CreateFile(filename, dwDesiredAccess, dwShareMode, &sa, dwCreationDisposition, dwFlagsAndAttributes,
nullptr);
2491 switch (mode & (mode_for_reading | mode_for_writing)) {
2492 case mode_for_reading: flags |= O_RDONLY;
break;
2493 case mode_for_writing: flags |= O_WRONLY;
break;
2494 case mode_for_reading | mode_for_writing: flags |= O_RDWR;
break;
2496 if (mode & mode_create) flags |= mode & mode_preserve_existing ? O_CREAT : (O_CREAT | O_EXCL);
2497 if (mode & hint_write_thru) flags |= O_DSYNC;
2499 if (mode & hint_no_buffering) flags |= O_RSYNC;
2502 m_h =
::open(filename, flags, DEFFILEMODE);
2504 if (m_h != invalid_handle) {
2505 m_state = state_t::ok;
2506 if (mode & mode_append)
2507 seek(0, seek_t::end);
2510 m_state = state_t::fail;
2513 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
2517 li.QuadPart = offset;
2518 li.LowPart = SetFilePointer(m_h, li.LowPart, &li.HighPart,
static_cast<DWORD
>(how));
2519 if (li.LowPart != 0xFFFFFFFF || GetLastError() == NO_ERROR) {
2520 m_state = state_t::ok;
2524 off64_t result = lseek64(m_h, offset,
static_cast<int>(how));
2526 m_state = state_t::ok;
2530 m_state = state_t::fail;
2536 if (m_h != invalid_handle) {
2540 li.LowPart = SetFilePointer(m_h, 0, &li.HighPart, FILE_CURRENT);
2541 if (li.LowPart != 0xFFFFFFFF || GetLastError() == NO_ERROR)
2544 off64_t result = lseek64(m_h, 0, SEEK_CUR);
2552 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
2555 LARGE_INTEGER liOffset;
2556 LARGE_INTEGER liSize;
2557 liOffset.QuadPart = offset;
2558 liSize.QuadPart = length;
2559 if (LockFile(m_h, liOffset.LowPart, liOffset.HighPart, liSize.LowPart, liSize.HighPart)) {
2560 m_state = state_t::ok;
2564 off64_t orig = lseek64(m_h, 0, SEEK_CUR);
2566 m_state = lseek64(m_h, offset, SEEK_SET) >= 0 && lockf64(m_h, F_LOCK, length) >= 0 ? state_t::ok : state_t::fail;
2567 lseek64(m_h, orig, SEEK_SET);
2568 m_state = state_t::ok;
2572 m_state = state_t::fail;
2575 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
2578 LARGE_INTEGER liOffset;
2579 LARGE_INTEGER liSize;
2580 liOffset.QuadPart = offset;
2581 liSize.QuadPart = length;
2582 if (UnlockFile(m_h, liOffset.LowPart, liOffset.HighPart, liSize.LowPart, liSize.HighPart)) {
2583 m_state = state_t::ok;
2587 off64_t orig = lseek64(m_h, 0, SEEK_CUR);
2589 if (lseek64(m_h, offset, SEEK_SET) >= 0 && lockf64(m_h, F_ULOCK, length) >= 0) {
2590 lseek64(m_h, orig, SEEK_SET);
2591 m_state = state_t::ok;
2594 lseek64(m_h, orig, SEEK_SET);
2597 m_state = state_t::fail;
2604 li.LowPart = GetFileSize(m_h, (LPDWORD)&li.HighPart);
2605 if (li.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR)
2609 off64_t length = -1, orig = lseek64(m_h, 0, SEEK_CUR);
2611 length = lseek64(m_h, 0, SEEK_END);
2612 lseek64(m_h, orig, SEEK_SET);
2621 if (SetEndOfFile(m_h)) {
2622 m_state = state_t::ok;
2626 off64_t length = lseek64(m_h, 0, SEEK_CUR);
2627 if (length >= 0 && ftruncate64(m_h, length) >= 0) {
2628 m_state = state_t::ok;
2632 m_state = state_t::fail;
2636 static inline time_point ft2tp(_In_
const FILETIME& ft)
2639 uint64_t t = (
static_cast<int64_t
>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
2641 uint64_t t = ((
static_cast<int64_t
>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000ll;
2643 return time_point(time_point::duration(t));
2646 static inline void tp2ft(_In_ time_point tp, _Out_ FILETIME& ft)
2649 uint64_t t = tp.time_since_epoch().count();
2651 uint64_t t = tp.time_since_epoch().count() + 116444736000000000ll;
2653 ft.dwHighDateTime =
static_cast<DWORD
>((t >> 32) & 0xffffffff);
2654 ft.dwLowDateTime =
static_cast<DWORD
>(t & 0xffffffff);
2662 if (GetFileTime(m_h, &ft,
nullptr,
nullptr))
2665 return time_point::min();
2672 if (GetFileTime(m_h,
nullptr, &ft,
nullptr))
2676 if (fstat(m_h, &buf) >= 0)
2677 return clock::from_time_t(buf.st_atime);
2679 return time_point::min();
2686 if (GetFileTime(m_h,
nullptr,
nullptr, &ft))
2690 if (fstat(m_h, &buf) >= 0)
2691 return clock::from_time_t(buf.st_mtime);
2693 return time_point::min();
2698 assert(m_h != invalid_handle);
2702 if (SetFileTime(m_h, &ft,
nullptr,
nullptr))
2705 throw std::runtime_error(
"failed to set file ctime");
2710 assert(m_h != invalid_handle);
2714 if (SetFileTime(m_h,
nullptr, &ft,
nullptr))
2717 struct timespec ts[2] = {
2718 { date.time_since_epoch().count(), 0 },
2721 if (futimens(m_h, ts) >= 0)
2724 throw std::runtime_error(
"failed to set file atime");
2732 if (SetFileTime(m_h,
nullptr,
nullptr, &ft))
2735 struct timespec ts[2] = {
2737 { date.time_since_epoch().count(), 0 },
2739 if (futimens(m_h, ts) >= 0)
2742 throw std::runtime_error(
"failed to set file mtime");
2753 cached_file(_In_opt_ sys_handle h = invalid_handle, _In_ state_t
state = state_t::ok, _In_
size_t cache_size = default_cache_size) :
2767 cached_file(_In_z_
const schar_t* filename, _In_
int mode, _In_
size_t cache_size = default_cache_size) :
2769 m_source(filename, mode & mode_for_writing ? mode | mode_for_reading : mode)
2785 void open(_In_z_
const schar_t* filename, _In_
int mode)
2788 if (!
ok()) _Unlikely_{
2789 m_state = state_t::fail;
2792 m_source.
open(filename, mode & mode_for_writing ? mode | mode_for_reading : mode);
2793 if (m_source.
ok()) {
2794#if SET_FILE_OP_TIMES
2795 m_atime = m_source.
atime();
2796 m_mtime = m_source.
mtime();
2799 m_state = state_t::ok;
2802 m_state = state_t::fail;
2823#if SET_FILE_OP_TIMES
2824 m_ctime = m_atime = m_mtime = time_point::now();
2836 m_data(reinterpret_cast<uint8_t*>(malloc(
size))),
2843 throw std::bad_alloc();
2844#if SET_FILE_OP_TIMES
2845 m_ctime = m_atime = m_mtime = time_point::now();
2867 assert(reserved >=
size);
2868#if SET_FILE_OP_TIMES
2869 m_ctime = m_atime = m_mtime = time_point::now();
2893 load(filename, mode);
2908 void reserve(_In_
size_t required, _In_
bool tight =
false) noexcept
2911 m_state = state_t::ok;
2915 m_state = state_t::fail;
2918 size_t reserved = tight ? required : ((required + required / 4 + (default_block_size - 1)) / default_block_size) * default_block_size;
2919 auto data =
reinterpret_cast<uint8_t*
>(realloc(
m_data, reserved));
2920 if (!
data && reserved) _Unlikely_ {
2921 m_state = state_t::fail;
2928 m_state = state_t::ok;
2937 void load(_In_z_
const schar_t* filename, _In_
int mode)
2939 file f(filename, (mode & ~hint_random_access) | mode_for_reading | hint_sequential_access);
2941 m_state = state_t::fail;
2945 if (
size > SIZE_MAX) {
2946 m_state = state_t::fail;
2950 if (!
ok()) _Unlikely_ {
2957#if SET_FILE_OP_TIMES
2958 m_ctime = f.
ctime();
2959 m_atime = f.
atime();
2960 m_mtime = f.
mtime();
2970 void save(_In_z_
const schar_t* filename, _In_
int mode)
2972 file f(filename, (mode & ~hint_random_access) | mode_for_writing | hint_sequential_access);
2974 m_state = state_t::fail;
2979 m_state = state_t::fail;
2983#if SET_FILE_OP_TIMES
2995 virtual _Success_(
return != 0 || length == 0) size_t
read(
2996 _Out_writes_bytes_to_opt_(length, return)
void*
data, _In_
size_t length)
2998 assert(
data || !length);
2999#if SET_FILE_OP_TIMES
3000 m_atime = time_point::now();
3003 if (length <= available) {
3006 m_state = state_t::ok;
3009 if (length && !available) {
3010 m_state = state_t::eof;
3015 m_state = state_t::ok;
3036#if SET_FILE_OP_TIMES
3037 m_atime = time_point::now();
3039 if (CHECK_STREAM_STATE && !
ok()) _Unlikely_ {
3043 size_t end_offset =
m_offset +
sizeof(T);
3044 if (end_offset <=
m_size) {
3047#if !CHECK_STREAM_STATE
3048 m_state = state_t::ok;
3054 m_state = state_t::eof;
3073 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
3076#if SET_FILE_OP_TIMES
3077 m_atime = time_point::now();
3079 if (CHECK_STREAM_STATE && !
ok()) _Unlikely_ {
3083 size_t end_offset =
m_offset +
sizeof(uint32_t);
3084 if (end_offset <=
m_size) {
3085 uint32_t num_chars = LE2HE(*
reinterpret_cast<uint32_t*
>(
m_data +
m_offset));
3087 end_offset = stdex::add(
m_offset, stdex::mul(num_chars,
sizeof(_Elem)));
3089 if (end_offset <=
m_size) {
3090 data.assign(start, start + num_chars);
3092#if !CHECK_STREAM_STATE
3093 m_state = state_t::ok;
3097 if (end_offset <=
m_size)
3101 m_state = state_t::eof;
3105 virtual _Success_(
return != 0) size_t
write(
3106 _In_reads_bytes_opt_(length) const
void*
data, _In_
size_t length)
3108 assert(
data || !length);
3109#if SET_FILE_OP_TIMES
3110 m_atime = m_mtime = time_point::now();
3112 size_t end_offset =
m_offset + length;
3115 if (!
ok()) _Unlikely_
3122 m_state = state_t::ok;
3131#if SET_FILE_OP_TIMES
3132 m_atime = m_mtime = time_point::now();
3134 size_t end_offset =
m_offset + amount;
3137 if (!
ok()) _Unlikely_
3144 m_state = state_t::ok;
3164#if SET_FILE_OP_TIMES
3165 m_atime = m_mtime = time_point::now();
3167 if (CHECK_STREAM_STATE && !
ok()) _Unlikely_
3169 size_t end_offset =
m_offset +
sizeof(T);
3172 if (!
ok()) _Unlikely_
3179#if !CHECK_STREAM_STATE
3180 m_state = state_t::ok;
3202#if SET_FILE_OP_TIMES
3203 m_atime = m_mtime = time_point::now();
3205 if (CHECK_STREAM_STATE && !
ok()) _Unlikely_
3207 size_t num_chars = stdex::strlen(
data);
3208 if (num_chars > UINT32_MAX)
3209 throw std::invalid_argument(
"string too long");
3210 size_t size_chars = num_chars *
sizeof(T);
3211 size_t size =
sizeof(uint32_t) + size_chars;
3215 if (!
ok()) _Unlikely_
3219 *
reinterpret_cast<uint32_t*
>(p) = HE2LE((uint32_t)num_chars);
3220 memcpy(p +
sizeof(uint32_t),
data, size_chars);
3224#if !CHECK_STREAM_STATE
3225 m_state = state_t::ok;
3237#if SET_FILE_OP_TIMES
3238 m_atime = m_mtime = time_point::now();
3241 size_t num_copied = 0, to_write = amount;
3242 m_state = state_t::ok;
3243 if (amount != SIZE_MAX) {
3244 dst_size = stdex::add(dst_size, amount);
3246 if (!
ok()) _Unlikely_
3249 num_read = stream.read(
m_data + dst_offset, to_write);
3250 dst_size = dst_offset += num_read;
3251 num_copied += num_read;
3252 to_write -= num_read;
3254 if (stream.state() != state_t::eof)
3255 m_state = state_t::fail;
3263 block_size = std::min(to_write, default_block_size);
3264 dst_size = stdex::add(dst_size, block_size);
3266 if (!
ok()) _Unlikely_
3268 num_read = stream.read(
m_data + dst_offset, block_size);
3269 dst_size = dst_offset += num_read;
3270 num_copied += num_read;
3271 to_write -= num_read;
3273 if (stream.state() != state_t::eof)
3274 m_state = state_t::fail;
3293#if SET_FILE_OP_TIMES
3294 m_ctime = m_atime = m_mtime = time_point::min();
3296 m_state = state_t::ok;
3299 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
3303 case seek_t::beg: target = offset;
break;
3304 case seek_t::cur: target =
static_cast<fpos_t
>(
m_offset) + offset;
break;
3305 case seek_t::end: target =
static_cast<fpos_t
>(
m_size) + offset;
break;
3306 default:
throw std::invalid_argument(
"unknown seek origin");
3308 if (target <= SIZE_MAX) {
3309 m_state = state_t::ok;
3310 return m_offset =
static_cast<size_t>(target);
3312 m_state = state_t::fail;
3328#if SET_FILE_OP_TIMES
3329 m_atime = m_mtime = time_point::now();
3335#if SET_FILE_OP_TIMES
3336 virtual time_point
ctime()
const
3341 virtual time_point
atime()
const
3346 virtual time_point
mtime()
const
3376 inline void set(_In_ fpos_t offset, _In_
const T
data)
3378#if SET_FILE_OP_TIMES
3379 m_atime = m_mtime = time_point::now();
3381 assert(offset +
sizeof(T) <
m_size);
3382 (*
reinterpret_cast<T*
>(
m_data + offset)) = HE2LE(
data);
3386 inline void set(_In_ fpos_t offset, _In_
const int8_t
data) { set<int8_t>(offset,
data); }
3387 inline void set(_In_ fpos_t offset, _In_
const int16_t
data) { set<int16_t>(offset,
data); }
3388 inline void set(_In_ fpos_t offset, _In_
const int32_t
data) { set<int32_t>(offset,
data); }
3389 inline void set(_In_ fpos_t offset, _In_
const int64_t
data) { set<int64_t>(offset,
data); }
3390 inline void set(_In_ fpos_t offset, _In_
const uint8_t
data) { set<uint8_t>(offset,
data); }
3391 inline void set(_In_ fpos_t offset, _In_
const uint16_t
data) { set<uint16_t>(offset,
data); }
3392 inline void set(_In_ fpos_t offset, _In_
const uint32_t
data) { set<uint32_t>(offset,
data); }
3393 inline void set(_In_ fpos_t offset, _In_
const uint64_t
data) { set<uint64_t>(offset,
data); }
3394 inline void set(_In_ fpos_t offset, _In_
const float data) { set<float>(offset,
data); }
3395 inline void set(_In_ fpos_t offset, _In_
const double data) { set<double>(offset,
data); }
3396 inline void set(_In_ fpos_t offset, _In_
const char data) { set<char>(offset,
data); }
3397#ifdef _NATIVE_WCHAR_T_DEFINED
3398 inline void set(_In_ fpos_t offset, _In_
const wchar_t data) { set<wchar_t>(offset,
data); }
3410 inline void get(_In_ fpos_t offset, _Out_ T &
data)
3412 assert(offset +
sizeof(T) <
m_size);
3414#if SET_FILE_OP_TIMES
3415 m_atime = time_point::now();
3420 inline void get(_In_ fpos_t offset, _Out_ int8_t &
data) { get<int8_t>(offset,
data); }
3421 inline void get(_In_ fpos_t offset, _Out_ int16_t &
data) { get<int16_t>(offset,
data); }
3422 inline void get(_In_ fpos_t offset, _Out_ int32_t &
data) { get<int32_t>(offset,
data); }
3423 inline void get(_In_ fpos_t offset, _Out_ int64_t &
data) { get<int64_t>(offset,
data); }
3424 inline void get(_In_ fpos_t offset, _Out_ uint8_t &
data) { get<uint8_t>(offset,
data); }
3425 inline void get(_In_ fpos_t offset, _Out_ uint16_t &
data) { get<uint16_t>(offset,
data); }
3426 inline void get(_In_ fpos_t offset, _Out_ uint32_t &
data) { get<uint32_t>(offset,
data); }
3427 inline void get(_In_ fpos_t offset, _Out_ uint64_t &
data) { get<uint64_t>(offset,
data); }
3428 inline void get(_In_ fpos_t offset, _Out_
float&
data) { get<float>(offset,
data); }
3429 inline void get(_In_ fpos_t offset, _Out_
double&
data) { get<double>(offset,
data); }
3430 inline void get(_In_ fpos_t offset, _Out_
char&
data) { get<char>(offset,
data); }
3431#ifdef _NATIVE_WCHAR_T_DEFINED
3432 inline void get(_In_ fpos_t offset, _Out_
wchar_t&
data) { get<wchar_t>(offset,
data); }
3436 inline memory_file& operator >>(_Out_ int8_t &
data) {
return read_data(
data); }
3437 inline memory_file& operator <<(_In_
const int16_t
data) {
return write_data(
data); }
3438 inline memory_file& operator >>(_Out_ int16_t &
data) {
return read_data(
data); }
3439 inline memory_file& operator <<(_In_
const int32_t
data) {
return write_data(
data); }
3440 inline memory_file& operator >>(_Out_ int32_t &
data) {
return read_data(
data); }
3441 inline memory_file& operator <<(_In_
const int64_t
data) {
return write_data(
data); }
3442 inline memory_file& operator >>(_Out_ int64_t &
data) {
return read_data(
data); }
3443 inline memory_file& operator <<(_In_
const uint8_t
data) {
return write_data(
data); }
3444 inline memory_file& operator >>(_Out_ uint8_t &
data) {
return read_data(
data); }
3445 inline memory_file& operator <<(_In_
const uint16_t
data) {
return write_data(
data); }
3446 inline memory_file& operator >>(_Out_ uint16_t &
data) {
return read_data(
data); }
3447 inline memory_file& operator <<(_In_
const uint32_t
data) {
return write_data(
data); }
3448 inline memory_file& operator >>(_Out_ uint32_t &
data) {
return read_data(
data); }
3449 inline memory_file& operator <<(_In_
const uint64_t
data) {
return write_data(
data); }
3450 inline memory_file& operator >>(_Out_ uint64_t &
data) {
return read_data(
data); }
3457#ifdef _NATIVE_WCHAR_T_DEFINED
3458 inline memory_file& operator <<(_In_
const wchar_t data) {
return write_data(
data); }
3459 inline memory_file& operator >>(_Out_
wchar_t&
data) {
return read_data(
data); }
3462 inline memory_file& operator <<(_In_
const T *
data) {
return write_str(
data); }
3463 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
3464 inline memory_file& operator >>(_Inout_ std::basic_string<_Elem, _Traits, _Ax>&
data) {
return read_str(
data); }
3472#if SET_FILE_OP_TIMES
3501#pragma warning(suppress: 6101)
3502 virtual _Success_(
return != 0 || length == 0) size_t
read(
3503 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
3505 assert(data || !length);
3506 for (
size_t to_read = length;;) {
3507 if (!m_head) _Unlikely_ {
3509 m_state = to_read < length || !length ? state_t::ok : state_t::eof;
3510 return length - to_read;
3512 size_t remaining = m_head->size - m_offset;
3513 if (remaining > to_read) {
3514 memcpy(data, m_head->data + m_offset, to_read);
3515 m_offset += to_read;
3517 m_state = state_t::ok;
3520 memcpy(data, m_head->data + m_offset, remaining);
3522 m_size -= remaining;
3523 reinterpret_cast<uint8_t*&
>(data) += remaining;
3524 to_read -= remaining;
3531 virtual _Success_(
return != 0) size_t
write(
3532 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
3534 assert(data || !length);
3536 std::unique_ptr<node_t> n(
reinterpret_cast<node_t*
>(
new uint8_t[
sizeof(
node_t) + length]));
3539 memcpy(n->data, data, length);
3542 m_tail = m_tail->next = n.release();
3544 m_head = m_tail = n.release();
3545 m_state = state_t::ok;
3548 catch (
const std::bad_alloc&) {
3549 m_state = state_t::fail;
3556 m_size = m_offset = 0;
3562 m_state = state_t::ok;
3568 inline size_t size()
const {
return m_size; };
3571 size_t m_offset, m_size;
3575#pragma warning(suppress:4200)
3577 } *m_head, * m_tail;
3586 basic(num_files ? files[0]->
state() : state_t::fail),
3587 m_files(files, files + num_files)
3591 virtual _Success_(
return != 0 || length == 0) size_t
read(
3592 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
3594 assert(data || !length);
3595 if (m_files.empty()) {
3596 m_state = state_t::fail;
3599 size_t result = m_files[0]->read(data, length);
3600 _Analysis_assume_(result <= length);
3601 m_state = m_files[0]->state();
3602 if (length > m_tmp.size())
3603 m_tmp.resize(length);
3604 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3605 if (m_files[i]->
read(m_tmp.data(), length) != result ||
3606 memcmp(m_tmp.data(), data, result))
3607 throw std::runtime_error(
"read mismatch");
3608 if (m_files[i]->
state() != m_state)
3609 throw std::runtime_error(
"state mismatch");
3614 virtual _Success_(
return != 0) size_t
write(
3615 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
3617 if (m_files.empty()) {
3618 m_state = state_t::fail;
3621 size_t result = m_files[0]->write(data, length);
3622 m_state = m_files[0]->state();
3623 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3624 if (m_files[i]->
write(data, length) != result)
3625 throw std::runtime_error(
"write mismatch");
3626 if (m_files[i]->
state() != m_state)
3627 throw std::runtime_error(
"state mismatch");
3634 if (m_files.empty()) {
3635 m_state = state_t::ok;
3638 m_files[0]->flush();
3639 m_state = m_files[0]->state();
3640 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3641 m_files[i]->flush();
3642 if (m_files[i]->
state() != m_state)
3643 throw std::runtime_error(
"state mismatch");
3649 if (m_files.empty()) {
3650 m_state = state_t::ok;
3653 m_files[0]->close();
3654 m_state = m_files[0]->state();
3655 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3656 m_files[i]->close();
3657 if (m_files[i]->
state() != m_state)
3658 throw std::runtime_error(
"state mismatch");
3661 m_tmp.shrink_to_fit();
3664 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
3666 if (m_files.empty()) {
3667 m_state = state_t::fail;
3670 fpos_t result = m_files[0]->seek(offset, how);
3671 m_state = m_files[0]->state();
3672 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3673 if (m_files[i]->
seek(offset, how) != result)
3674 throw std::runtime_error(
"seek mismatch");
3675 if (m_files[i]->
state() != m_state)
3676 throw std::runtime_error(
"state mismatch");
3683 if (m_files.empty())
3685 fpos_t result = m_files[0]->tell();
3686 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3687 if (m_files[i]->
tell() != result)
3688 throw std::runtime_error(
"tell mismatch");
3693 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
3695 if (m_files.empty())
3696 m_state = state_t::fail;
3697 m_files[0]->lock(offset, length);
3698 m_state = m_files[0]->state();
3699 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3700 m_files[i]->lock(offset, length);
3701 if (m_files[i]->
state() != m_state)
3702 throw std::runtime_error(
"state mismatch");
3706 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
3708 if (m_files.empty())
3709 m_state = state_t::fail;
3710 m_files[0]->unlock(offset, length);
3711 m_state = m_files[0]->state();
3712 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3713 m_files[i]->unlock(offset, length);
3714 if (m_files[i]->
state() != m_state)
3715 throw std::runtime_error(
"state mismatch");
3721 if (m_files.empty()) {
3722 m_state = state_t::fail;
3725 fsize_t result = m_files[0]->size();
3726 m_state = m_files[0]->state();
3727 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3728 if (m_files[i]->
size() != result)
3729 throw std::runtime_error(
"size mismatch");
3730 if (m_files[i]->
state() != m_state)
3731 throw std::runtime_error(
"state mismatch");
3738 if (m_files.empty())
3739 m_state = state_t::fail;
3740 m_files[0]->truncate();
3741 m_state = m_files[0]->state();
3742 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3743 m_files[i]->truncate();
3744 if (m_files[i]->
state() != m_state)
3745 throw std::runtime_error(
"state mismatch");
3750 std::vector<basic_file*> m_files;
3751 std::vector<uint8_t> m_tmp;
Provides read-ahead stream capability.
Definition stream.hpp:1118
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:1132
Provides write-back stream capability.
Definition stream.hpp:1186
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1223
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:1199
Basic seekable stream operations.
Definition stream.hpp:696
virtual void skip(fsize_t amount)
Skips given amount of bytes of data on the stream.
Definition stream.hpp:739
virtual time_point ctime() const
Returns file creation time.
Definition stream.hpp:786
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:755
virtual void truncate()=0
Sets file size - truncates the remainder of file content from the current file position to the end of...
charset_id read_charset(charset_id default_charset=charset_id::system)
Attempts to detect textfile charset based on UTF16 or UTF8 BOM.
Definition stream.hpp:859
fpos_t seekbeg(fpos_t offset)
Seeks to absolute file position.
Definition stream.hpp:723
virtual std::vector< uint8_t > read_remainder(size_t max_length=SIZE_MAX)
Reads and returns remainder of the stream.
Definition stream.hpp:698
virtual void set_mtime(time_point date)
Sets file modification time.
Definition stream.hpp:828
fpos_t seekcur(foff_t offset)
Seeks to relative from current file position.
Definition stream.hpp:730
virtual time_point atime() const
Returns file access time.
Definition stream.hpp:794
virtual void set_ctime(time_point date)
Sets file create time.
Definition stream.hpp:810
virtual fsize_t size()=0
Returns file size Should the file size cannot be determined, the method returns fsize_max and it does...
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:765
virtual fpos_t tell() const =0
Returns absolute file position in file or fpos_max if fails. This method does not update stream state...
virtual time_point mtime() const
Returns file modification time.
Definition stream.hpp:802
fpos_t seekend(foff_t offset)
Seeks to relative from end file position.
Definition stream.hpp:737
virtual void set_atime(time_point date)
Sets file access time.
Definition stream.hpp:819
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)=0
Seeks to specified relative file position.
OS data stream (file, pipe, socket...)
Definition stream.hpp:2064
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:2121
virtual void flush()
Persists volatile element data.
Definition stream.hpp:2179
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:2071
virtual void close()
Closes the stream.
Definition stream.hpp:2168
UTF-8 byte-order-mark
Definition stream.hpp:76
bool ok() const
Returns true if the stream state is clean i.e. previous operation was succesful.
Definition stream.hpp:170
size_t write_vsprintf(_Printf_format_string_params_(2) const char *format, locale_t locale, va_list params)
Writes formatted string to the stream.
Definition stream.hpp:600
size_t write_array(_In_reads_or_z_opt_(num_chars) const wchar_t *wstr, size_t num_chars, charset_id charset)
Writes array of characters to the stream.
Definition stream.hpp:430
state_t state() const
Returns stream state after last operation.
Definition stream.hpp:165
basic & read_str(std::basic_string< _Elem, _Traits, _Ax > &data)
Reads length-prefixed string from the stream.
Definition stream.hpp:474
size_t write_sprintf(_Printf_format_string_params_(2) const wchar_t *format, locale_t locale,...)
Writes formatted string to the stream.
Definition stream.hpp:586
size_t write_vsprintf(_Printf_format_string_params_(2) const wchar_t *format, locale_t locale, va_list params)
Writes formatted string to the stream.
Definition stream.hpp:613
virtual void flush()
Persists volatile element data.
Definition stream.hpp:121
virtual void skip(fsize_t amount)
Skips given amount of bytes of data on the stream.
Definition stream.hpp:137
virtual void close()
Closes the stream.
Definition stream.hpp:129
uint8_t read_byte()
Reads one byte of data.
Definition stream.hpp:205
virtual std::vector< uint8_t > read_remainder(size_t max_length=SIZE_MAX)
Reads and returns remainder of the stream.
Definition stream.hpp:179
size_t write_sprintf(_Printf_format_string_params_(2) const char *format, locale_t locale,...)
Writes formatted string to the stream.
Definition stream.hpp:572
size_t readln_and_attach(std::basic_string< wchar_t, _Traits, _Ax > &wstr, charset_id charset)
Reads stream to the end-of-line or end-of-file and append to str.
Definition stream.hpp:363
size_t readln(std::basic_string< char, _Traits, _Ax > &str)
Reads stream to the end-of-line or end-of-file.
Definition stream.hpp:301
size_t readln_and_attach(std::basic_string< _Elem, _Traits, _Ax > &str)
Reads stream to the end-of-line or end-of-file and append to str.
Definition stream.hpp:342
size_t read_array(_Out_writes_bytes_(size *count) void *array, size_t size, size_t count)
Reads an array of data from the stream.
Definition stream.hpp:378
basic & write_str(const T *data)
Writes string to the stream length-prefixed.
Definition stream.hpp:499
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:91
size_t readln(std::basic_string< wchar_t, _Traits, _Ax > &wstr)
Reads stream to the end-of-line or end-of-file.
Definition stream.hpp:313
void write_charset(charset_id charset)
Writes UTF8 or UTF-16 byte-order-mark.
Definition stream.hpp:559
size_t readln(std::basic_string< wchar_t, _Traits, _Ax > &wstr, charset_id charset)
Reads stream to the end-of-line or end-of-file.
Definition stream.hpp:325
size_t write_array(const wchar_t *wstr, charset_id charset)
Writes array of characters to the stream.
Definition stream.hpp:409
basic & write_data(const T data)
Writes one primitive data type.
Definition stream.hpp:282
fsize_t write_stream(basic &stream, fsize_t amount=fsize_max)
Writes content of another stream.
Definition stream.hpp:534
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:109
size_t write_array(const std::basic_string< wchar_t, _Traits, _Ax > &wstr, charset_id charset)
Writes array of characters to the stream.
Definition stream.hpp:451
size_t write_array(_In_reads_bytes_opt_(size *count) const void *array, size_t size, size_t count)
Writes an array of data to the stream.
Definition stream.hpp:396
void write_byte(uint8_t byte, fsize_t amount=1)
Writes a byte of data.
Definition stream.hpp:216
basic & read_data(T &data)
Reads one primitive data type.
Definition stream.hpp:254
Buffered read/write stream.
Definition stream.hpp:1257
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1367
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:1285
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:1321
Buffered OS data stream (file, pipe, socket...)
Definition stream.hpp:2193
Cached file.
Definition stream.hpp:1684
virtual time_point ctime() const
Returns file creation time.
Definition stream.hpp:1936
fpos_t m_offset
Logical absolute file position.
Definition stream.hpp:2052
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:1915
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:1741
virtual time_point atime() const
Returns file access time.
Definition stream.hpp:1941
virtual fsize_t size()
Returns file size Should the file size cannot be determined, the method returns fsize_max and it does...
Definition stream.hpp:1908
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:1902
virtual time_point mtime() const
Returns file modification time.
Definition stream.hpp:1950
virtual void close()
Closes the stream.
Definition stream.hpp:1856
virtual void set_mtime(time_point date)
Sets file modification time.
Definition stream.hpp:1972
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:1896
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1865
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:1803
virtual void set_ctime(time_point date)
Sets file create time.
Definition stream.hpp:1959
virtual fpos_t tell() const
Returns absolute file position in file or fpos_max if fails. This method does not update stream state...
Definition stream.hpp:1891
virtual void set_atime(time_point date)
Sets file access time.
Definition stream.hpp:1964
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:1876
Cached file-system file.
Definition stream.hpp:2751
void open(const schar_t *filename, int mode)
Opens file.
Definition stream.hpp:2785
cached_file(const schar_t *filename, int mode, size_t cache_size=default_cache_size)
Opens file.
Definition stream.hpp:2767
Modifies data on the fly when reading from/writing to a source stream.
Definition stream.hpp:889
virtual void flush()
Persists volatile element data.
Definition stream.hpp:935
virtual void close()
Closes the stream.
Definition stream.hpp:929
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:913
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:921
Compares multiple files to perform the same.
Definition stream.hpp:3583
virtual fsize_t size()
Returns file size Should the file size cannot be determined, the method returns fsize_max and it does...
Definition stream.hpp:3719
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:3736
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:3614
virtual void close()
Closes the stream.
Definition stream.hpp:3647
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:3693
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:3706
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:3664
virtual fpos_t tell() const
Returns absolute file position in file or fpos_max if fails. This method does not update stream state...
Definition stream.hpp:3681
virtual void flush()
Persists volatile element data.
Definition stream.hpp:3632
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:3591
In-memory FIFO queue.
Definition stream.hpp:3483
virtual void close()
Closes the stream.
Definition stream.hpp:3554
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:3531
size_t size() const
Returns total size of pending data in the queue.
Definition stream.hpp:3568
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:3502
Limits file reading/writing to a predefined window.
Definition stream.hpp:1574
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:1667
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1617
virtual void skip(fsize_t amount)
Skips given amount of bytes of data on the stream.
Definition stream.hpp:1630
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:1623
virtual fsize_t size()
Returns file size Should the file size cannot be determined, the method returns fsize_max and it does...
Definition stream.hpp:1662
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:1597
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:1642
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:1583
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:1652
virtual fpos_t tell() const
Returns absolute file position in file or fpos_max if fails. This method does not update stream state...
Definition stream.hpp:1636
virtual void close()
Closes the stream.
Definition stream.hpp:1611
File-system file.
Definition stream.hpp:2434
virtual time_point mtime() const
Returns file modification time.
Definition stream.hpp:2682
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:2575
file(const schar_t *filename, int mode)
Opens file.
Definition stream.hpp:2444
virtual void set_ctime(time_point date)
Sets file create time.
Definition stream.hpp:2696
virtual time_point atime() const
Returns file access time.
Definition stream.hpp:2668
void open(const schar_t *filename, int mode)
Opens file.
Definition stream.hpp:2455
virtual void set_mtime(time_point date)
Sets file modification time.
Definition stream.hpp:2727
virtual void set_atime(time_point date)
Sets file access time.
Definition stream.hpp:2708
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:2552
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:2618
virtual time_point ctime() const
Returns file creation time.
Definition stream.hpp:2658
virtual fsize_t size()
Returns file size Should the file size cannot be determined, the method returns fsize_max and it does...
Definition stream.hpp:2600
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:2513
virtual fpos_t tell() const
Returns absolute file position in file or fpos_max if fails. This method does not update stream state...
Definition stream.hpp:2534
Limits reading from/writing to stream to a predefined number of bytes.
Definition stream.hpp:1415
fsize_t read_limit
Number of bytes left that may be read from the stream.
Definition stream.hpp:1475
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:1423
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:1448
fsize_t write_limit
Number of bytes left, that can be written to the stream.
Definition stream.hpp:1476
In-memory file.
Definition stream.hpp:2813
memory_file(const schar_t *filename, int mode)
Loads content from file-system file.
Definition stream.hpp:2891
size_t m_size
file size
Definition stream.hpp:3470
void get(fpos_t offset, T &data)
Reads data from specified file location This does not move file pointer. It checks for data size asse...
Definition stream.hpp:3410
size_t write_stream(basic &stream, size_t amount=SIZE_MAX)
Writes content of another stream.
Definition stream.hpp:3235
uint8_t * m_data
file data
Definition stream.hpp:3467
memory_file & read_data(T &data)
Reads one primitive data type.
Definition stream.hpp:3034
virtual void close()
Closes the stream.
Definition stream.hpp:3285
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:2995
virtual fpos_t tell() const
Returns absolute file position in file or fpos_max if fails. This method does not update stream state...
Definition stream.hpp:3316
size_t m_reserved
reserved file size
Definition stream.hpp:3471
memory_file(size_t size, state_t state=state_t::ok)
Creates an empty file of reserved size.
Definition stream.hpp:2834
void reserve(size_t required, bool tight=false) noexcept
Reallocates memory.
Definition stream.hpp:2908
memory_file & read_str(std::basic_string< _Elem, _Traits, _Ax > &data)
Reads length-prefixed string from the stream.
Definition stream.hpp:3074
void write_byte(uint8_t byte, size_t amount=1)
Writes a byte of data.
Definition stream.hpp:3129
void set(fpos_t offset, const T data)
Writes data to specified file location This does not move file pointer nor update file size....
Definition stream.hpp:3376
size_t m_offset
file pointer
Definition stream.hpp:3469
void save(const schar_t *filename, int mode)
Saves content to a file-system file.
Definition stream.hpp:2970
void load(const schar_t *filename, int mode)
Loads content from a file-system file.
Definition stream.hpp:2937
virtual fsize_t size()
Returns file size Should the file size cannot be determined, the method returns fsize_max and it does...
Definition stream.hpp:3321
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:3299
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:3326
memory_file & write_data(const T data)
Writes one primitive data type.
Definition stream.hpp:3162
memory_file & write_str(const T *data)
Writes string to the stream length-prefixed.
Definition stream.hpp:3200
bool m_manage
may reallocate m_data?
Definition stream.hpp:3468
memory_file(void *data, size_t size, bool manage=false, state_t state=state_t::ok)
Creates a file based on available data.
Definition stream.hpp:2881
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:3105
memory_file(void *data, size_t size, size_t reserved, bool manage=false, state_t state=state_t::ok)
Creates a file based on available data.
Definition stream.hpp:2858
const void * data() const
Returns pointer to data.
Definition stream.hpp:2993
Definition stream.hpp:1032
enum stdex::stream::replicator::worker::op_t op
Operation to perform.
size_t num_written
Number of bytes written.
Definition stream.hpp:1080
size_t length
Byte limit of data to write.
Definition stream.hpp:1079
const void * data
Data to write.
Definition stream.hpp:1078
Replicates writing of the same data to multiple streams.
Definition stream.hpp:949
void push_back(basic *source)
Adds stream on the list.
Definition stream.hpp:968
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1025
void remove(basic *source)
Removes stream from the list.
Definition stream.hpp:976
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:993
virtual void close()
Closes the stream.
Definition stream.hpp:1020
Limits reading from/writing to stream to a predefined window.
Definition stream.hpp:1483
fpos_t write_offset
Number of bytes to discard on write.
Definition stream.hpp:1567
virtual size_t write(_In_reads_bytes_opt_(length) const void *data, size_t length)
Writes block of data to the stream.
Definition stream.hpp:1524
virtual size_t read(_Out_writes_bytes_to_opt_(length, return) void *data, size_t length)
Reads block of data from the stream.
Definition stream.hpp:1491
fpos_t read_offset
Number of bytes to skip on read.
Definition stream.hpp:1566
Operating system object (file, pipe, anything with an OS handle etc.)
Definition system.hpp:88
virtual void close()
Closes object.
Definition system.hpp:129
Numerical interval.
Definition interval.hpp:18
bool contains(T x) const
Is value in interval?
Definition interval.hpp:70
bool empty() const
Is interval empty?
Definition interval.hpp:54
T size() const
Returns interval size.
Definition interval.hpp:47
T end
interval end
Definition interval.hpp:20
T start
interval start
Definition interval.hpp:19
Definition stream.hpp:1392
Definition stream.hpp:2030
interval< fpos_t > region
valid data region
Definition stream.hpp:2038
Definition stream.hpp:3572