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' };
80 virtual ~basic()
noexcept(
false) {}
93 virtual _Success_(
return != 0 || length == 0) size_t
read(
94 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
97 _Unreferenced_(length);
98 m_state = state_t::fail;
111 virtual _Success_(
return != 0) size_t
write(
112 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
114 _Unreferenced_(data);
115 _Unreferenced_(length);
116 m_state = state_t::fail;
125 m_state = state_t::ok;
133 m_state = state_t::ok;
139 virtual void skip(_In_ fsize_t amount)
143 else if (amount < iterate_count) {
144 for (
size_t i = 0; i < static_cast<size_t>(amount); i++) {
146 if (!
ok()) _Unlikely_
151 size_t block =
static_cast<size_t>(std::min<fsize_t>(amount, default_block_size));
153 std::unique_ptr<uint8_t[]> dummy(
new uint8_t[block]);
155 amount -=
read_array(dummy.get(),
sizeof(uint8_t),
static_cast<size_t>(std::min<fsize_t>(amount, block)));
156 if (!
ok()) _Unlikely_
160 catch (
const std::bad_alloc&) { m_state = state_t::fail; }
167 inline state_t
state()
const {
return m_state; };
172 inline bool ok()
const {
return m_state == state_t::ok; };
183 std::vector<uint8_t> result;
184 size_t offset, length;
186 length = default_block_size;
187 while (offset < max_length) {
188 length = std::min(length, max_length);
189 try { result.resize(length); }
190 catch (
const std::bad_alloc&) {
191 m_state = state_t::fail;
194 auto num_read =
read_array(result.data() + offset,
sizeof(uint8_t), length - offset);
196 if (!
ok()) _Unlikely_
198 length += default_block_size;
200 result.resize(offset);
212 throw std::runtime_error(
"failed to read");
221 write(&
byte,
sizeof(uint8_t));
222 else if (amount < iterate_count) {
223 for (
size_t i = 0; i < static_cast<size_t>(amount); i++) {
224 write(&
byte,
sizeof(uint8_t));
225 if (!
ok()) _Unlikely_
230 size_t block =
static_cast<size_t>(std::min<fsize_t>(amount, default_block_size));
232 std::unique_ptr<uint8_t[]> dummy(
new uint8_t[block]);
233 memset(dummy.get(),
byte, block);
235 amount -=
write_array(dummy.get(),
sizeof(uint8_t),
static_cast<size_t>(std::min<fsize_t>(amount, block)));
236 if (!
ok()) _Unlikely_
240 catch (
const std::bad_alloc&) { m_state = state_t::fail; }
258 if (!
ok()) _Unlikely_ {
267 m_state = state_t::eof;
286 if (!
ok()) _Unlikely_
288#if BYTE_ORDER == BIG_ENDIAN
289 T data_le = HE2LE(data);
290 write(&data_le,
sizeof(T));
292 write(&data,
sizeof(T));
302 template<
class _Traits = std::
char_traits<
char>,
class _Ax = std::allocator<
char>>
303 inline size_t readln(_Inout_ std::basic_string<char, _Traits, _Ax>& str)
314 template<
class _Traits = std::
char_traits<
wchar_t>,
class _Ax = std::allocator<
wchar_t>>
315 inline size_t readln(_Inout_ std::basic_string<wchar_t, _Traits, _Ax>& wstr)
326 template<
class _Traits = std::
char_traits<
wchar_t>,
class _Ax = std::allocator<
wchar_t>>
327 size_t readln(_Inout_ std::basic_string<wchar_t, _Traits, _Ax>& wstr, _In_ charset_id charset)
329 if (charset == charset_id::utf16)
334 str2wstr(wstr, str, charset);
343 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
347 _Elem chr, previous = (_Elem)0;
350 if (!initial && !(previous ==
static_cast<_Elem
>(
'\r') && chr ==
static_cast<_Elem
>(
'\n')))
355 }
while (
ok() && chr !=
static_cast<_Elem
>(
'\n'));
364 template<
class _Traits = std::
char_traits<
wchar_t>,
class _Ax = std::allocator<
wchar_t>>
365 size_t readln_and_attach(_Inout_ std::basic_string<wchar_t, _Traits, _Ax>& wstr, _In_ charset_id charset)
367 if (charset == charset_id::utf16)
371 str2wstr(wstr, str, charset);
380 size_t read_array(_Out_writes_bytes_(size* count)
void* array, _In_
size_t size, _In_
size_t count)
382 for (
size_t to_read = mul(size, count);;) {
383 size_t num_read =
read(array, to_read);
387 if (!
ok()) _Unlikely_
388 return count - to_read / size;
389 reinterpret_cast<uint8_t*&
>(array) += num_read;
398 inline size_t write_array(_In_reads_bytes_opt_(size* count)
const void* array, _In_
size_t size, _In_
size_t count)
400 return write(array, mul(size, count)) / size;
411 size_t write_array(_In_z_
const wchar_t* wstr, _In_ charset_id charset)
413 if (!
ok()) _Unlikely_
415 size_t num_chars = stdex::strlen(wstr);
416 if (charset != charset_id::utf16) {
417 std::string str(wstr2str(wstr, num_chars, charset));
418 return write_array(str.data(),
sizeof(
char), str.size());
420 return write_array(wstr,
sizeof(
wchar_t), num_chars);
432 size_t write_array(_In_reads_or_z_opt_(num_chars)
const wchar_t* wstr, _In_
size_t num_chars, _In_ charset_id charset)
434 if (!
ok()) _Unlikely_
436 num_chars = stdex::strnlen(wstr, num_chars);
437 if (charset != charset_id::utf16) {
438 std::string str(wstr2str(wstr, num_chars, charset));
439 return write_array(str.data(),
sizeof(
char), str.size());
441 return write_array(wstr,
sizeof(
wchar_t), num_chars);
452 template<
class _Traits = std::
char_traits<
wchar_t>,
class _Ax = std::allocator<
wchar_t>>
453 size_t write_array(_In_
const std::basic_string<wchar_t, _Traits, _Ax>& wstr, _In_ charset_id charset)
455 if (!
ok()) _Unlikely_
457 if (charset != charset_id::utf16) {
458 std::string str(wstr2str(wstr, charset));
459 return write_array(str.data(),
sizeof(
char), str.size());
461 return write_array(wstr.data(),
sizeof(
wchar_t), wstr.size());
475 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
476 inline basic&
read_str(_Inout_ std::basic_string<_Elem, _Traits, _Ax>& data)
480 if (!
ok()) _Unlikely_ {
484 data.resize(num_chars);
485 data.resize(
read_array(data.data(),
sizeof(_Elem), num_chars));
504 size_t num_chars = stdex::strlen(data);
505 if (num_chars > UINT32_MAX)
506 throw std::invalid_argument(
"string too long");
508 if (!
ok()) _Unlikely_
520 size_t write_sa(_In_ LPSAFEARRAY sa)
522 safearray_accessor<void> a(sa);
524 if (FAILED(SafeArrayGetUBound(sa, 1, &ubound)) ||
525 FAILED(SafeArrayGetLBound(sa, 1, &lbound)))
526 throw std::invalid_argument(
"SafeArrayGet[UL]Bound failed");
527 return write(a.data(),
static_cast<size_t>(ubound) - lbound + 1);
538 std::unique_ptr<uint8_t[]> data(
new uint8_t[
static_cast<size_t>(std::min<fsize_t>(amount, default_block_size))]);
539 fsize_t num_copied = 0, to_write = amount;
540 m_state = state_t::ok;
542 size_t num_read = stream.read(data.get(),
static_cast<size_t>(std::min<fsize_t>(default_block_size, to_write)));
543 size_t num_written =
write(data.get(), num_read);
544 num_copied += num_written;
545 to_write -= num_written;
546 if (stream.m_state == state_t::eof) {
548 m_state = state_t::ok;
551 m_state = stream.m_state;
563 if (charset == charset_id::utf16)
565 else if (charset == charset_id::utf8)
574 size_t write_sprintf(_In_z_ _Printf_format_string_params_(2)
const char* format, _In_opt_ locale_t locale, ...)
577 va_start(params, locale);
588 size_t write_sprintf(_In_z_ _Printf_format_string_params_(2)
const wchar_t* format, _In_opt_ locale_t locale, ...)
591 va_start(params, locale);
602 size_t write_vsprintf(_In_z_ _Printf_format_string_params_(2)
const char* format, _In_opt_ locale_t locale, _In_ va_list params)
605 str.reserve(default_block_size);
606 vappendf(str, format, locale, params);
607 return write_array(str.data(),
sizeof(
char), str.size());
615 size_t write_vsprintf(_In_z_ _Printf_format_string_params_(2)
const wchar_t* format, _In_opt_ locale_t locale, _In_ va_list params)
618 str.reserve(default_block_size);
619 vappendf(str, format, locale, params);
620 return write_array(str.data(),
sizeof(
wchar_t), str.size());
623 inline basic& operator >>(_Out_ int8_t& data) {
return read_data(data); }
624 inline basic& operator <<(_In_
const int8_t data) {
return write_data(data); }
625 inline basic& operator >>(_Out_ int16_t& data) {
return read_data(data); }
626 inline basic& operator <<(_In_
const int16_t data) {
return write_data(data); }
627 inline basic& operator >>(_Out_ int32_t& data) {
return read_data(data); }
628 inline basic& operator <<(_In_
const int32_t data) {
return write_data(data); }
629 inline basic& operator >>(_Out_ int64_t& data) {
return read_data(data); }
630 inline basic& operator <<(_In_
const int64_t data) {
return write_data(data); }
631 inline basic& operator >>(_Out_ uint8_t& data) {
return read_data(data); }
632 inline basic& operator <<(_In_
const uint8_t data) {
return write_data(data); }
633 inline basic& operator >>(_Out_ uint16_t& data) {
return read_data(data); }
634 inline basic& operator <<(_In_
const uint16_t data) {
return write_data(data); }
635 inline basic& operator >>(_Out_ uint32_t& data) {
return read_data(data); }
636 inline basic& operator <<(_In_
const uint32_t data) {
return write_data(data); }
637 inline basic& operator >>(_Out_ uint64_t& data) {
return read_data(data); }
638 inline basic& operator <<(_In_
const uint64_t data) {
return write_data(data); }
639 inline basic& operator >>(_Out_
float& data) {
return read_data(data); }
640 inline basic& operator <<(_In_
const float data) {
return write_data(data); }
641 inline basic& operator >>(_Out_
double& data) {
return read_data(data); }
642 inline basic& operator <<(_In_
const double data) {
return write_data(data); }
643 inline basic& operator >>(_Out_
char& data) {
return read_data(data); }
644 inline basic& operator <<(_In_
const char data) {
return write_data(data); }
645#ifdef _NATIVE_WCHAR_T_DEFINED
646 inline basic& operator >>(_Out_
wchar_t& data) {
return read_data(data); }
647 inline basic& operator <<(_In_
const wchar_t data) {
return write_data(data); }
649 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
650 inline basic& operator >>(_Inout_ std::basic_string<_Elem, _Traits, _Ax>& data) {
return read_str(data); }
652 inline basic& operator <<(_In_
const T* data) {
return write_str(data); }
661 using fpos_t = uint64_t;
662 constexpr fpos_t fpos_max = UINT64_MAX;
663 constexpr fpos_t fpos_min = 0;
668 using foff_t = int64_t;
669 constexpr foff_t foff_max = INT64_MAX;
670 constexpr foff_t foff_min = INT64_MIN;
688 using clock = std::chrono::file_clock;
690 using clock = std::chrono::system_clock;
692 using time_point = std::chrono::time_point<clock>;
702 size_t length = std::min<size_t>(max_length,
static_cast<size_t>(
size() -
tell()));
703 std::vector<uint8_t> result;
704 try { result.resize(length); }
705 catch (
const std::bad_alloc&) {
706 m_state = state_t::fail;
709 result.resize(
read_array(result.data(),
sizeof(uint8_t), length));
718 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg) = 0;
725 inline fpos_t
seekbeg(_In_ fpos_t offset) {
return seek(offset, seek_t::beg); }
732 inline fpos_t
seekcur(_In_ foff_t offset) {
return seek(offset, seek_t::cur); }
739 inline fpos_t
seekend(_In_ foff_t offset) {
return seek(offset, seek_t::end); }
741 virtual void skip(_In_ fsize_t amount)
743 seek(amount, seek_t::cur);
752 virtual fpos_t
tell()
const = 0;
757 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
759 _Unreferenced_(offset);
760 _Unreferenced_(length);
761 throw std::domain_error(
"not implemented");
767 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
769 _Unreferenced_(offset);
770 _Unreferenced_(length);
771 throw std::domain_error(
"not implemented");
790 return time_point::min();
798 return time_point::min();
806 return time_point::min();
814 _Unreferenced_(date);
815 throw std::domain_error(
"not implemented");
823 _Unreferenced_(date);
824 throw std::domain_error(
"not implemented");
832 _Unreferenced_(date);
833 throw std::domain_error(
"not implemented");
840 LPSAFEARRAY read_sa()
842 assert(
size() <= SIZE_MAX);
843 size_t length =
static_cast<size_t>(
size());
844 std::unique_ptr<SAFEARRAY, SafeArrayDestroy_delete> sa(SafeArrayCreateVector(VT_UI1, 0, (ULONG)length));
846 throw std::runtime_error(
"SafeArrayCreateVector failed");
847 safearray_accessor<void> a(sa.get());
849 throw std::runtime_error(
"failed to seek");
850 if (
read_array(a.data(), 1, length) != length)
851 throw std::runtime_error(
"failed to read");
861 charset_id
read_charset(_In_ charset_id default_charset = charset_id::system)
864 throw std::runtime_error(
"failed to seek");
867 if (!
ok()) _Unlikely_
868 return default_charset;
869 if (id_utf16 == utf16_bom)
870 return charset_id::utf16;
873 throw std::runtime_error(
"failed to seek");
874 char id_utf8[3] = { 0 };
876 if (!
ok()) _Unlikely_
877 return default_charset;
878 if (strncmp(id_utf8, _countof(id_utf8), utf8_bom, _countof(utf8_bom)) == 0)
879 return charset_id::utf8;
882 throw std::runtime_error(
"failed to seek");
883 return default_charset;
894 basic(state_t::fail),
898 void init(_Inout_
basic& source)
900 m_state = source.state();
911 basic(source.state()),
915 virtual _Success_(
return != 0 || length == 0) size_t
read(
916 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
918 size_t num_read = m_source->
read(data, length);
919 m_state = m_source->
state();
923 virtual _Success_(
return != 0) size_t
write(
924 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
926 size_t num_written = m_source->
write(data, length);
927 m_state = m_source->
state();
934 m_state = m_source->
state();
940 m_state = m_source->
state();
955 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
958 const std::lock_guard<std::mutex> lk(_w->mutex);
959 _w->op = worker::op_t::quit;
963 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w)
964 w->get()->thread.join();
972 m_workers.push_back(std::unique_ptr<worker>(
new worker(source)));
980 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
982 if (_w->source == source) {
984 const std::lock_guard<std::mutex> lk(_w->mutex);
985 _w->op = worker::op_t::quit;
995 virtual _Success_(
return != 0) size_t
write(
996 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
998 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
1001 const std::lock_guard<std::mutex> lk(_w->mutex);
1002 _w->op = worker::op_t::write;
1004 _w->length = length;
1006 _w->cv.notify_one();
1008 size_t num_written = length;
1009 m_state = state_t::ok;
1010 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
1012 std::unique_lock<std::mutex> lk(_w->mutex);
1013 _w->cv.wait(lk, [&] {
return _w->op == worker::op_t::noop; });
1014 if (_w->num_written < num_written)
1015 num_written = _w->num_written;
1016 if (
ok() && !_w->source->ok())
1017 m_state = _w->source->state();
1024 foreach_worker(worker::op_t::close);
1029 foreach_worker(worker::op_t::flush);
1042 thread(process_op, std::ref(*
this))
1046 static void process_op(_Inout_
worker& w)
1049 std::unique_lock<std::mutex> lk(w.mutex);
1050 w.cv.wait(lk, [&] {
return w.op != op_t::noop; });
1055 w.num_written = w.source->write(w.data, w.length);
1084 std::condition_variable cv;
1088 void foreach_worker(_In_ worker::op_t op)
1090 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
1093 const std::lock_guard<std::mutex> lk(_w->mutex);
1096 _w->cv.notify_one();
1098 m_state = state_t::ok;
1099 for (
auto w = m_workers.begin(), w_end = m_workers.end(); w != w_end; ++w) {
1101 std::unique_lock<std::mutex> lk(_w->mutex);
1102 _w->cv.wait(lk, [&] {
return _w->op == worker::op_t::noop; });
1104 m_state = _w->source->state();
1108 std::list<std::unique_ptr<worker>> m_workers;
1111 constexpr size_t default_async_limit = 0x100000;
1118 template <
size_t CAPACITY = default_async_limit>
1124 m_worker(process, std::ref(*
this))
1133#pragma warning(suppress: 6101)
1134 virtual _Success_(
return != 0 || length == 0) size_t
read(
1135 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1137 assert(data || !length);
1138 for (
size_t to_read = length;;) {
1139 uint8_t* ptr;
size_t num_read;
1140 std::tie(ptr, num_read) = m_ring.front();
1141 if (!ptr) _Unlikely_ {
1143 m_state = to_read < length || !length ? state_t::ok : m_source->
state();
1144 return length - to_read;
1146 if (to_read < num_read)
1148 memcpy(data, ptr, num_read);
1149 m_ring.pop(num_read);
1150 to_read -= num_read;
1152 m_state = state_t::ok;
1155 reinterpret_cast<uint8_t*&
>(data) += num_read;
1163 uint8_t* ptr;
size_t num_write;
1164 std::tie(ptr, num_write) = w.m_ring.back();
1165 if (!ptr) _Unlikely_
1167 num_write = w.m_source->read(ptr, num_write);
1168 w.m_ring.push(num_write);
1169 if (!w.m_source->ok()) {
1177 ring<uint8_t, CAPACITY> m_ring;
1178 std::thread m_worker;
1186 template <
size_t CAPACITY = default_async_limit>
1192 m_worker(process, std::ref(*
this))
1201 virtual _Success_(
return != 0) size_t
write(
1202 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1204 assert(data || !length);
1205 for (
size_t to_write = length;;) {
1206 uint8_t* ptr;
size_t num_write;
1207 std::tie(ptr, num_write) = m_ring.back();
1208 if (!ptr) _Unlikely_ {
1209 m_state = state_t::fail;
1210 return length - to_write;
1212 if (to_write < num_write)
1213 num_write = to_write;
1214 memcpy(ptr, data, num_write);
1215 m_ring.push(num_write);
1216 to_write -= num_write;
1218 m_state = state_t::ok;
1221 reinterpret_cast<const uint8_t*&
>(data) += num_write;
1235 uint8_t* ptr;
size_t num_read;
1236 std::tie(ptr, num_read) = w.m_ring.front();
1239 num_read = w.m_source->write(ptr, num_read);
1240 w.m_ring.pop(num_read);
1241 if (!w.m_source->ok()) {
1249 ring<uint8_t, CAPACITY> m_ring;
1250 std::thread m_worker;
1253 constexpr size_t default_buffer_size = 0x400;
1261 explicit buffer(_In_
size_t read_buffer_size = default_buffer_size, _In_
size_t write_buffer_size = default_buffer_size) :
1263 m_read_buffer(read_buffer_size),
1264 m_write_buffer(write_buffer_size)
1275 buffer(_Inout_
basic& source, _In_
size_t read_buffer_size = default_buffer_size, _In_
size_t write_buffer_size = default_buffer_size) :
1277 m_read_buffer(read_buffer_size),
1278 m_write_buffer(write_buffer_size)
1287 virtual _Success_(
return != 0 || length == 0) size_t
read(
1288 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1290 assert(data || !length);
1291 for (
size_t to_read = length;;) {
1292 size_t buffer_size = m_read_buffer.tail - m_read_buffer.head;
1293 if (to_read <= buffer_size) {
1294 memcpy(data, m_read_buffer.data + m_read_buffer.head, to_read);
1295 m_read_buffer.head += to_read;
1296 m_state = state_t::ok;
1300 memcpy(data, m_read_buffer.data + m_read_buffer.head, buffer_size);
1301 reinterpret_cast<uint8_t*&
>(data) += buffer_size;
1302 to_read -= buffer_size;
1304 m_read_buffer.head = 0;
1305 if (to_read > m_read_buffer.capacity) {
1307 m_read_buffer.tail = 0;
1308 to_read -= m_source->
read(data, to_read);
1309 m_state = to_read < length ? state_t::ok : m_source->
state();
1310 return length - to_read;
1312 m_read_buffer.tail = m_source->
read(m_read_buffer.data, m_read_buffer.capacity);
1313 if (m_read_buffer.tail < m_read_buffer.capacity && m_read_buffer.tail < to_read) _Unlikely_ {
1314 memcpy(data, m_read_buffer.data, m_read_buffer.tail);
1315 m_read_buffer.head = m_read_buffer.tail;
1316 to_read -= m_read_buffer.tail;
1317 m_state = to_read < length ? state_t::ok : m_source->
state();
1318 return length - to_read;
1323 virtual _Success_(
return != 0) size_t
write(
1324 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1326 assert(data || !length);
1327 if (!length) _Unlikely_ {
1330 if (!
ok()) _Unlikely_
1332 m_source->
write(
nullptr, 0);
1333 m_state = m_source->
state();
1337 for (
size_t to_write = length;;) {
1338 size_t available_buffer = m_write_buffer.capacity - m_write_buffer.tail;
1339 if (to_write <= available_buffer) {
1340 memcpy(m_write_buffer.data + m_write_buffer.tail, data, to_write);
1341 m_write_buffer.tail += to_write;
1342 m_state = state_t::ok;
1345 if (available_buffer) {
1346 memcpy(m_write_buffer.data + m_write_buffer.tail, data, available_buffer);
1347 reinterpret_cast<const uint8_t*&
>(data) += available_buffer;
1348 to_write -= available_buffer;
1349 m_write_buffer.tail += available_buffer;
1351 size_t buffer_size = m_write_buffer.tail - m_write_buffer.head;
1353 m_write_buffer.head += m_source->
write(m_write_buffer.data + m_write_buffer.head, buffer_size);
1354 m_state = m_source->
state();
1355 if (m_write_buffer.head == m_write_buffer.tail)
1356 m_write_buffer.head = m_write_buffer.tail = 0;
1358 return length - to_write;
1360 if (to_write > m_write_buffer.capacity) {
1362 to_write -= m_source->
write(data, to_write);
1363 m_state = m_source->
state();
1364 return length - to_write;
1379 size_t buffer_size = m_write_buffer.tail - m_write_buffer.head;
1381 m_write_buffer.head += m_source->
write(m_write_buffer.data + m_write_buffer.head, buffer_size);
1382 if (m_write_buffer.head == m_write_buffer.tail) {
1383 m_write_buffer.head = 0;
1384 m_write_buffer.tail = 0;
1387 m_state = m_source->
state();
1391 m_state = state_t::ok;
1396 size_t head, tail, capacity;
1398 buffer_t(_In_
size_t buffer_size) :
1401 capacity(buffer_size),
1402 data(buffer_size ?
new uint8_t[buffer_size] :
nullptr)
1410 } m_read_buffer, m_write_buffer;
1419 limiter(_Inout_
basic& source, _In_ fsize_t _read_limit = 0, _In_ fsize_t _write_limit = 0) :
1425 virtual _Success_(
return != 0 || length == 0) size_t
read(
1426 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1430 num_read = m_source->
read(data, length);
1431 m_state = m_source->
state();
1434 num_read = m_source->
read(data, length);
1435 m_state = m_source->
state();
1440 m_state = state_t::eof;
1443 num_read = m_source->
read(data,
static_cast<size_t>(
read_limit));
1444 m_state = m_source->
state();
1450 virtual _Success_(
return != 0) size_t
write(
1451 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1455 num_written = m_source->
write(data, length);
1456 m_state = m_source->
state();
1459 num_written = m_source->
write(data, length);
1460 m_state = m_source->
state();
1465 m_state = state_t::fail;
1469 m_state = m_source->
state();
1487 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) :
1493 virtual _Success_(
return != 0 || length == 0) size_t
read(
1494 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1498 m_state = m_source->
state();
1499 if (!
ok()) _Unlikely_
1505 num_read = m_source->
read(data, length);
1506 m_state = m_source->
state();
1509 num_read = m_source->
read(data, length);
1510 m_state = m_source->
state();
1515 m_source->
skip(length);
1516 m_state = state_t::eof;
1519 num_read = m_source->
read(data,
static_cast<size_t>(
read_limit));
1520 m_state = m_source->
state();
1526 virtual _Success_(
return != 0) size_t
write(
1527 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1529 size_t num_skipped, num_written;
1532 m_state = state_t::ok;
1536 reinterpret_cast<const uint8_t*&
>(data) +=
static_cast<size_t>(
write_offset);
1544 num_written = m_source->
write(data, length);
1545 m_state = m_source->
state();
1548 num_written = m_source->
write(data, length);
1549 m_state = m_source->
state();
1553 num_skipped += length;
1555 m_state = state_t::ok;
1558 num_skipped += length -
static_cast<size_t>(
write_limit);
1560 m_state = m_source->
state();
1563 return num_skipped + num_written;
1579 basic(source.state()),
1581 m_offset(source.tell()),
1582 m_region(offset, offset + length)
1585 virtual _Success_(
return != 0 || length == 0) size_t
read(
1586 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1588 assert(data || !length);
1590 size_t num_read = m_source.
read(data,
static_cast<size_t>(std::min<fpos_t>(length, m_region.
end - m_offset)));
1591 m_state = m_source.
state();
1592 m_offset += num_read;
1595 m_state = length ? state_t::eof : state_t::ok;
1599 virtual _Success_(
return != 0) size_t
write(
1600 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1602 assert(data || !length);
1604 size_t num_written = m_source.
write(data,
static_cast<size_t>(std::min<fpos_t>(length, m_region.
end - m_offset)));
1605 m_state = m_source.
state();
1606 m_offset += num_written;
1609 m_state = state_t::fail;
1616 m_state = m_source.
state();
1622 m_state = m_source.
state();
1625 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
1627 m_offset = m_source.
seek(offset, how);
1628 m_state = m_source.
state();
1629 return ok() ? m_offset - m_region.
start : fpos_max;
1632 virtual void skip(_In_ fsize_t amount)
1634 m_source.
skip(amount);
1635 m_state = m_source.
state();
1640 fpos_t offset = m_source.
tell();
1641 return m_region.
contains(offset) ? offset - m_region.
start : fpos_max;
1644 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
1647 m_source.
lock(m_region.
start + offset, std::min<fsize_t>(length, m_region.
end - offset));
1648 m_state = m_source.
state();
1651 m_state = state_t::fail;
1654 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
1657 m_source.
unlock(m_region.
start + offset, std::min<fsize_t>(length, m_region.
end - offset));
1658 m_state = m_source.
state();
1661 m_state = state_t::fail;
1666 return m_region.
size();
1671 m_state = state_t::fail;
1680 constexpr size_t default_cache_size = 0x1000;
1688 explicit cache(_In_
size_t cache_size = default_cache_size) :
1689 basic(state_t::fail),
1691 m_cache(cache_size),
1693#if SET_FILE_OP_TIMES
1694 , m_atime(time_point::min()),
1695 m_mtime(time_point::min())
1701 m_state = source.state();
1704#if SET_FILE_OP_TIMES
1705 m_atime = source.atime();
1706 m_mtime = source.mtime();
1714 if (!
ok()) _Unlikely_
1715 throw std::runtime_error(
"cache flush failed");
1722 cache(_Inout_
basic_file& source, _In_
size_t cache_size = default_cache_size) :
1723 basic(source.state()),
1725 m_cache(cache_size),
1727#if SET_FILE_OP_TIMES
1728 , m_atime(source.atime()),
1729 m_mtime(source.mtime())
1733 virtual ~cache()
noexcept(
false)
1737 if (!
ok()) _Unlikely_
1738 throw std::runtime_error(
"cache flush failed");
1743 virtual _Success_(
return != 0 || length == 0) size_t
read(
1744 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
1746 assert(data || !length);
1747#if SET_FILE_OP_TIMES
1748 m_atime = time_point::now();
1750 for (
size_t to_read = length;;) {
1751 if (m_cache.status != cache_t::cache_t::status_t::empty) {
1754 if (to_read <= remaining_cache) {
1755 memcpy(data, m_cache.data +
static_cast<size_t>(
m_offset - m_cache.
region.
start), to_read);
1757 m_state = state_t::ok;
1760 memcpy(data, m_cache.data +
static_cast<size_t>(
m_offset - m_cache.
region.
start), remaining_cache);
1761 reinterpret_cast<uint8_t*&
>(data) += remaining_cache;
1762 to_read -= remaining_cache;
1766 if (!
ok()) _Unlikely_ {
1767 if (to_read < length)
1768 m_state = state_t::ok;
1769 return length - to_read;
1773 fpos_t end_max =
m_offset + to_read;
1774 if (
m_offset / m_cache.capacity < end_max / m_cache.capacity) {
1777 if (!m_source->
ok()) _Unlikely_ {
1778 m_state = to_read < length ? state_t::ok : state_t::fail;
1779 return length - to_read;
1781 size_t num_read = m_source->
read(data, to_read -
static_cast<size_t>(end_max % m_cache.capacity));
1783 to_read -= num_read;
1785 m_state = state_t::ok;
1788 reinterpret_cast<uint8_t*&
>(data) += num_read;
1789 m_state = m_source->
state();
1791 if (to_read < length)
1792 m_state = state_t::ok;
1793 return length - to_read;
1799 m_state = to_read < length ? state_t::ok : state_t::fail;
1800 return length - to_read;
1805 virtual _Success_(
return != 0) size_t
write(
1806 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
1808 assert(data || !length);
1809#if SET_FILE_OP_TIMES
1810 m_atime = m_mtime = time_point::now();
1812 for (
size_t to_write = length;;) {
1813 if (m_cache.status != cache_t::cache_t::status_t::empty) {
1814 fpos_t end_max = m_cache.
region.
start + m_cache.capacity;
1816 size_t remaining_cache =
static_cast<size_t>(end_max -
m_offset);
1817 if (to_write <= remaining_cache) {
1818 memcpy(m_cache.data +
static_cast<size_t>(
m_offset - m_cache.
region.
start), data, to_write);
1820 m_cache.status = cache_t::cache_t::status_t::dirty;
1822 m_state = state_t::ok;
1825 memcpy(m_cache.data +
static_cast<size_t>(
m_offset - m_cache.
region.
start), data, remaining_cache);
1826 reinterpret_cast<const uint8_t*&
>(data) += remaining_cache;
1827 to_write -= remaining_cache;
1829 m_cache.status = cache_t::cache_t::status_t::dirty;
1833 if (!
ok()) _Unlikely_
1834 return length - to_write;
1837 fpos_t end_max =
m_offset + to_write;
1838 if (
m_offset / m_cache.capacity < end_max / m_cache.capacity) {
1841 if (!
ok()) _Unlikely_
1842 return length - to_write;
1843 size_t num_written = m_source->
write(data, to_write -
static_cast<size_t>(end_max % m_cache.capacity));
1845 m_state = m_source->
state();
1846 to_write -= num_written;
1847 if (!to_write || !
ok())
1848 return length - to_write;
1849 reinterpret_cast<const uint8_t*&
>(data) += num_written;
1853 if (!
ok()) _Unlikely_
1854 return length - to_write;
1861 if (!
ok()) _Unlikely_
1862 throw std::runtime_error(
"cache flush failed");
1864 m_state = m_source->
state();
1869#if SET_FILE_OP_TIMES
1870 m_atime = m_mtime = time_point::min();
1873 if (!
ok()) _Unlikely_
1878 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
1880 m_state = state_t::ok;
1889 throw std::invalid_argument(
"unknown seek origin");
1898 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
1900 m_source->
lock(offset, length);
1901 m_state = m_source->
state();
1904 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
1906 m_source->
unlock(offset, length);
1907 m_state = m_source->
state();
1912 return m_cache.status != cache_t::cache_t::status_t::empty ?
1919#if SET_FILE_OP_TIMES
1920 m_atime = m_mtime = time_point::now();
1932 m_cache.status = cache_t::cache_t::status_t::empty;
1935 m_state = m_source->
state();
1940 return m_source->
ctime();
1945#if SET_FILE_OP_TIMES
1946 return std::max(m_atime, m_source->
atime());
1948 return m_source->
atime();
1954#if SET_FILE_OP_TIMES
1955 return std::max(m_mtime, m_source->
mtime());
1957 return m_source->
mtime();
1968#if SET_FILE_OP_TIMES
1976#if SET_FILE_OP_TIMES
1985 if (m_cache.status != cache_t::cache_t::status_t::dirty)
1986 m_state = state_t::ok;
1990 m_cache.status = cache_t::cache_t::status_t::loaded;
1993 m_state = state_t::ok;
1994 m_cache.status = cache_t::cache_t::status_t::loaded;
1998 void invalidate_cache()
2000 if (m_cache.status == cache_t::cache_t::status_t::dirty && !m_cache.
region.
empty()) {
2002 if (!
ok()) _Unlikely_
2005 m_state = state_t::ok;
2006 m_cache.status = cache_t::cache_t::status_t::empty;
2009 void load_cache(_In_ fpos_t start)
2011 assert(m_cache.status != cache_t::cache_t::status_t::dirty);
2012 start -= start % m_cache.capacity;
2014 if (m_source->
ok()) {
2015 m_cache.
region.
end = start + m_source->
read(m_cache.data, m_cache.capacity);
2016 m_cache.status = cache_t::cache_t::status_t::loaded;
2017 m_state = state_t::ok;
2020 m_state = state_t::fail;
2025 assert(m_cache.status == cache_t::cache_t::status_t::dirty);
2027 m_source->
write(m_cache.data,
static_cast<size_t>(m_cache.
region.
size()));
2028 m_state = m_source->
state();
2031 basic_file* m_source;
2035 enum class status_t {
2042 cache_t(_In_
size_t _capacity) :
2043 data(new uint8_t[_capacity]),
2044 capacity(_capacity),
2045 status(status_t::empty),
2055#if SET_FILE_OP_TIMES
2068 basic_sys(_In_opt_ sys_handle h = invalid_handle, _In_ state_t
state = state_t::ok) :
2073 virtual _Success_(
return != 0 || length == 0) size_t
read(
2074 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
2076 assert(data || !length);
2082 block_size = 0x1F80000;
2083#elif defined(_WIN32)
2084 block_size = 0x3f00000;
2086 block_size = SSIZE_MAX;
2088 for (
size_t to_read = length;;) {
2093 __try { succeeded = ReadFile(m_h, data,
static_cast<DWORD
>(std::min<size_t>(to_read, block_size)), &num_read,
nullptr); }
2094 __except (EXCEPTION_EXECUTE_HANDLER) { succeeded = FALSE; SetLastError(ERROR_UNHANDLED_EXCEPTION); num_read = 0; }
2095 if (!succeeded && GetLastError() == ERROR_NO_SYSTEM_RESOURCES && block_size > default_block_size) _Unlikely_ {
2098 block_size = default_block_size;
2101 if (!succeeded) _Unlikely_
2103 ssize_t num_read =
::read(m_h, data,
static_cast<ssize_t
>(std::min<size_t>(to_read, block_size)));
2104 if (num_read < 0) _Unlikely_
2107 m_state = to_read < length ? state_t::ok : state_t::fail;
2108 return length - to_read;
2110 if (!num_read) _Unlikely_ {
2111 m_state = to_read < length || !length ? state_t::ok : state_t::eof;
2112 return length - to_read;
2114 to_read -= num_read;
2116 m_state = state_t::ok;
2119 reinterpret_cast<uint8_t*&
>(data) += num_read;
2123 virtual _Success_(
return != 0) size_t
write(
2124 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
2131 block_size = 0x1F80000;
2132#elif defined(_WIN32)
2133 block_size = 0x3f00000;
2135 block_size = SSIZE_MAX;
2137 for (
size_t to_write = length;;) {
2142 __try { succeeded = WriteFile(m_h, data,
static_cast<DWORD
>(std::min<size_t>(to_write, block_size)), &num_written,
nullptr); }
2143 __except (EXCEPTION_EXECUTE_HANDLER) { succeeded = FALSE; SetLastError(ERROR_UNHANDLED_EXCEPTION); num_written = 0; }
2144 to_write -= num_written;
2146 m_state = state_t::ok;
2149 reinterpret_cast<const uint8_t*&
>(data) += num_written;
2150 if (!succeeded) _Unlikely_ {
2151 m_state = state_t::fail;
2152 return length - to_write;
2155 ssize_t num_written =
::write(m_h, data,
static_cast<ssize_t
>(std::min<size_t>(to_write, block_size)));
2156 if (num_written < 0) _Unlikely_ {
2157 m_state = state_t::fail;
2158 return length - to_write;
2160 to_write -= num_written;
2162 m_state = state_t::ok;
2165 reinterpret_cast<const uint8_t*&
>(data) += num_written;
2174 m_state = state_t::ok;
2177 m_state = state_t::fail;
2184 m_state = FlushFileBuffers(m_h) ? state_t::ok : state_t::fail;
2186 m_state = fsync(m_h) >= 0 ? state_t::ok : state_t::fail;
2197 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) :
2198 buffer(read_buffer_size, write_buffer_size),
2217 class sequential_stream :
public basic
2220 sequential_stream(_In_ ISequentialStream* source) : m_source(source)
2225 virtual ~sequential_stream()
2227 m_source->Release();
2230 virtual _Success_(
return != 0 || length == 0) size_t read(
2231 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
2233 assert(data || !length);
2234 for (
size_t to_read = length;;) {
2237 __try { hr = m_source->Read(data, (ULONG)std::min<size_t>(to_read, ULONG_MAX), &num_read); }
2238 __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; }
2239 if (FAILED(hr)) _Unlikely_ {
2240 m_state = to_read < length ? state_t::ok : state_t::fail;
2241 return length - to_read;
2243 to_read -= num_read;
2244 if (hr == S_FALSE) _Unlikely_ {
2245 m_state = to_read < length || !length ? state_t::ok : state_t::eof;
2246 return length - to_read;
2249 m_state = state_t::ok;
2252 reinterpret_cast<uint8_t*&
>(data) += num_read;
2256 virtual _Success_(
return != 0) size_t write(
2257 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
2259 assert(data || !length);
2260 for (
size_t to_write = length;;) {
2262 ULONG num_written = 0;
2263 __try { hr = m_source->Write(data,
static_cast<ULONG
>(std::min<size_t>(to_write, ULONG_MAX)), &num_written); }
2264 __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; }
2267 if (FAILED(hr)) _Unlikely_ {
2268 m_state = state_t::fail;
2269 return length - to_write;
2271 to_write -= num_written;
2273 m_state = state_t::ok;
2276 reinterpret_cast<const uint8_t*&
>(data) += num_written;
2281 ISequentialStream* m_source;
2287 class asp :
public basic
2290 asp(_In_opt_ IRequest* request, _In_opt_ IResponse* response) :
2292 m_response(response)
2295 m_request->AddRef();
2297 m_response->AddRef();
2303 m_request->Release();
2305 m_response->Release();
2308 virtual _Success_(
return != 0 || length == 0) size_t read(
2309 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
2311 assert(data || !length);
2312 if (!m_request) _Unlikely_ {
2313 m_state = state_t::fail;
2316 for (
size_t to_read = length;;) {
2317 VARIANT var_amount, var_data;
2318 V_VT(&var_amount) = VT_I4;
2319 V_I4(&var_amount) = (LONG)std::min<size_t>(to_read, LONG_MAX);
2320 V_VT(&var_data) = VT_EMPTY;
2321 HRESULT hr = [&]() {
2322 __try {
return m_request->BinaryRead(&var_amount, &var_data); }
2323 __except (EXCEPTION_EXECUTE_HANDLER) {
return E_FAIL; }
2325 if (FAILED(hr)) _Unlikely_ {
2326 m_state = to_read < length ? state_t::ok : state_t::fail;
2327 return length - to_read;
2329 assert(V_VT(&var_amount) == VT_I4);
2330 assert(V_VT(&var_data) == (VT_ARRAY | VT_UI1));
2331 std::unique_ptr<SAFEARRAY, SafeArrayDestroy_delete> sa(V_ARRAY(&var_data));
2332 if (!V_I4(&var_amount)) _Unlikely_ {
2333 m_state = to_read < length || !length ? state_t::ok : state_t::eof;
2334 return length - to_read;
2336 safearray_accessor<uint8_t> a(sa.get());
2337 memcpy(data, a.data(), V_I4(&var_amount));
2338 to_read -= V_I4(&var_amount);
2340 m_state = state_t::ok;
2343 reinterpret_cast<uint8_t*&
>(data) += V_I4(&var_amount);
2347 virtual _Success_(
return != 0) size_t write(
2348 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
2351 m_state = state_t::fail;
2354 for (
size_t to_write = length;;) {
2355 UINT num_written =
static_cast<UINT
>(std::min<size_t>(to_write, UINT_MAX));
2356 std::unique_ptr<OLECHAR, SysFreeString_delete> bstr_data(SysAllocStringByteLen(
reinterpret_cast<LPCSTR
>(data), num_written));
2358 V_VT(&var_data) = VT_BSTR;
2359 V_BSTR(&var_data) = bstr_data.get();
2360 HRESULT hr = [&]() {
2361 __try {
return m_response->BinaryWrite(var_data); }
2362 __except (EXCEPTION_EXECUTE_HANDLER) {
return E_FAIL; }
2364 if (FAILED(hr)) _Unlikely_ {
2365 m_state = state_t::fail;
2366 return length - to_write;
2368 to_write -= num_written;
2370 m_state = state_t::ok;
2373 reinterpret_cast<const uint8_t*&
>(data) += num_written;
2377 virtual void close()
2380 __try { m_response->End(); }
2381 __except (EXCEPTION_EXECUTE_HANDLER) {}
2383 m_state = state_t::ok;
2386 virtual void flush()
2390 __try { hr = m_response->Flush(); }
2391 __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; }
2392 m_state = SUCCEEDED(hr) ? state_t::ok : state_t::fail;
2397 IRequest* m_request;
2398 IResponse* m_response;
2407 mode_for_reading = 1 << 0,
2408 mode_for_writing = 1 << 1,
2409 mode_for_chmod = 1 << 2,
2410 mode_create = 1 << 3,
2411 mode_preserve_existing = mode_create | (1 << 4),
2412 mode_append = 1 << 5,
2414 mode_binary = 1 << 6,
2417 share_reading = 1 << 7,
2418 share_writing = 1 << 8,
2419 share_deleting = 1 << 9,
2420 share_all = share_reading | share_writing | share_deleting,
2422 inherit_handle = 1 << 10,
2424 hint_write_thru = 1 << 11,
2425 hint_no_buffering = 1 << 12,
2426 hint_random_access = 1 << 13,
2427 hint_sequential_access = 1 << 14,
2430#pragma warning(push)
2431#pragma warning(disable: 4250)
2446 file(_In_z_
const schar_t* filename, _In_
int mode)
2448 open(filename, mode);
2457 void open(_In_z_
const schar_t* filename, _In_
int mode)
2459 if (m_h != invalid_handle)
2463 DWORD dwDesiredAccess = 0;
2464 if (mode & mode_for_reading) dwDesiredAccess |= GENERIC_READ;
2465 if (mode & mode_for_writing) dwDesiredAccess |= GENERIC_WRITE;
2466 if (mode & mode_for_chmod) dwDesiredAccess |= FILE_WRITE_ATTRIBUTES;
2468 DWORD dwShareMode = 0;
2469 if (mode & share_reading) dwShareMode |= FILE_SHARE_READ;
2470 if (mode & share_writing) dwShareMode |= FILE_SHARE_WRITE;
2471 if (mode & share_deleting) dwShareMode |= FILE_SHARE_DELETE;
2473 SECURITY_ATTRIBUTES sa = {
sizeof(SECURITY_ATTRIBUTES) };
2474 sa.bInheritHandle = mode & inherit_handle ? true :
false;
2476 DWORD dwCreationDisposition;
2477 switch (mode & mode_preserve_existing) {
2478 case mode_create: dwCreationDisposition = CREATE_ALWAYS;
break;
2479 case mode_preserve_existing: dwCreationDisposition = OPEN_ALWAYS;
break;
2480 case 0: dwCreationDisposition = OPEN_EXISTING;
break;
2481 default:
throw std::invalid_argument(
"invalid mode");
2484 DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
2485 if (mode & hint_write_thru) dwFlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
2486 if (mode & hint_no_buffering) dwFlagsAndAttributes |= FILE_FLAG_NO_BUFFERING;
2487 if (mode & hint_random_access) dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
2488 if (mode & hint_sequential_access) dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
2490 m_h = CreateFile(filename, dwDesiredAccess, dwShareMode, &sa, dwCreationDisposition, dwFlagsAndAttributes,
nullptr);
2493 switch (mode & (mode_for_reading | mode_for_writing)) {
2494 case mode_for_reading: flags |= O_RDONLY;
break;
2495 case mode_for_writing: flags |= O_WRONLY;
break;
2496 case mode_for_reading | mode_for_writing: flags |= O_RDWR;
break;
2498 if (mode & mode_create) flags |= mode & mode_preserve_existing ? O_CREAT : (O_CREAT | O_EXCL);
2499 if (mode & hint_write_thru) flags |= O_DSYNC;
2501 if (mode & hint_no_buffering) flags |= O_RSYNC;
2504 m_h =
::open(filename, flags, DEFFILEMODE);
2506 if (m_h != invalid_handle) {
2507 m_state = state_t::ok;
2508 if (mode & mode_append)
2509 seek(0, seek_t::end);
2512 m_state = state_t::fail;
2515 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
2519 li.QuadPart = offset;
2520 li.LowPart = SetFilePointer(m_h, li.LowPart, &li.HighPart,
static_cast<DWORD
>(how));
2521 if (li.LowPart != 0xFFFFFFFF || GetLastError() == NO_ERROR) {
2522 m_state = state_t::ok;
2526 off64_t result = lseek64(m_h, offset,
static_cast<int>(how));
2528 m_state = state_t::ok;
2532 m_state = state_t::fail;
2538 if (m_h != invalid_handle) {
2542 li.LowPart = SetFilePointer(m_h, 0, &li.HighPart, FILE_CURRENT);
2543 if (li.LowPart != 0xFFFFFFFF || GetLastError() == NO_ERROR)
2546 off64_t result = lseek64(m_h, 0, SEEK_CUR);
2554 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
2557 LARGE_INTEGER liOffset;
2558 LARGE_INTEGER liSize;
2559 liOffset.QuadPart = offset;
2560 liSize.QuadPart = length;
2561 if (LockFile(m_h, liOffset.LowPart, liOffset.HighPart, liSize.LowPart, liSize.HighPart)) {
2562 m_state = state_t::ok;
2566 off64_t orig = lseek64(m_h, 0, SEEK_CUR);
2568 m_state = lseek64(m_h, offset, SEEK_SET) >= 0 && lockf64(m_h, F_LOCK, length) >= 0 ? state_t::ok : state_t::fail;
2569 lseek64(m_h, orig, SEEK_SET);
2570 m_state = state_t::ok;
2574 m_state = state_t::fail;
2577 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
2580 LARGE_INTEGER liOffset;
2581 LARGE_INTEGER liSize;
2582 liOffset.QuadPart = offset;
2583 liSize.QuadPart = length;
2584 if (UnlockFile(m_h, liOffset.LowPart, liOffset.HighPart, liSize.LowPart, liSize.HighPart)) {
2585 m_state = state_t::ok;
2589 off64_t orig = lseek64(m_h, 0, SEEK_CUR);
2591 if (lseek64(m_h, offset, SEEK_SET) >= 0 && lockf64(m_h, F_ULOCK, length) >= 0) {
2592 lseek64(m_h, orig, SEEK_SET);
2593 m_state = state_t::ok;
2596 lseek64(m_h, orig, SEEK_SET);
2599 m_state = state_t::fail;
2606 li.LowPart = GetFileSize(m_h, (LPDWORD)&li.HighPart);
2607 if (li.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR)
2611 off64_t length = -1, orig = lseek64(m_h, 0, SEEK_CUR);
2613 length = lseek64(m_h, 0, SEEK_END);
2614 lseek64(m_h, orig, SEEK_SET);
2623 if (SetEndOfFile(m_h)) {
2624 m_state = state_t::ok;
2628 off64_t length = lseek64(m_h, 0, SEEK_CUR);
2629 if (length >= 0 && ftruncate64(m_h, length) >= 0) {
2630 m_state = state_t::ok;
2634 m_state = state_t::fail;
2638 static inline time_point ft2tp(_In_
const FILETIME& ft)
2641 uint64_t t = (
static_cast<int64_t
>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
2643 uint64_t t = ((
static_cast<int64_t
>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000ll;
2645 return time_point(time_point::duration(t));
2648 static inline void tp2ft(_In_ time_point tp, _Out_ FILETIME& ft)
2651 uint64_t t = tp.time_since_epoch().count();
2653 uint64_t t = tp.time_since_epoch().count() + 116444736000000000ll;
2655 ft.dwHighDateTime =
static_cast<DWORD
>((t >> 32) & 0xffffffff);
2656 ft.dwLowDateTime =
static_cast<DWORD
>(t & 0xffffffff);
2664 if (GetFileTime(m_h, &ft,
nullptr,
nullptr))
2667 return time_point::min();
2674 if (GetFileTime(m_h,
nullptr, &ft,
nullptr))
2678 if (fstat(m_h, &buf) >= 0)
2679 return clock::from_time_t(buf.st_atime);
2681 return time_point::min();
2688 if (GetFileTime(m_h,
nullptr,
nullptr, &ft))
2692 if (fstat(m_h, &buf) >= 0)
2693 return clock::from_time_t(buf.st_mtime);
2695 return time_point::min();
2700 assert(m_h != invalid_handle);
2704 if (SetFileTime(m_h, &ft,
nullptr,
nullptr))
2707 throw std::runtime_error(
"failed to set file ctime");
2712 assert(m_h != invalid_handle);
2716 if (SetFileTime(m_h,
nullptr, &ft,
nullptr))
2719 struct timespec ts[2] = {
2720 { date.time_since_epoch().count(), 0 },
2723 if (futimens(m_h, ts) >= 0)
2726 throw std::runtime_error(
"failed to set file atime");
2734 if (SetFileTime(m_h,
nullptr,
nullptr, &ft))
2737 struct timespec ts[2] = {
2739 { date.time_since_epoch().count(), 0 },
2741 if (futimens(m_h, ts) >= 0)
2744 throw std::runtime_error(
"failed to set file mtime");
2755 cached_file(_In_opt_ sys_handle h = invalid_handle, _In_ state_t
state = state_t::ok, _In_
size_t cache_size = default_cache_size) :
2769 cached_file(_In_z_
const schar_t* filename, _In_
int mode, _In_
size_t cache_size = default_cache_size) :
2771 m_source(filename, mode & mode_for_writing ? mode | mode_for_reading : mode)
2787 void open(_In_z_
const schar_t* filename, _In_
int mode)
2790 if (!
ok()) _Unlikely_{
2791 m_state = state_t::fail;
2794 m_source.
open(filename, mode & mode_for_writing ? mode | mode_for_reading : mode);
2795 if (m_source.
ok()) {
2796#if SET_FILE_OP_TIMES
2797 m_atime = m_source.
atime();
2798 m_mtime = m_source.
mtime();
2801 m_state = state_t::ok;
2804 m_state = state_t::fail;
2825#if SET_FILE_OP_TIMES
2826 m_ctime = m_atime = m_mtime = time_point::now();
2838 m_data(reinterpret_cast<uint8_t*>(malloc(
size))),
2845 throw std::bad_alloc();
2846#if SET_FILE_OP_TIMES
2847 m_ctime = m_atime = m_mtime = time_point::now();
2869 assert(reserved >=
size);
2870#if SET_FILE_OP_TIMES
2871 m_ctime = m_atime = m_mtime = time_point::now();
2895 load(filename, mode);
2910 void reserve(_In_
size_t required, _In_
bool tight =
false) noexcept
2913 m_state = state_t::ok;
2917 m_state = state_t::fail;
2920 size_t reserved = tight ? required : ((required + required / 4 + (default_block_size - 1)) / default_block_size) * default_block_size;
2921 auto data =
reinterpret_cast<uint8_t*
>(realloc(
m_data, reserved));
2922 if (!
data && reserved) _Unlikely_ {
2923 m_state = state_t::fail;
2930 m_state = state_t::ok;
2939 void load(_In_z_
const schar_t* filename, _In_
int mode)
2941 file f(filename, (mode & ~hint_random_access) | mode_for_reading | hint_sequential_access);
2943 m_state = state_t::fail;
2947 if (
size > SIZE_MAX) {
2948 m_state = state_t::fail;
2952 if (!
ok()) _Unlikely_ {
2959#if SET_FILE_OP_TIMES
2960 m_ctime = f.
ctime();
2961 m_atime = f.
atime();
2962 m_mtime = f.
mtime();
2972 void save(_In_z_
const schar_t* filename, _In_
int mode)
2974 file f(filename, (mode & ~hint_random_access) | mode_for_writing | hint_sequential_access);
2976 m_state = state_t::fail;
2981 m_state = state_t::fail;
2985#if SET_FILE_OP_TIMES
2997 virtual _Success_(
return != 0 || length == 0) size_t
read(
2998 _Out_writes_bytes_to_opt_(length, return)
void*
data, _In_
size_t length)
3000 assert(
data || !length);
3001#if SET_FILE_OP_TIMES
3002 m_atime = time_point::now();
3005 if (length <= available) {
3008 m_state = state_t::ok;
3011 if (length && !available) {
3012 m_state = state_t::eof;
3017 m_state = state_t::ok;
3038#if SET_FILE_OP_TIMES
3039 m_atime = time_point::now();
3041 if (CHECK_STREAM_STATE && !
ok()) _Unlikely_ {
3045 size_t end_offset =
m_offset +
sizeof(T);
3046 if (end_offset <=
m_size) {
3049#if !CHECK_STREAM_STATE
3050 m_state = state_t::ok;
3056 m_state = state_t::eof;
3075 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
3078#if SET_FILE_OP_TIMES
3079 m_atime = time_point::now();
3081 if (CHECK_STREAM_STATE && !
ok()) _Unlikely_ {
3085 size_t end_offset =
m_offset +
sizeof(uint32_t);
3086 if (end_offset <=
m_size) {
3087 uint32_t num_chars = LE2HE(*
reinterpret_cast<uint32_t*
>(
m_data +
m_offset));
3089 end_offset = stdex::add(
m_offset, stdex::mul(num_chars,
sizeof(_Elem)));
3091 if (end_offset <=
m_size) {
3092 data.assign(start, start + num_chars);
3094#if !CHECK_STREAM_STATE
3095 m_state = state_t::ok;
3099 if (end_offset <=
m_size)
3103 m_state = state_t::eof;
3107 virtual _Success_(
return != 0) size_t
write(
3108 _In_reads_bytes_opt_(length) const
void*
data, _In_
size_t length)
3110 assert(
data || !length);
3111#if SET_FILE_OP_TIMES
3112 m_atime = m_mtime = time_point::now();
3114 size_t end_offset =
m_offset + length;
3117 if (!
ok()) _Unlikely_
3124 m_state = state_t::ok;
3133#if SET_FILE_OP_TIMES
3134 m_atime = m_mtime = time_point::now();
3136 size_t end_offset =
m_offset + amount;
3139 if (!
ok()) _Unlikely_
3146 m_state = state_t::ok;
3166#if SET_FILE_OP_TIMES
3167 m_atime = m_mtime = time_point::now();
3169 if (CHECK_STREAM_STATE && !
ok()) _Unlikely_
3171 size_t end_offset =
m_offset +
sizeof(T);
3174 if (!
ok()) _Unlikely_
3181#if !CHECK_STREAM_STATE
3182 m_state = state_t::ok;
3204#if SET_FILE_OP_TIMES
3205 m_atime = m_mtime = time_point::now();
3207 if (CHECK_STREAM_STATE && !
ok()) _Unlikely_
3209 size_t num_chars = stdex::strlen(
data);
3210 if (num_chars > UINT32_MAX)
3211 throw std::invalid_argument(
"string too long");
3212 size_t size_chars = num_chars *
sizeof(T);
3213 size_t size =
sizeof(uint32_t) + size_chars;
3217 if (!
ok()) _Unlikely_
3221 *
reinterpret_cast<uint32_t*
>(p) = HE2LE((uint32_t)num_chars);
3222 memcpy(p +
sizeof(uint32_t),
data, size_chars);
3226#if !CHECK_STREAM_STATE
3227 m_state = state_t::ok;
3239#if SET_FILE_OP_TIMES
3240 m_atime = m_mtime = time_point::now();
3243 size_t num_copied = 0, to_write = amount;
3244 m_state = state_t::ok;
3245 if (amount != SIZE_MAX) {
3246 dst_size = stdex::add(dst_size, amount);
3248 if (!
ok()) _Unlikely_
3251 num_read = stream.read(
m_data + dst_offset, to_write);
3252 dst_size = dst_offset += num_read;
3253 num_copied += num_read;
3254 to_write -= num_read;
3256 if (stream.state() != state_t::eof)
3257 m_state = state_t::fail;
3265 block_size = std::min(to_write, default_block_size);
3266 dst_size = stdex::add(dst_size, block_size);
3268 if (!
ok()) _Unlikely_
3270 num_read = stream.read(
m_data + dst_offset, block_size);
3271 dst_size = dst_offset += num_read;
3272 num_copied += num_read;
3273 to_write -= num_read;
3275 if (stream.state() != state_t::eof)
3276 m_state = state_t::fail;
3295#if SET_FILE_OP_TIMES
3296 m_ctime = m_atime = m_mtime = time_point::min();
3298 m_state = state_t::ok;
3301 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
3305 case seek_t::beg: target = offset;
break;
3306 case seek_t::cur: target =
static_cast<fpos_t
>(
m_offset) + offset;
break;
3307 case seek_t::end: target =
static_cast<fpos_t
>(
m_size) + offset;
break;
3308 default:
throw std::invalid_argument(
"unknown seek origin");
3310 if (target <= SIZE_MAX) {
3311 m_state = state_t::ok;
3312 return m_offset =
static_cast<size_t>(target);
3314 m_state = state_t::fail;
3330#if SET_FILE_OP_TIMES
3331 m_atime = m_mtime = time_point::now();
3337#if SET_FILE_OP_TIMES
3338 virtual time_point
ctime()
const
3343 virtual time_point
atime()
const
3348 virtual time_point
mtime()
const
3378 inline void set(_In_ fpos_t offset, _In_
const T
data)
3380#if SET_FILE_OP_TIMES
3381 m_atime = m_mtime = time_point::now();
3383 assert(offset +
sizeof(T) <
m_size);
3384 (*
reinterpret_cast<T*
>(
m_data + offset)) = HE2LE(
data);
3388 inline void set(_In_ fpos_t offset, _In_
const int8_t
data) { set<int8_t>(offset,
data); }
3389 inline void set(_In_ fpos_t offset, _In_
const int16_t
data) { set<int16_t>(offset,
data); }
3390 inline void set(_In_ fpos_t offset, _In_
const int32_t
data) { set<int32_t>(offset,
data); }
3391 inline void set(_In_ fpos_t offset, _In_
const int64_t
data) { set<int64_t>(offset,
data); }
3392 inline void set(_In_ fpos_t offset, _In_
const uint8_t
data) { set<uint8_t>(offset,
data); }
3393 inline void set(_In_ fpos_t offset, _In_
const uint16_t
data) { set<uint16_t>(offset,
data); }
3394 inline void set(_In_ fpos_t offset, _In_
const uint32_t
data) { set<uint32_t>(offset,
data); }
3395 inline void set(_In_ fpos_t offset, _In_
const uint64_t
data) { set<uint64_t>(offset,
data); }
3396 inline void set(_In_ fpos_t offset, _In_
const float data) { set<float>(offset,
data); }
3397 inline void set(_In_ fpos_t offset, _In_
const double data) { set<double>(offset,
data); }
3398 inline void set(_In_ fpos_t offset, _In_
const char data) { set<char>(offset,
data); }
3399#ifdef _NATIVE_WCHAR_T_DEFINED
3400 inline void set(_In_ fpos_t offset, _In_
const wchar_t data) { set<wchar_t>(offset,
data); }
3412 inline void get(_In_ fpos_t offset, _Out_ T &
data)
3414 assert(offset +
sizeof(T) <
m_size);
3416#if SET_FILE_OP_TIMES
3417 m_atime = time_point::now();
3422 inline void get(_In_ fpos_t offset, _Out_ int8_t &
data) { get<int8_t>(offset,
data); }
3423 inline void get(_In_ fpos_t offset, _Out_ int16_t &
data) { get<int16_t>(offset,
data); }
3424 inline void get(_In_ fpos_t offset, _Out_ int32_t &
data) { get<int32_t>(offset,
data); }
3425 inline void get(_In_ fpos_t offset, _Out_ int64_t &
data) { get<int64_t>(offset,
data); }
3426 inline void get(_In_ fpos_t offset, _Out_ uint8_t &
data) { get<uint8_t>(offset,
data); }
3427 inline void get(_In_ fpos_t offset, _Out_ uint16_t &
data) { get<uint16_t>(offset,
data); }
3428 inline void get(_In_ fpos_t offset, _Out_ uint32_t &
data) { get<uint32_t>(offset,
data); }
3429 inline void get(_In_ fpos_t offset, _Out_ uint64_t &
data) { get<uint64_t>(offset,
data); }
3430 inline void get(_In_ fpos_t offset, _Out_
float&
data) { get<float>(offset,
data); }
3431 inline void get(_In_ fpos_t offset, _Out_
double&
data) { get<double>(offset,
data); }
3432 inline void get(_In_ fpos_t offset, _Out_
char&
data) { get<char>(offset,
data); }
3433#ifdef _NATIVE_WCHAR_T_DEFINED
3434 inline void get(_In_ fpos_t offset, _Out_
wchar_t&
data) { get<wchar_t>(offset,
data); }
3438 inline memory_file& operator >>(_Out_ int8_t &
data) {
return read_data(
data); }
3439 inline memory_file& operator <<(_In_
const int16_t
data) {
return write_data(
data); }
3440 inline memory_file& operator >>(_Out_ int16_t &
data) {
return read_data(
data); }
3441 inline memory_file& operator <<(_In_
const int32_t
data) {
return write_data(
data); }
3442 inline memory_file& operator >>(_Out_ int32_t &
data) {
return read_data(
data); }
3443 inline memory_file& operator <<(_In_
const int64_t
data) {
return write_data(
data); }
3444 inline memory_file& operator >>(_Out_ int64_t &
data) {
return read_data(
data); }
3445 inline memory_file& operator <<(_In_
const uint8_t
data) {
return write_data(
data); }
3446 inline memory_file& operator >>(_Out_ uint8_t &
data) {
return read_data(
data); }
3447 inline memory_file& operator <<(_In_
const uint16_t
data) {
return write_data(
data); }
3448 inline memory_file& operator >>(_Out_ uint16_t &
data) {
return read_data(
data); }
3449 inline memory_file& operator <<(_In_
const uint32_t
data) {
return write_data(
data); }
3450 inline memory_file& operator >>(_Out_ uint32_t &
data) {
return read_data(
data); }
3451 inline memory_file& operator <<(_In_
const uint64_t
data) {
return write_data(
data); }
3452 inline memory_file& operator >>(_Out_ uint64_t &
data) {
return read_data(
data); }
3459#ifdef _NATIVE_WCHAR_T_DEFINED
3460 inline memory_file& operator <<(_In_
const wchar_t data) {
return write_data(
data); }
3461 inline memory_file& operator >>(_Out_
wchar_t&
data) {
return read_data(
data); }
3464 inline memory_file& operator <<(_In_
const T *
data) {
return write_str(
data); }
3465 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
3466 inline memory_file& operator >>(_Inout_ std::basic_string<_Elem, _Traits, _Ax>&
data) {
return read_str(
data); }
3474#if SET_FILE_OP_TIMES
3503#pragma warning(suppress: 6101)
3504 virtual _Success_(
return != 0 || length == 0) size_t
read(
3505 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
3507 assert(data || !length);
3508 for (
size_t to_read = length;;) {
3509 if (!m_head) _Unlikely_ {
3511 m_state = to_read < length || !length ? state_t::ok : state_t::eof;
3512 return length - to_read;
3514 size_t remaining = m_head->size - m_offset;
3515 if (remaining > to_read) {
3516 memcpy(data, m_head->data + m_offset, to_read);
3517 m_offset += to_read;
3519 m_state = state_t::ok;
3522 memcpy(data, m_head->data + m_offset, remaining);
3524 m_size -= remaining;
3525 reinterpret_cast<uint8_t*&
>(data) += remaining;
3526 to_read -= remaining;
3533 virtual _Success_(
return != 0) size_t
write(
3534 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
3536 assert(data || !length);
3538 std::unique_ptr<node_t> n(
reinterpret_cast<node_t*
>(
new uint8_t[
sizeof(
node_t) + length]));
3541 memcpy(n->data, data, length);
3544 m_tail = m_tail->next = n.release();
3546 m_head = m_tail = n.release();
3547 m_state = state_t::ok;
3550 catch (
const std::bad_alloc&) {
3551 m_state = state_t::fail;
3558 m_size = m_offset = 0;
3564 m_state = state_t::ok;
3570 inline size_t size()
const {
return m_size; };
3573 size_t m_offset, m_size;
3577#pragma warning(suppress:4200)
3579 } *m_head, * m_tail;
3588 basic(num_files ? files[0]->
state() : state_t::fail),
3589 m_files(files, files + num_files)
3593 virtual _Success_(
return != 0 || length == 0) size_t
read(
3594 _Out_writes_bytes_to_opt_(length, return)
void* data, _In_
size_t length)
3596 assert(data || !length);
3597 if (m_files.empty()) {
3598 m_state = state_t::fail;
3601 size_t result = m_files[0]->read(data, length);
3602 _Analysis_assume_(result <= length);
3603 m_state = m_files[0]->state();
3604 if (length > m_tmp.size())
3605 m_tmp.resize(length);
3606 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3607 if (m_files[i]->
read(m_tmp.data(), length) != result ||
3608 memcmp(m_tmp.data(), data, result))
3609 throw std::runtime_error(
"read mismatch");
3610 if (m_files[i]->
state() != m_state)
3611 throw std::runtime_error(
"state mismatch");
3616 virtual _Success_(
return != 0) size_t
write(
3617 _In_reads_bytes_opt_(length) const
void* data, _In_
size_t length)
3619 if (m_files.empty()) {
3620 m_state = state_t::fail;
3623 size_t result = m_files[0]->write(data, length);
3624 m_state = m_files[0]->state();
3625 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3626 if (m_files[i]->
write(data, length) != result)
3627 throw std::runtime_error(
"write mismatch");
3628 if (m_files[i]->
state() != m_state)
3629 throw std::runtime_error(
"state mismatch");
3636 if (m_files.empty()) {
3637 m_state = state_t::ok;
3640 m_files[0]->flush();
3641 m_state = m_files[0]->state();
3642 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3643 m_files[i]->flush();
3644 if (m_files[i]->
state() != m_state)
3645 throw std::runtime_error(
"state mismatch");
3651 if (m_files.empty()) {
3652 m_state = state_t::ok;
3655 m_files[0]->close();
3656 m_state = m_files[0]->state();
3657 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3658 m_files[i]->close();
3659 if (m_files[i]->
state() != m_state)
3660 throw std::runtime_error(
"state mismatch");
3663 m_tmp.shrink_to_fit();
3666 virtual fpos_t
seek(_In_ foff_t offset, _In_ seek_t how = seek_t::beg)
3668 if (m_files.empty()) {
3669 m_state = state_t::fail;
3672 fpos_t result = m_files[0]->seek(offset, how);
3673 m_state = m_files[0]->state();
3674 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3675 if (m_files[i]->
seek(offset, how) != result)
3676 throw std::runtime_error(
"seek mismatch");
3677 if (m_files[i]->
state() != m_state)
3678 throw std::runtime_error(
"state mismatch");
3685 if (m_files.empty())
3687 fpos_t result = m_files[0]->tell();
3688 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3689 if (m_files[i]->
tell() != result)
3690 throw std::runtime_error(
"tell mismatch");
3695 virtual void lock(_In_ fpos_t offset, _In_ fsize_t length)
3697 if (m_files.empty())
3698 m_state = state_t::fail;
3699 m_files[0]->lock(offset, length);
3700 m_state = m_files[0]->state();
3701 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3702 m_files[i]->lock(offset, length);
3703 if (m_files[i]->
state() != m_state)
3704 throw std::runtime_error(
"state mismatch");
3708 virtual void unlock(_In_ fpos_t offset, _In_ fsize_t length)
3710 if (m_files.empty())
3711 m_state = state_t::fail;
3712 m_files[0]->unlock(offset, length);
3713 m_state = m_files[0]->state();
3714 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3715 m_files[i]->unlock(offset, length);
3716 if (m_files[i]->
state() != m_state)
3717 throw std::runtime_error(
"state mismatch");
3723 if (m_files.empty()) {
3724 m_state = state_t::fail;
3727 fsize_t result = m_files[0]->size();
3728 m_state = m_files[0]->state();
3729 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3730 if (m_files[i]->
size() != result)
3731 throw std::runtime_error(
"size mismatch");
3732 if (m_files[i]->
state() != m_state)
3733 throw std::runtime_error(
"state mismatch");
3740 if (m_files.empty())
3741 m_state = state_t::fail;
3742 m_files[0]->truncate();
3743 m_state = m_files[0]->state();
3744 for (
size_t i = 1, n = m_files.size(); i < n; ++i) {
3745 m_files[i]->truncate();
3746 if (m_files[i]->
state() != m_state)
3747 throw std::runtime_error(
"state mismatch");
3752 std::vector<basic_file*> m_files;
3753 std::vector<uint8_t> m_tmp;
Provides read-ahead stream capability.
Definition stream.hpp:1120
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:1134
Provides write-back stream capability.
Definition stream.hpp:1188
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1225
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:1201
Basic seekable stream operations.
Definition stream.hpp:698
virtual void skip(fsize_t amount)
Skips given amount of bytes of data on the stream.
Definition stream.hpp:741
virtual time_point ctime() const
Returns file creation time.
Definition stream.hpp:788
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:757
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:861
fpos_t seekbeg(fpos_t offset)
Seeks to absolute file position.
Definition stream.hpp:725
virtual std::vector< uint8_t > read_remainder(size_t max_length=SIZE_MAX)
Reads and returns remainder of the stream.
Definition stream.hpp:700
virtual void set_mtime(time_point date)
Sets file modification time.
Definition stream.hpp:830
fpos_t seekcur(foff_t offset)
Seeks to relative from current file position.
Definition stream.hpp:732
virtual time_point atime() const
Returns file access time.
Definition stream.hpp:796
virtual void set_ctime(time_point date)
Sets file create time.
Definition stream.hpp:812
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:767
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:804
fpos_t seekend(foff_t offset)
Seeks to relative from end file position.
Definition stream.hpp:739
virtual void set_atime(time_point date)
Sets file access time.
Definition stream.hpp:821
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:2066
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:2123
virtual void flush()
Persists volatile element data.
Definition stream.hpp:2181
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:2073
virtual void close()
Closes the stream.
Definition stream.hpp:2170
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:172
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:602
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:432
state_t state() const
Returns stream state after last operation.
Definition stream.hpp:167
basic & read_str(std::basic_string< _Elem, _Traits, _Ax > &data)
Reads length-prefixed string from the stream.
Definition stream.hpp:476
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:588
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:615
virtual void flush()
Persists volatile element data.
Definition stream.hpp:123
virtual void skip(fsize_t amount)
Skips given amount of bytes of data on the stream.
Definition stream.hpp:139
virtual void close()
Closes the stream.
Definition stream.hpp:131
uint8_t read_byte()
Reads one byte of data.
Definition stream.hpp:207
virtual std::vector< uint8_t > read_remainder(size_t max_length=SIZE_MAX)
Reads and returns remainder of the stream.
Definition stream.hpp:181
size_t write_sprintf(_Printf_format_string_params_(2) const char *format, locale_t locale,...)
Writes formatted string to the stream.
Definition stream.hpp:574
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:365
size_t readln(std::basic_string< char, _Traits, _Ax > &str)
Reads stream to the end-of-line or end-of-file.
Definition stream.hpp:303
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:344
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:380
basic & write_str(const T *data)
Writes string to the stream length-prefixed.
Definition stream.hpp:501
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:93
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:315
void write_charset(charset_id charset)
Writes UTF8 or UTF-16 byte-order-mark.
Definition stream.hpp:561
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:327
size_t write_array(const wchar_t *wstr, charset_id charset)
Writes array of characters to the stream.
Definition stream.hpp:411
basic & write_data(const T data)
Writes one primitive data type.
Definition stream.hpp:284
fsize_t write_stream(basic &stream, fsize_t amount=fsize_max)
Writes content of another stream.
Definition stream.hpp:536
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:111
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:453
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:398
void write_byte(uint8_t byte, fsize_t amount=1)
Writes a byte of data.
Definition stream.hpp:218
basic & read_data(T &data)
Reads one primitive data type.
Definition stream.hpp:256
Buffered read/write stream.
Definition stream.hpp:1259
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1369
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:1287
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:1323
Buffered OS data stream (file, pipe, socket...)
Definition stream.hpp:2195
Cached file.
Definition stream.hpp:1686
virtual time_point ctime() const
Returns file creation time.
Definition stream.hpp:1938
fpos_t m_offset
Logical absolute file position.
Definition stream.hpp:2054
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:1917
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:1743
virtual time_point atime() const
Returns file access time.
Definition stream.hpp:1943
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:1910
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:1904
virtual time_point mtime() const
Returns file modification time.
Definition stream.hpp:1952
virtual void close()
Closes the stream.
Definition stream.hpp:1858
virtual void set_mtime(time_point date)
Sets file modification time.
Definition stream.hpp:1974
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:1898
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1867
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:1805
virtual void set_ctime(time_point date)
Sets file create time.
Definition stream.hpp:1961
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:1893
virtual void set_atime(time_point date)
Sets file access time.
Definition stream.hpp:1966
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:1878
Cached file-system file.
Definition stream.hpp:2753
void open(const schar_t *filename, int mode)
Opens file.
Definition stream.hpp:2787
cached_file(const schar_t *filename, int mode, size_t cache_size=default_cache_size)
Opens file.
Definition stream.hpp:2769
Modifies data on the fly when reading from/writing to a source stream.
Definition stream.hpp:891
virtual void flush()
Persists volatile element data.
Definition stream.hpp:937
virtual void close()
Closes the stream.
Definition stream.hpp:931
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:915
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:923
Compares multiple files to perform the same.
Definition stream.hpp:3585
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:3721
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:3738
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:3616
virtual void close()
Closes the stream.
Definition stream.hpp:3649
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:3695
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:3708
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:3666
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:3683
virtual void flush()
Persists volatile element data.
Definition stream.hpp:3634
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:3593
In-memory FIFO queue.
Definition stream.hpp:3485
virtual void close()
Closes the stream.
Definition stream.hpp:3556
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:3533
size_t size() const
Returns total size of pending data in the queue.
Definition stream.hpp:3570
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:3504
Limits file reading/writing to a predefined window.
Definition stream.hpp:1576
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:1669
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1619
virtual void skip(fsize_t amount)
Skips given amount of bytes of data on the stream.
Definition stream.hpp:1632
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:1625
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:1664
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:1599
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:1644
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:1585
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:1654
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:1638
virtual void close()
Closes the stream.
Definition stream.hpp:1613
File-system file.
Definition stream.hpp:2436
virtual time_point mtime() const
Returns file modification time.
Definition stream.hpp:2684
virtual void unlock(fpos_t offset, fsize_t length)
Unlocks file section for exclusive access.
Definition stream.hpp:2577
file(const schar_t *filename, int mode)
Opens file.
Definition stream.hpp:2446
virtual void set_ctime(time_point date)
Sets file create time.
Definition stream.hpp:2698
virtual time_point atime() const
Returns file access time.
Definition stream.hpp:2670
void open(const schar_t *filename, int mode)
Opens file.
Definition stream.hpp:2457
virtual void set_mtime(time_point date)
Sets file modification time.
Definition stream.hpp:2729
virtual void set_atime(time_point date)
Sets file access time.
Definition stream.hpp:2710
virtual void lock(fpos_t offset, fsize_t length)
Locks file section for exclusive access.
Definition stream.hpp:2554
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:2620
virtual time_point ctime() const
Returns file creation time.
Definition stream.hpp:2660
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:2602
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:2515
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:2536
Limits reading from/writing to stream to a predefined number of bytes.
Definition stream.hpp:1417
fsize_t read_limit
Number of bytes left that may be read from the stream.
Definition stream.hpp:1477
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:1425
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:1450
fsize_t write_limit
Number of bytes left, that can be written to the stream.
Definition stream.hpp:1478
In-memory file.
Definition stream.hpp:2815
memory_file(const schar_t *filename, int mode)
Loads content from file-system file.
Definition stream.hpp:2893
size_t m_size
file size
Definition stream.hpp:3472
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:3412
size_t write_stream(basic &stream, size_t amount=SIZE_MAX)
Writes content of another stream.
Definition stream.hpp:3237
uint8_t * m_data
file data
Definition stream.hpp:3469
memory_file & read_data(T &data)
Reads one primitive data type.
Definition stream.hpp:3036
virtual void close()
Closes the stream.
Definition stream.hpp:3287
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:2997
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:3318
size_t m_reserved
reserved file size
Definition stream.hpp:3473
memory_file(size_t size, state_t state=state_t::ok)
Creates an empty file of reserved size.
Definition stream.hpp:2836
void reserve(size_t required, bool tight=false) noexcept
Reallocates memory.
Definition stream.hpp:2910
memory_file & read_str(std::basic_string< _Elem, _Traits, _Ax > &data)
Reads length-prefixed string from the stream.
Definition stream.hpp:3076
void write_byte(uint8_t byte, size_t amount=1)
Writes a byte of data.
Definition stream.hpp:3131
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:3378
size_t m_offset
file pointer
Definition stream.hpp:3471
void save(const schar_t *filename, int mode)
Saves content to a file-system file.
Definition stream.hpp:2972
void load(const schar_t *filename, int mode)
Loads content from a file-system file.
Definition stream.hpp:2939
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:3323
virtual fpos_t seek(foff_t offset, seek_t how=seek_t::beg)
Seeks to specified relative file position.
Definition stream.hpp:3301
virtual void truncate()
Sets file size - truncates the remainder of file content from the current file position to the end of...
Definition stream.hpp:3328
memory_file & write_data(const T data)
Writes one primitive data type.
Definition stream.hpp:3164
memory_file & write_str(const T *data)
Writes string to the stream length-prefixed.
Definition stream.hpp:3202
bool m_manage
may reallocate m_data?
Definition stream.hpp:3470
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:2883
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:3107
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:2860
const void * data() const
Returns pointer to data.
Definition stream.hpp:2995
Definition stream.hpp:1034
enum stdex::stream::replicator::worker::op_t op
Operation to perform.
size_t num_written
Number of bytes written.
Definition stream.hpp:1082
size_t length
Byte limit of data to write.
Definition stream.hpp:1081
const void * data
Data to write.
Definition stream.hpp:1080
Replicates writing of the same data to multiple streams.
Definition stream.hpp:951
void push_back(basic *source)
Adds stream on the list.
Definition stream.hpp:970
virtual void flush()
Persists volatile element data.
Definition stream.hpp:1027
void remove(basic *source)
Removes stream from the list.
Definition stream.hpp:978
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:995
virtual void close()
Closes the stream.
Definition stream.hpp:1022
Limits reading from/writing to stream to a predefined window.
Definition stream.hpp:1485
fpos_t write_offset
Number of bytes to discard on write.
Definition stream.hpp:1569
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:1526
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:1493
fpos_t read_offset
Number of bytes to skip on read.
Definition stream.hpp:1568
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:1394
Definition stream.hpp:2032
interval< fpos_t > region
valid data region
Definition stream.hpp:2040
Definition stream.hpp:3574