1 /***
2 * ==++==
3 *
4 * Copyright (c) Microsoft Corporation. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * ==--==
17 * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
18 *
19 * Asynchronous I/O: streams API, used for formatted input and output, based on unformatted I/O using stream buffers
20 *
21 * For the latest on this and related APIs, please see http://casablanca.codeplex.com.
22 *
23 * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
24 ****/
25 #pragma once
26
27 #ifndef _CASA_STREAMS_H
28 #define _CASA_STREAMS_H
29
30 #include "cpprest/astreambuf.h"
31 #include <iosfwd>
32
34 {
35 template<typename CharType> class basic_ostream;
36 template<typename CharType> class basic_istream;
37
38 namespace details {
39 template<typename CharType>
41 {
42 public:
44
46
47 private:
49
50 concurrency::streams::streambuf<CharType> m_buffer;
51 };
52
53 template<typename CharType>
55 {
56 public:
58
60
61 private:
63
64 concurrency::streams::streambuf<CharType> m_buffer;
65 };
66
67 template <typename CharType>
69 {
70 template <typename T>
71 static std::basic_string<CharType> format(const T &val)
72 {
73 std::basic_ostringstream<CharType> ss;
74 ss << val;
75 return ss.str();
76 }
77 };
78
79 template <>
81 {
82 template <typename T>
83 static std::basic_string<uint8_t> format(const T &val)
84 {
85 std::basic_ostringstream<char> ss;
86 ss << val;
87 return reinterpret_cast<const uint8_t *>(ss.str().c_str());
88 }
89
90 static std::basic_string<uint8_t> format(const utf16string &val)
91 {
93 }
94
95 };
96
97 static const char *_in_stream_msg = "stream not set up for input of data";
98 static const char *_in_streambuf_msg = "stream buffer not set up for input of data";
99 static const char *_out_stream_msg = "stream not set up for output of data";
100 static const char *_out_streambuf_msg = "stream buffer not set up for output of data";
101 }
102
106 template<typename CharType>
108 {
109 public:
110
112 typedef typename traits::int_type int_type;
113 typedef typename traits::pos_type pos_type;
114 typedef typename traits::off_type off_type;
115
120
126
133
139 m_helper(std::make_shared<details::basic_ostream_helper<CharType>>(buffer))
140 {
141 _verify_and_throw(details::_out_streambuf_msg);
142 }
143
148 {
150 helper()->m_buffer.close(std::ios_base::out) :
151 pplx::task_from_result();
152 }
153
159 {
161 helper()->m_buffer.close(std::ios_base::out, eptr) :
162 pplx::task_from_result();
163 }
164
170 {
172 if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
173 return helper()->m_buffer.putc(ch);
174 }
175
188 template<typename T>
189 CASABLANCA_DEPRECATED("Unsafe API that will be removed in future releases, use one of the other write overloads instead.")
191 {
192 static_assert(sizeof(CharType) == 1, "binary write is only supported for single-byte streams");
193 static_assert(std::is_trivial<T>::value, "unsafe to use with non-trivial types");
194
196 if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
197
198 auto copy = std::make_shared<T>(std::move(value));
199 return helper()->m_buffer.putn_nocopy((CharType*)copy.get(),
sizeof(T)).then([copy](
pplx::task<size_t> op) ->
size_t {
return op.
get(); });
200 }
201
208 {
210 if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
212 return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("source buffer not set up for input of data")));
213
214 if (count == 0)
215 return pplx::task_from_result((size_t)0);
216
217 auto buffer = helper()->m_buffer;
218 auto data = buffer.alloc(count);
219
220 if ( data != nullptr )
221 {
222 auto post_read =
224 {
225 auto b = buffer;
226 b.commit(op.get());
227 return op;
228 };
229 return source.
getn(data, count).then(post_read);
230 }
231 else
232 {
233 size_t available = 0;
234
235 const bool acquired = source.
acquire(data, available);
236 if (available >= count)
237 {
238 auto post_write =
240 {
241 auto s = source;
243 return op;
244 };
245 return buffer.putn_nocopy(data, count).then(post_write);
246 }
247 else
248 {
249 // Always have to release if acquire returned true.
250 if(acquired)
251 {
253 }
254
255 std::shared_ptr<CharType> buf(new CharType[count], [](CharType *buf) { delete [] buf; });
256
257 auto post_write =
259 {
260 return op;
261 };
262 auto post_read =
264 {
265 auto b = buffer;
266 return b.putn_nocopy(buf.get(), op.get()).then(post_write);
267 };
268
269 return source.
getn(buf.get(), count).then(post_read);
270 }
271 }
272 }
273
279 {
281 if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
282
283 if (str.empty())
284 {
285 return pplx::task_from_result<size_t>(0);
286 }
287 else
288 {
289 auto sharedStr = std::make_shared<std::basic_string<CharType>>(str);
290 return helper()->m_buffer.putn_nocopy(sharedStr->c_str(), sharedStr->size()).then([sharedStr](size_t size) { return size; });
291 }
292 }
293
301 template<typename T>
303 {
305 if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
306 // TODO in the future this could be improved to have Value2StringFormatter avoid another unnecessary copy
307 // by putting the string on the heap before calling the print string overload.
309 }
310
318 template<typename T>
320 {
322 if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
324 str.push_back(CharType('\n'));
326 }
327
332 {
334 if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
335 return helper()->m_buffer.sync();
336 }
337
343 pos_type
seek(pos_type pos)
const
344 {
345 _verify_and_throw(details::_out_stream_msg);
346 return helper()->m_buffer.seekpos(pos, std::ios_base::out);
347 }
348
355 pos_type
seek(off_type off, std::ios_base::seekdir way)
const
356 {
357 _verify_and_throw(details::_out_stream_msg);
358 return helper()->m_buffer.seekoff(off, way, std::ios_base::out);
359 }
360
366 {
367 _verify_and_throw(details::_out_stream_msg);
368 return helper()->m_buffer.getpos(std::ios_base::out);
369 }
370
376
381 bool is_valid()
const {
return (m_helper !=
nullptr) && ((bool)m_helper->m_buffer); }
382
387
393
398 concurrency::streams::streambuf<CharType>
streambuf()
const
399 {
400 return helper()->m_buffer;
401 }
402
403 protected:
404
406 {
407 m_helper = helper;
408 }
409
410 private:
411
412 template<typename T>
413 bool _verify_and_return_task(
const char *msg,
pplx::task<T> &tsk)
const
414 {
415 auto buffer = helper()->m_buffer;
416 if ( !(buffer.exception() == nullptr) )
417 {
418 tsk = pplx::task_from_exception<T>(buffer.exception());
419 return false;
420 }
421 if ( !buffer.can_write() )
422 {
423 tsk = pplx::task_from_exception<T>(std::make_exception_ptr(std::runtime_error(msg)));
424 return false;
425 }
426 return true;
427 }
428
429 void _verify_and_throw(const char *msg) const
430 {
431 auto buffer = helper()->m_buffer;
432 if ( !(buffer.exception() == nullptr) )
433 std::rethrow_exception(buffer.exception());
434 if ( !buffer.can_write() )
435 throw std::runtime_error(msg);
436 }
437
438 std::shared_ptr<details::basic_ostream_helper<CharType>> helper() const
439 {
440 if ( !m_helper )
441 throw std::logic_error("uninitialized stream object");
442 return m_helper;
443 }
444
445 std::shared_ptr<details::basic_ostream_helper<CharType>> m_helper;
446 };
447
448 template<typename int_type>
450 {
451 typedef std::false_type _is_integral;
452 typedef std::false_type _is_unsigned;
453 };
454
455 #ifdef _WIN32
456 #define _INT_TRAIT(_t,_low,_high) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::false_type _is_unsigned;static const int64_t _min = _low;static const int64_t _max = _high;};
457 #define _UINT_TRAIT(_t,_low,_high) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::true_type _is_unsigned;static const uint64_t _max = _high;};
458
459 _INT_TRAIT(char,INT8_MIN,INT8_MAX)
460 _INT_TRAIT(signed char,INT8_MIN,INT8_MAX)
461 _INT_TRAIT(short,INT16_MIN,INT16_MAX)
462 _INT_TRAIT(utf16char,INT16_MIN,INT16_MAX)
463 _INT_TRAIT(int,INT32_MIN,INT32_MAX)
464 _INT_TRAIT(long, LONG_MIN, LONG_MAX)
465 _INT_TRAIT(long long, LLONG_MIN, LLONG_MAX)
466 _UINT_TRAIT(unsigned char,UINT8_MIN,UINT8_MAX)
467 _UINT_TRAIT(unsigned short,UINT16_MIN,UINT16_MAX)
468 _UINT_TRAIT(unsigned int,UINT32_MIN,UINT32_MAX)
469 _UINT_TRAIT(unsigned long, ULONG_MIN, ULONG_MAX)
470 _UINT_TRAIT(unsigned long long, ULLONG_MIN, ULLONG_MAX)
471 #else
472 #define _INT_TRAIT(_t) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::false_type _is_unsigned;static const int64_t _min = std::numeric_limits<_t>::min();static const int64_t _max = (std::numeric_limits<_t>::max)();};
473 #define _UINT_TRAIT(_t) template<> struct _type_parser_integral_traits<_t>{typedef std::true_type _is_integral;typedef std::true_type _is_unsigned;static const uint64_t _max = (std::numeric_limits<_t>::max)();};
474
475 _INT_TRAIT(char)
476 _INT_TRAIT(signed char)
477 _INT_TRAIT(short)
478 _INT_TRAIT(utf16char)
479 _INT_TRAIT(int)
480 _INT_TRAIT(long)
481 _INT_TRAIT(long long)
482 _UINT_TRAIT(unsigned char)
483 _UINT_TRAIT(unsigned short)
484 _UINT_TRAIT(unsigned int)
485 _UINT_TRAIT(unsigned long)
486 _UINT_TRAIT(unsigned long long)
487 #endif
488
489 template<typename CharType>
491 {
492 public:
493 typedef typename ::concurrency::streams::char_traits<CharType>::int_type int_type;
494
496
497 protected:
498 // Aid in parsing input: skipping whitespace characters.
500
501 // Aid in parsing input: peek at a character at a time, call type-specific code to examine, extract value when done.
502 // <remark>AcceptFunctor should model std::function<bool(std::shared_ptr<X>, int_type)></remark>
503 // <remark>ExtractFunctor should model std::function<pplx::task<ReturnType>(std::shared_ptr<X>)></remark>
504 template<typename StateType, typename ReturnType, typename AcceptFunctor, typename ExtractFunctor>
506 };
507
512 template<typename CharType, typename T>
514 {
515 public:
517 {
518 typename _type_parser_integral_traits<T>::_is_integral ii;
519 typename _type_parser_integral_traits<T>::_is_unsigned ui;
520 return _parse(buffer, ii, ui);
521 }
522 private:
524 {
525 _parse_floating_point(buffer);
526 }
527
529 {
530 #ifdef _WIN32
531 static_assert(false, "type is not supported for extraction from a stream");
532 #else
533 throw std::runtime_error("type is not supported for extraction from a stream");
534 #endif
535 }
536
538 {
541 {
542 int64_t val = op.
get();
544 return (T)val;
545 else
546 throw std::range_error("input out of range for target type");
547 });
548 }
549
551 {
554 {
555 uint64_t val = op.
get();
557 return (T)val;
558 else
559 throw std::range_error("input out of range for target type");
560 });
561 }
562 };
563
567 template<typename CharType>
569 {
570 public:
571
574 typedef typename traits::pos_type pos_type;
575 typedef typename traits::off_type off_type;
576
577
582
591 {
592 _verify_and_throw(details::_in_streambuf_msg);
593 }
594
600
607 {
608 m_helper = other.m_helper;
609 return *this;
610 }
611
616 {
618 helper()->m_buffer.close(std::ios_base::in) :
619 pplx::task_from_result();
620 }
621
627 {
629 m_helper->m_buffer.close(std::ios_base::in, eptr) :
630 pplx::task_from_result();
631 }
632
638 {
639 return is_valid() ? m_helper->m_buffer.is_eof() :
false;
640 }
641
647 {
649 if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
650 return helper()->m_buffer.bumpc();
651 }
652
665 template<typename T>
666 CASABLANCA_DEPRECATED("Unsafe API that will be removed in future releases, use one of the other read overloads instead.")
668 {
669 static_assert(sizeof(CharType) == 1, "binary read is only supported for single-byte streams");
670 static_assert(std::is_trivial<T>::value, "unsafe to use with non-trivial types");
671
673 if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
674
675 auto copy = std::make_shared<T>();
676 return helper()->m_buffer.getn((CharType*)copy.get(),
sizeof(T)).then([copy](
pplx::task<size_t> op) -> T
677 {
678 return std::move(*copy);
679 });
680 }
681
689 {
691 if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
693 return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("target not set up for output of data")));
694
695 // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.
696 auto buffer = helper()->m_buffer;
697
698 auto data = target.
alloc(count);
699
700 if ( data != nullptr )
701 {
702 auto post_read =
704 {
705 auto t = target;
707 return op;
708 };
709 return buffer.getn(data, count).then(post_read);
710 }
711 else
712 {
713 size_t available = 0;
714
715 const bool acquired = buffer.acquire(data, available);
716 if (available >= count)
717 {
718 auto post_write =
720 {
721 auto b = buffer;
722 b.release(data, op.get());
723 return op;
724 };
725 return target.
putn_nocopy(data, count).then(post_write);
726 }
727 else
728 {
729 // Always have to release if acquire returned true.
730 if(acquired)
731 {
732 buffer.release(data, 0);
733 }
734
735 std::shared_ptr<CharType> buf(new CharType[count], [](CharType *buf) { delete [] buf; });
736
737 auto post_write =
739 {
740 return op;
741 };
742 auto post_read =
744 {
745 auto trg = target;
746 return trg.putn_nocopy(buf.get(), op.get()).then(post_write);
747 };
748
749 return helper()->m_buffer.getn(buf.get(), count).then(post_read);
750 }
751 }
752 }
753
759 {
761 if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
762 return helper()->m_buffer.getc();
763 }
764
773 {
775 if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
777 return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("target not set up for output of data")));
778
779 // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.
780 auto buffer = helper()->m_buffer;
781
782 int_type req_async = ::concurrency::streams::char_traits<CharType>::requires_async();
783
784 std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>();
785
786 auto flush = [=]() mutable
787 {
788 return target.
putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](
size_t wrote)
mutable
789 {
790 _locals->total += wrote;
791 _locals->write_pos = 0;
792 return target.
sync();
793 });
794 };
795
796 auto update = [=](int_type ch) mutable
797 {
798 if (ch == ::concurrency::streams::char_traits<CharType>::eof()) return false;
799 if (ch == delim) return false;
800
801 _locals->outbuf[_locals->write_pos] = static_cast<CharType>(ch);
802 _locals->write_pos += 1;
803
804 if (_locals->is_full())
805 {
806 // Flushing synchronously because performance is terrible if we
807 // schedule an empty task. This isn't on a user's thread.
808 flush().get();
809 }
810
811 return true;
812 };
813
815 {
816 while (buffer.in_avail() > 0)
817 {
818 int_type ch = buffer.sbumpc();
819
820 if (ch == req_async)
821 {
822 break;
823 }
824
825 if (!update(ch))
826 {
827 return pplx::task_from_result(false);
828 }
829 }
830 return buffer.bumpc().then(update);
831 });
832
833 return loop.then([=](bool) mutable
834 {
835 return flush().then([=] { return _locals->total; });
836 });
837 }
838
845 {
847 if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
849 return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("target not set up for receiving data")));
850
851 // Capture 'buffer' rather than 'helper' here due to VC++ 2010 limitations.
852 concurrency::streams::streambuf<CharType> buffer = helper()->m_buffer;
853
854 typename concurrency::streams::char_traits<CharType>::int_type req_async = concurrency::streams::char_traits<CharType>::requires_async();
855
856 std::shared_ptr<_read_helper> _locals = std::make_shared<_read_helper>();
857
858 auto flush = [=]() mutable
859 {
860 return target.
putn_nocopy(_locals->outbuf, _locals->write_pos).then([=](
size_t wrote)
mutable
861 {
862 _locals->total += wrote;
863 _locals->write_pos = 0;
864 return target.
sync();
865 });
866 };
867
868 auto update = [=](typename concurrency::streams::char_traits<CharType>::int_type ch) mutable
869 {
870 if (ch == concurrency::streams::char_traits<CharType>::eof()) return false;
871 if (ch == '\n') return false;
872 if (ch == '\r')
873 {
874 _locals->saw_CR = true;
875 return true;
876 }
877
878 _locals->outbuf[_locals->write_pos] = static_cast<CharType>(ch);
879 _locals->write_pos += 1;
880
881 if (_locals->is_full())
882 {
883 // Flushing synchronously because performance is terrible if we
884 // schedule an empty task. This isn't on a user's thread.
885 flush().wait();
886 }
887
888 return true;
889 };
890
891 auto update_after_cr = [=] (
typename concurrency::streams::char_traits<CharType>::int_type ch)
mutable ->
pplx::task<bool>
892 {
893 if (ch == concurrency::streams::char_traits<CharType>::eof()) return pplx::task_from_result(false);
894 if (ch == '\n')
895 {
896 return buffer.bumpc().then([](
897 #ifndef _WIN32 // Required by GCC
898 typename
899 #endif
900 concurrency::streams::char_traits<CharType>::int_type) { return false; });
901 }
902 return pplx::task_from_result(false);
903 };
904
906 {
907 while ( buffer.in_avail() > 0 )
908 {
909 #ifndef _WIN32 // Required by GCC, because concurrency::streams::char_traits<CharType> is a dependent scope
910 typename
911 #endif
912 concurrency::streams::char_traits<CharType>::int_type ch;
913
914 if (_locals->saw_CR)
915 {
916 ch = buffer.sgetc();
917 if (ch == '\n')
918 buffer.sbumpc();
919 return pplx::task_from_result(false);
920 }
921
922 ch = buffer.sbumpc();
923
924 if (ch == req_async)
925 break;
926
927 if (!update(ch))
928 {
929 return pplx::task_from_result(false);
930 }
931 }
932
933 if (_locals->saw_CR)
934 {
935 return buffer.getc().then(update_after_cr);
936 }
937 return buffer.bumpc().then(update);
938 });
939
940 return loop.then([=](bool) mutable
941 {
942 return flush().then([=] { return _locals->total; });
943 });
944 }
945
952 {
954 if ( !_verify_and_return_task("stream not set up for output of data", result) ) return result;
956 return pplx::task_from_exception<size_t>(std::make_exception_ptr(std::runtime_error("source buffer not set up for input of data")));
957
958 auto l_buffer = helper()->m_buffer;
959 auto l_buf_size = this->buf_size;
960 std::shared_ptr<_read_helper> l_locals = std::make_shared<_read_helper>();
961
962 auto copy_to_target = [l_locals, target, l_buffer, l_buf_size]()
mutable ->
pplx::task<bool>
963 {
964 // We need to capture these, because the object itself may go away
965 // before we're done processing the data.
966 //auto locs = _locals;
967 //auto trg = target;
968
969 return l_buffer.getn(l_locals->outbuf, l_buf_size).then([=](
size_t rd)
mutable ->
pplx::task<bool>
970 {
971 if (rd == 0)
972 return pplx::task_from_result(false);
973
974 // Must be nested to capture rd
975 return target.putn_nocopy(l_locals->outbuf, rd).then([target, l_locals, rd](
size_t wr)
mutable ->
pplx::task<bool>
976 {
977 l_locals->total += wr;
978
979 if (rd != wr)
980 // Number of bytes written is less than number of bytes received.
981 throw std::runtime_error("failed to write all bytes");
982
983 return target.sync().then([]() { return true; });
984 });
985 });
986 };
987
988 auto loop = pplx::details::do_while(copy_to_target);
989
990 return loop.then([=](bool) mutable -> size_t
991 {
992 return l_locals->total;
993 });
994 }
995
1002 {
1003 _verify_and_throw(details::_in_stream_msg);
1004 return helper()->m_buffer.seekpos(pos, std::ios_base::in);
1005 }
1006
1013 pos_type
seek(off_type off, std::ios_base::seekdir way)
const
1014 {
1015 _verify_and_throw(details::_in_stream_msg);
1016 return helper()->m_buffer.seekoff(off, way, std::ios_base::in);
1017 }
1018
1024 {
1025 _verify_and_throw(details::_in_stream_msg);
1026 return helper()->m_buffer.getpos(std::ios_base::in);
1027 }
1028
1034
1038 bool is_valid()
const {
return (m_helper !=
nullptr) && ((bool)m_helper->m_buffer); }
1039
1044
1050
1055 {
1056 return helper()->m_buffer;
1057 }
1058
1070 template<typename T>
1072 {
1074 if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
1076 }
1077
1078 private:
1079
1080 template<typename T>
1081 bool _verify_and_return_task(
const char *msg,
pplx::task<T> &tsk)
const
1082 {
1083 auto buffer = helper()->m_buffer;
1084 if ( !(buffer.exception() == nullptr) )
1085 {
1086 tsk = pplx::task_from_exception<T>(buffer.exception());
1087 return false;
1088 }
1089 if ( !buffer.can_read() )
1090 {
1091 tsk = pplx::task_from_exception<T>(std::make_exception_ptr(std::runtime_error(msg)));
1092 return false;
1093 }
1094 return true;
1095 }
1096
1097 void _verify_and_throw(const char *msg) const
1098 {
1099 auto buffer = helper()->m_buffer;
1100 if ( !(buffer.exception() == nullptr) )
1101 std::rethrow_exception(buffer.exception());
1102 if ( !buffer.can_read() )
1103 throw std::runtime_error(msg);
1104 }
1105
1106 std::shared_ptr<details::basic_istream_helper<CharType>> helper() const
1107 {
1108 if ( !m_helper )
1109 throw std::logic_error("uninitialized stream object");
1110 return m_helper;
1111 }
1112
1113 static const size_t buf_size = 16*1024;
1114
1115 struct _read_helper
1116 {
1117 size_t total;
1118 CharType outbuf[buf_size];
1119 size_t write_pos;
1120 bool saw_CR;
1121
1122 bool is_full() const
1123 {
1124 return write_pos == buf_size;
1125 }
1126
1127 _read_helper() : total(0), write_pos(0), saw_CR(false)
1128 {
1129 }
1130 };
1131
1132 std::shared_ptr<details::basic_istream_helper<CharType>> m_helper;
1133 };
1134
1135 typedef basic_ostream<uint8_t> ostream;
1136 typedef basic_istream<uint8_t> istream;
1137
1138 typedef basic_ostream<utf16char> wostream;
1139 typedef basic_istream<utf16char> wistream;
1140
1141 template<typename CharType>
1142 pplx::task<void> concurrency::streams::_type_parser_base<CharType>::_skip_whitespace(streams::streambuf<CharType> buffer)
1143 {
1144 int_type req_async = concurrency::streams::char_traits<CharType>::requires_async();
1145
1146 auto update = [=] (int_type ch) mutable
1147 {
1148 if (isspace(ch))
1149 {
1150 if (buffer.sbumpc() == req_async)
1151 {
1152 // Synchronously because performance is terrible if we
1153 // schedule an empty task. This isn't on a user's thread.
1154 buffer.nextc().wait();
1155 }
1156 return true;
1157 }
1158
1159 return false;
1160 };
1161
1163 {
1164 while (buffer.in_avail() > 0)
1165 {
1166 int_type ch = buffer.sgetc();
1167
1168 if (ch == req_async)
1169 break;
1170
1171 if (!update(ch))
1172 {
1173 return pplx::task_from_result(false);
1174 }
1175 }
1176 return buffer.getc().then(update);
1177 });
1178
1180 {
1182 });
1183 }
1184
1185 template<typename CharType>
1186 template<typename StateType, typename ReturnType, typename AcceptFunctor, typename ExtractFunctor>
1188 concurrency::streams::streambuf<CharType> buffer,
1189 AcceptFunctor accept_character,
1190 ExtractFunctor extract)
1191 {
1192 std::shared_ptr<StateType> state = std::make_shared<StateType>();
1193
1195 {
1196 int_type ch = op.
get();
1197 if (ch == concurrency::streams::char_traits<CharType>::eof()) return pplx::task_from_result(false);
1198 bool accptd = accept_character(state, ch);
1199 if (!accptd)
1200 return pplx::task_from_result(false);
1201 // We peeked earlier, so now we must advance the position.
1202 concurrency::streams::streambuf<CharType> buf = buffer;
1203 return buf.bumpc().then([](int_type) { return true; });
1204 };
1205
1207 {
1208 concurrency::streams::streambuf<CharType> buf = buffer;
1209
1210 // If task results are immediately available, there's little need to use ".then(),"
1211 // so optimize for prompt values.
1212
1213 auto get_op = buf.getc();
1214 while (get_op.is_done())
1215 {
1216 auto condition = update(get_op);
1217 if (!condition.is_done() || !condition.get())
1218 return condition;
1219
1220 get_op = buf.getc();
1221 }
1222
1223 return get_op.then(update);
1224 };
1225
1226 auto finish =
1228 {
1231 return result;
1232 };
1233
1235 {
1237 return pplx::details::do_while(peek_char).then(finish);
1238 });
1239 }
1240
1241 template<typename CharType>
1243 {
1244 typedef typename _type_parser_base<CharType>::int_type int_type;
1245 public:
1247 {
1248 return concurrency::streams::_type_parser_base<CharType>::template _parse_input<std::basic_string<CharType>, std::string>(buffer, _accept_char, _extract_result);
1249 }
1250
1251 private:
1252 static bool _accept_char(std::shared_ptr<std::basic_string<CharType>> state, int_type ch)
1253 {
1254 if ( ch == concurrency::streams::char_traits<CharType>::eof() || isspace(ch)) return false;
1255 state->push_back(CharType(ch));
1256 return true;
1257 }
1259 {
1260 return pplx::task_from_result(*state);
1261 }
1262 };
1263
1264 template<typename CharType>
1266 {
1267 public:
1268 typedef typename _type_parser_base<CharType>::int_type int_type;
1270 {
1272 }
1273 private:
1274 struct _int64_state
1275 {
1276 _int64_state() : result(0), correct(false), minus(0) {}
1277
1278 int64_t result;
1279 bool correct;
1280 char minus; // 0 -- no sign, 1 -- plus, 2 -- minus
1281 };
1282
1283 static bool _accept_char(std::shared_ptr<_int64_state> state, int_type ch)
1284 {
1285 if ( ch == concurrency::streams::char_traits<CharType>::eof()) return false;
1286 if ( state->minus == 0 )
1287 {
1288 // OK to find a sign.
1289 if ( !::isdigit(ch) && ch != int_type('+') && ch != int_type('-') )
1290 return false;
1291 }
1292 else
1293 {
1294 if ( !::isdigit(ch) ) return false;
1295 }
1296
1297 // At least one digit was found.
1298 state->correct = true;
1299
1300 if ( ch == int_type('+') )
1301 {
1302 state->minus = 1;
1303 }
1304 else if ( ch == int_type('-') )
1305 {
1306 state->minus = 2;
1307 }
1308 else
1309 {
1310 if (state->minus == 0) state->minus = 1;
1311
1312 // Shift the existing value by 10, then add the new value.
1313 bool positive = state->result >= 0;
1314
1315 state->result *= 10;
1316 state->result += int64_t(ch-int_type('0'));
1317
1318 if ( (state->result >= 0) != positive )
1319 {
1320 state->correct = false;
1321 return false;
1322 }
1323 }
1324 return true;
1325 }
1326
1328 {
1329 if (!state->correct)
1330 throw std::range_error("integer value is too large to fit in 64 bits");
1331
1332 int64_t result = (state->minus == 2) ? -state->result : state->result;
1333 return pplx::task_from_result<int64_t>(result);
1334 }
1335 };
1336
1337 template <typename FloatingPoint>
1339 {
1340 _double_state() : result(0), minus(0), after_comma(0), exponent(
false), exponent_number(0), exponent_minus(0), complete(
false), p_exception_string() {}
1341
1342 FloatingPoint result;
1343 char minus; // 0 -- no sign, 1 -- plus, 2 -- minus
1344 int after_comma;
1345 bool exponent;
1346 int exponent_number;
1347 char exponent_minus; // 0 -- no sign, 1 -- plus, 2 -- minus
1348 bool complete;
1349 std::string p_exception_string;
1350 };
1351
1352 template <typename FloatingPoint, typename int_type>
1353 static std::string create_exception_message(int_type ch, bool exponent)
1354 {
1355 std::ostringstream os;
1356 os << "Invalid character '" << char(ch) << "'" << (exponent ? " in exponent" : "");
1357 return os.str();
1358 }
1359
1360 template <typename FloatingPoint, typename int_type>
1361 static bool _accept_char(std::shared_ptr<_double_state<FloatingPoint>> state, int_type ch)
1362 {
1363 if ( state->minus == 0 )
1364 {
1365 if ( !::isdigit(ch) && ch != int_type('.') && ch != int_type('+') && ch != int_type('-') )
1366 {
1367 if (!state->complete)
1368 state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, false);
1369 return false;
1370 }
1371 }
1372 else
1373 {
1374 if (!state->exponent && !::isdigit(ch) && ch != int_type('.') && ch != int_type('E') && ch != int_type('e'))
1375 {
1376 if (!state->complete)
1377 state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, false);
1378 return false;
1379 }
1380
1381 if (state->exponent && !::isdigit(ch) && ch != int_type('+') && ch != int_type('-'))
1382 {
1383 if (!state->complete)
1384 state->p_exception_string = create_exception_message<FloatingPoint, int_type>(ch, true);
1385 return false;
1386 }
1387 }
1388
1389 switch (ch)
1390 {
1391 case int_type('+') :
1392 state->complete = false;
1393 if (state->exponent)
1394 {
1395 if (state->exponent_minus != 0)
1396 {
1397 state->p_exception_string = "The exponent sign already set";
1398 return false;
1399 }
1400 state->exponent_minus = 1;
1401 }
1402 else
1403 {
1404 state->minus = 1;
1405 }
1406 break;
1407 case int_type('-') :
1408 state->complete = false;
1409 if (state->exponent)
1410 {
1411 if (state->exponent_minus != 0)
1412 {
1413 state->p_exception_string = "The exponent sign already set";
1414 return false;
1415 }
1416
1417 state->exponent_minus = 2;
1418 }
1419 else
1420 {
1421 state->minus = 2;
1422 }
1423 break;
1424 case int_type('.') :
1425 state->complete = false;
1426 if (state->after_comma > 0)
1427 return false;
1428
1429 state->after_comma = 1;
1430 break;
1431 case int_type('E') : case int_type('e') :
1432 state->complete = false;
1433 if (state->exponent)
1434 return false;
1435 state->exponent_number = 0;
1436 state->exponent = true;
1437 break;
1438 default:
1439 state->complete = true;
1440 if (!state->exponent)
1441 {
1442 if (state->minus == 0)
1443 state->minus = 1;
1444
1445 state->result *= 10;
1446 state->result += int64_t(ch-int_type('0'));
1447
1448 if (state->after_comma > 0)
1449 state->after_comma++;
1450 }
1451 else
1452 {
1453 if (state->exponent_minus == 0) state->exponent_minus = 1;
1454 state->exponent_number *= 10;
1455 state->exponent_number += int64_t(ch-int_type('0'));
1456 }
1457 }
1458 return true;
1459 }
1460
1461 template <typename FloatingPoint>
1463 {
1464 if (state->p_exception_string.length() > 0)
1465 throw std::runtime_error(state->p_exception_string.c_str());
1466
1467 if (!state->complete && state->exponent)
1468 throw std::runtime_error("Incomplete exponent");
1469
1470 FloatingPoint result = static_cast<FloatingPoint>((state->minus == 2) ? -state->result : state->result);
1471 if (state->exponent_minus == 2)
1472 state->exponent_number = 0 - state->exponent_number;
1473
1474 if (state->after_comma > 0)
1475 state->exponent_number -= state->after_comma-1;
1476
1477 if (state->exponent_number >= 0)
1478 {
1479 result *= pow(FloatingPoint(10.0), state->exponent_number);
1480
1481 #pragma push_macro ("max")
1482 #undef max
1483
1484 if (result > std::numeric_limits<FloatingPoint>::max() || result < -std::numeric_limits<FloatingPoint>::max())
1485 throw std::overflow_error("The value is too big");
1486 #pragma pop_macro ("max")
1487 }
1488 else
1489 {
1490 bool is_zero = (result == 0);
1491
1492 result /= pow(FloatingPoint(10.0), -state->exponent_number);
1493
1494 if (!is_zero &&
1495 result > -std::numeric_limits<FloatingPoint>::denorm_min() &&
1496 result < std::numeric_limits<FloatingPoint>::denorm_min())
1497 throw std::underflow_error("The value is too small");
1498 }
1499
1500 return pplx::task_from_result<FloatingPoint>(result);
1501 }
1502
1503 template<typename CharType>
1505 {
1506 public:
1507 typedef typename _type_parser_base<CharType>::int_type int_type;
1509 {
1511 }
1512 protected:
1513 };
1514
1515 template<typename CharType>
1517 {
1518 public:
1519 typedef typename _type_parser_base<CharType>::int_type int_type;
1521 {
1523 }
1524 protected:
1525 };
1526
1527
1528 template<typename CharType>
1530 {
1531 public:
1532 typedef typename _type_parser_base<CharType>::int_type int_type;
1534 {
1536 }
1537
1538 private:
1539 struct _uint64_state
1540 {
1541 _uint64_state() : result(0), correct(false) {}
1542 uint64_t result;
1543 bool correct;
1544 };
1545
1546 static bool _accept_char(std::shared_ptr<_uint64_state> state, int_type ch)
1547 {
1548 if ( !::isdigit(ch) ) return false;
1549
1550 // At least one digit was found.
1551 state->correct = true;
1552
1553 // Shift the existing value by 10, then add the new value.
1554 state->result *= 10;
1555 state->result += uint64_t(ch-int_type('0'));
1556
1557 return true;
1558 }
1559
1561 {
1562 if (!state->correct)
1563 throw std::range_error("integer value is too large to fit in 64 bits");
1564 return pplx::task_from_result(state->result);
1565 }
1566 };
1567
1568 template<typename CharType>
1570 {
1571 public:
1572 typedef typename _type_parser_base<CharType>::int_type int_type;
1574 {
1576 }
1577 private:
1578 struct _bool_state
1579 {
1580 _bool_state() : state(0) { }
1581 // { 0 -- not started, 1 -- 't', 2 -- 'tr', 3 -- 'tru', 4 -- 'f', 5 -- 'fa', 6 -- 'fal', 7 -- 'fals', 8 -- 'true', 9 -- 'false' }
1582 short state;
1583 };
1584
1585 static bool _accept_char(std::shared_ptr<_bool_state> state, int_type ch)
1586 {
1587 switch (state->state)
1588 {
1589 case 0:
1590 if ( ch == int_type('t') ) state->state = 1;
1591 else if ( ch == int_type('f') ) state->state = 4;
1592 else if ( ch == int_type('1') ) state->state = 8;
1593 else if ( ch == int_type('0') ) state->state = 9;
1594 else return false;
1595 break;
1596 case 1:
1597 if ( ch == int_type('r') ) state->state = 2;
1598 else return false;
1599 break;
1600 case 2:
1601 if ( ch == int_type('u') ) state->state = 3;
1602 else return false;
1603 break;
1604 case 3:
1605 if ( ch == int_type('e') ) state->state = 8;
1606 else return false;
1607 break;
1608 case 4:
1609 if ( ch == int_type('a') ) state->state = 5;
1610 else return false;
1611 break;
1612 case 5:
1613 if ( ch == int_type('l') ) state->state = 6;
1614 else return false;
1615 break;
1616 case 6:
1617 if ( ch == int_type('s') ) state->state = 7;
1618 else return false;
1619 break;
1620 case 7:
1621 if ( ch == int_type('e') ) state->state = 9;
1622 else return false;
1623 break;
1624 case 8:
1625 case 9:
1626 return false;
1627 }
1628 return true;
1629 }
1630 static pplx::task<bool> _extract_result(std::shared_ptr<_bool_state> state)
1631 {
1632 bool correct = (state->state == 8 || state->state == 9);
1633 if (!correct)
1634 {
1635 std::runtime_error exc("cannot parse as Boolean value");
1636 throw exc;
1637 }
1638 return pplx::task_from_result(state->state == 8);
1639 }
1640 };
1641
1642 template<typename CharType>
1644 {
1645 typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
1646 public:
1648 {
1651 {
1654 });
1655 }
1656 private:
1658 {
1659 concurrency::streams::streambuf<CharType> buf = buffer;
1660 return buf.
bumpc().then(
1661 [=](
pplx::task<
typename concurrency::streams::streambuf<CharType>::int_type> op) ->
signed char
1662 {
1663 int_type val = op.
get();
1664 if (val == concurrency::streams::char_traits<CharType>::eof())
1665 throw std::runtime_error("reached end-of-stream while constructing a value");
1666 return static_cast<signed char>(val);
1667 });
1668 }
1669 };
1670
1671 template<typename CharType>
1673 {
1674 typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
1675 public:
1677 {
1680 {
1683 });
1684 }
1685 private:
1687 {
1688 concurrency::streams::streambuf<CharType> buf = buffer;
1689 return buf.
bumpc().then(
1690 [=](
pplx::task<
typename concurrency::streams::streambuf<CharType>::int_type> op) ->
unsigned char
1691 {
1692 int_type val = op.
get();
1693 if (val == concurrency::streams::char_traits<CharType>::eof())
1694 throw std::runtime_error("reached end-of-stream while constructing a value");
1695 return static_cast<unsigned char>(val);
1696 });
1697 }
1698 };
1699
1700 template<typename CharType>
1702 {
1703 typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
1704 public:
1706 {
1709 {
1711 return _get_char(buffer);
1712 });
1713 }
1714 private:
1716 {
1717 concurrency::streams::streambuf<CharType> buf = buffer;
1718 return buf.
bumpc().then(
1719 [=](
pplx::task<
typename concurrency::streams::streambuf<CharType>::int_type> op) ->
char
1720 {
1721 int_type val = op.
get();
1722 if (val == concurrency::streams::char_traits<CharType>::eof())
1723 throw std::runtime_error("reached end-of-stream while constructing a value");
1724 return char(val);
1725 });
1726 }
1727 };
1728
1729 #ifdef _WIN32
1730 template<>
1732 {
1733 public:
1735 {
1736 return _parse_input<std::basic_string<char>,std::basic_string<wchar_t>>(buffer, _accept_char, _extract_result);
1737 }
1738
1739 private:
1740 static bool _accept_char(const std::shared_ptr<std::basic_string<char>> &state, int_type ch)
1741 {
1742 if ( ch == concurrency::streams::char_traits<char>::eof() || isspace(ch)) return false;
1743 state->push_back(char(ch));
1744 return true;
1745 }
1747 {
1749 }
1750 };
1751
1752 template<>
1753 class type_parser<signed char,std::basic_string<wchar_t>> : public _type_parser_base<signed char>
1754 {
1755 public:
1757 {
1758 return _parse_input<std::basic_string<char>,std::basic_string<wchar_t>>(buffer, _accept_char, _extract_result);
1759 }
1760
1761 private:
1762 static bool _accept_char(const std::shared_ptr<std::basic_string<char>> &state, int_type ch)
1763 {
1764 if ( ch == concurrency::streams::char_traits<char>::eof() || isspace(ch)) return false;
1765 state->push_back(char(ch));
1766 return true;
1767 }
1769 {
1771 }
1772 };
1773
1774 template<>
1775 class type_parser<unsigned char,std::basic_string<wchar_t>> : public _type_parser_base<unsigned char>
1776 {
1777 public:
1779 {
1780 return _parse_input<std::basic_string<char>,std::basic_string<wchar_t>>(buffer, _accept_char, _extract_result);
1781 }
1782
1783 private:
1784 static bool _accept_char(const std::shared_ptr<std::basic_string<char>> &state, int_type ch)
1785 {
1786 if ( ch == concurrency::streams::char_traits<char>::eof() || isspace(ch)) return false;
1787 state->push_back(char(ch));
1788 return true;
1789 }
1791 {
1793 }
1794 };
1795 #endif //_WIN32
1796
1797 }}
1798
1799 #endif
concurrency::streams::streambuf< CharType > streambuf() const
Get the underlying stream buffer.
Definition: streams.h:398
Class used to handle asychronous parsing for basic_istream::extract. To support new types create a ne...
Definition: streams.h:513
_ASYNCRTIMP std::string __cdecl utf16_to_utf8(const utf16string &w)
Converts a UTF-16 string to a UTF-8 string.
pplx::task< int_type > write(CharType ch) const
Put a single character into the stream.
Definition: streams.h:169
pplx::task< size_t > read(streams::streambuf< CharType > target, size_t count) const
Reads up to count characters and place into the provided buffer.
Definition: streams.h:688
The pplx namespace provides classes and functions that give you access to the Concurrency Runtime...
Definition: pplx.h:81
task_status wait() const
Waits for this task to reach a terminal state. It is possible for wait to execute the task inline...
Definition: pplxtasks.h:3512
bool is_open() const
Test whether the stream is open for writing.
Definition: streams.h:1049
basic_ostream & operator=(const basic_ostream &other)
Assignment operator
Definition: streams.h:132
pos_type seek(pos_type pos) const
Seeks to the specified write position.
Definition: streams.h:343
Reference-counted stream buffer.
Definition: astreambuf.h:804
virtual void release(_Out_writes_(count) _CharType *ptr, _In_ size_t count)
Releases a block of data acquired using ::acquire method. This frees the stream buffer to de-allocate...
Definition: astreambuf.h:1030
pplx::task< size_t > write(streams::streambuf< CharType > source, size_t count) const
Write a number of characters from a given stream buffer into the stream.
Definition: streams.h:207
Base interface for all asynchronous output streams.
Definition: astreambuf.h:792
pplx::task< size_t > read_to_end(streams::streambuf< CharType > target) const
Read until reaching the end of the stream.
Definition: streams.h:951
_ASYNCRTIMP utf16string __cdecl utf8_to_utf16(const std::string &s)
Converts a UTF-8 string to a UTF-16
basic_ostream()
Default constructor
Definition: streams.h:119
pplx::task< void > close(std::exception_ptr eptr) const
Close the stream with exception, preventing further read operations.
Definition: streams.h:626
void get() const
Returns the result this task produced. If the task is not in a terminal state, a call to get will wai...
Definition: pplxtasks.h:4440
pplx::task< size_t > print(const std::basic_string< CharType > &str) const
Write the specified string to the output stream.
Definition: streams.h:278
basic_istream & operator=(const basic_istream &other)
Assignment operator
Definition: streams.h:606
pplx::task< void > close() const
Close the stream, preventing further write operations.
Definition: streams.h:147
pplx::task< void > close() const
Close the stream, preventing further read operations.
Definition: streams.h:615
virtual pplx::task< size_t > getn(_Out_writes_(count) _CharType *ptr, _In_ size_t count)
Reads up to a given number of characters from the stream.
Definition: astreambuf.h:1121
virtual pplx::task< int_type > bumpc()
Reads a single character from the stream and advances the read position.
Definition: astreambuf.h:1063
Definition: streams.h:1338
pplx::task< size_t > read_to_delim(streams::streambuf< CharType > target, int_type delim) const
Read characters until a delimiter or EOF is found, and place them into the target. Proceed past the delimiter, but don't include it in the target buffer.
Definition: streams.h:772
pos_type seek(off_type off, std::ios_base::seekdir way) const
Seeks to the specified write position.
Definition: streams.h:355
pplx::task< void > close(std::exception_ptr eptr) const
Close the stream with exception, preventing further write operations.
Definition: streams.h:158
pplx::task< T > extract() const
Read a value of type T from the stream.
Definition: streams.h:1071
The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed as...
Definition: pplxtasks.h:176
Definition: streams.h:449
bool is_valid() const
Test whether the stream has been initialized with a valid stream buffer.
Definition: streams.h:381
bool is_open() const
Test whether the stream is open for writing.
Definition: streams.h:392
pplx::task< size_t > print(const T &val) const
Write a value of type T to the output stream.
Definition: streams.h:302
task_status wait() const
Waits for this task to reach a terminal state. It is possible for wait to execute the task inline...
Definition: pplxtasks.h:4426
pplx::task< int_type > read() const
Get the next character and return it as an int_type. Advance the read position.
Definition: streams.h:646
pplx::task< size_t > print_line(const T &val) const
Write a value of type T to the output stream and append a newline character.
Definition: streams.h:319
bool can_seek() const
can_seek is used to determine whether the stream supports seeking.
Definition: streams.h:375
_ReturnType get() const
Returns the result this task produced. If the task is not in a terminal state, a call to get will wai...
Definition: pplxtasks.h:3534
Base interface for all asynchronous input streams.
Definition: astreambuf.h:791
The Parallel Patterns Library (PPL) task class. A task object represents work that can be executed as...
Definition: pplxtasks.h:4173
concurrency::streams::streambuf< CharType > streambuf() const
Get the underlying stream buffer.
Definition: streams.h:1054
pplx::task< int_type > peek() const
Get the next character and return it as an int_type. Do not advance the read position.
Definition: streams.h:758
pos_type tell() const
Get the current write position, i.e. the offset from the beginning of the stream. ...
Definition: streams.h:1023
virtual void commit(size_t count)
Submits a block already allocated by the stream buffer.
Definition: astreambuf.h:999
pplx::task< void > flush() const
Flush any buffered output data.
Definition: streams.h:331
basic_istream(streams::streambuf< CharType > buffer)
Constructor
Definition: streams.h:590
pplx::task< size_t > read_line(streams::streambuf< CharType > target) const
Read until reaching a newline character. The newline is not included in the target.
Definition: streams.h:844
Definition: astreambuf.h:37
basic_ostream(streams::streambuf< CharType > buffer)
Constructor
Definition: streams.h:138
basic_ostream(const basic_ostream &other)
Copy constructor
Definition: streams.h:125
bool is_eof() const
Tests whether last read cause the stream reach EOF.
Definition: streams.h:637
Definition: streams.h:490
virtual pplx::task< void > sync()
For output streams, flush any internally buffered data to the underlying medium.
Definition: astreambuf.h:1180
bool can_seek() const
can_seek is used to determine whether the stream supports seeking.
Definition: streams.h:1033
basic_istream()
Default constructor
Definition: streams.h:581
basic_istream(const basic_istream &other)
Copy constructor
Definition: streams.h:599
virtual _CharType * alloc(size_t count)
Allocates a contiguous memory block and returns it.
Definition: astreambuf.h:990
bool is_valid() const
Test whether the stream has been initialized with a valid stream buffer.
Definition: streams.h:1038
pos_type tell() const
Get the current write position, i.e. the offset from the beginning of the stream. ...
Definition: streams.h:365
virtual pplx::task< size_t > putn_nocopy(const _CharType *ptr, size_t count)
Writes a number of characters to the stream. Note: callers must make sure the data to be written is v...
Definition: astreambuf.h:1054
virtual bool acquire(_Out_ _CharType *&ptr, _Out_ size_t &count)
Gets a pointer to the next already allocated contiguous block of data.
Definition: astreambuf.h:1017
pos_type seek(off_type off, std::ios_base::seekdir way) const
Seeks to the specified write position.
Definition: streams.h:1013
Extending the standard char_traits type with one that adds values and types that are unique to "C++ R...
Definition: astreambuf.h:50
virtual bool can_read() const
can_read is used to determine whether a stream buffer will support read operations (get)...
Definition: astreambuf.h:889
virtual bool can_write() const
can_write is used to determine whether a stream buffer will support write operations (put)...
Definition: astreambuf.h:894
pos_type seek(pos_type pos) const
Seeks to the specified write position.
Definition: streams.h:1001