C++ Rest SDK
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.
streams.h
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 
33 namespace Concurrency { namespace streams
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:
43  basic_ostream_helper(streams::streambuf<CharType> buffer) : m_buffer(buffer) { }
44 
46 
47  private:
48  template<typename CharType1> friend class streams::basic_ostream;
49 
50  concurrency::streams::streambuf<CharType> m_buffer;
51  };
52 
53  template<typename CharType>
55  {
56  public:
57  basic_istream_helper(streams::streambuf<CharType> buffer) : m_buffer(buffer) { }
58 
60 
61  private:
62  template<typename CharType1> friend class streams::basic_istream;
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 <>
80  struct Value2StringFormatter <uint8_t>
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  {
92  return format(utility::conversions::utf16_to_utf8(val));
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>
107  class basic_ostream
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 
125  basic_ostream(const basic_ostream &other) : m_helper(other.m_helper) { }
126 
132  basic_ostream & operator =(const basic_ostream &other) { m_helper = other.m_helper; return *this; }
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  {
149  return is_valid() ?
150  helper()->m_buffer.close(std::ios_base::out) :
151  pplx::task_from_result();
152  }
153 
158  pplx::task<void> close(std::exception_ptr eptr) const
159  {
160  return is_valid() ?
161  helper()->m_buffer.close(std::ios_base::out, eptr) :
162  pplx::task_from_result();
163  }
164 
169  pplx::task<int_type> write(CharType ch) const
170  {
171  pplx::task<int_type> result;
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.")
190  pplx::task<size_t> write(T value) const
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 
195  pplx::task<size_t> result;
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  {
209  pplx::task<size_t> result;
210  if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
211  if ( !source.can_read() )
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 =
239  [source,data](pplx::task<size_t> op)-> pplx::task<size_t>
240  {
241  auto s = source;
242  s.release(data,op.get());
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  {
252  source.release(data, 0);
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 =
263  [buf,post_write,buffer](pplx::task<size_t> op) -> pplx::task<size_t>
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 
278  pplx::task<size_t> print(const std::basic_string<CharType>& str) const
279  {
280  pplx::task<size_t> result;
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>
302  pplx::task<size_t> print(const T& val) const
303  {
304  pplx::task<size_t> result;
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>
319  pplx::task<size_t> print_line(const T& val) const
320  {
321  pplx::task<size_t> result;
322  if ( !_verify_and_return_task(details::_out_stream_msg, result) ) return result;
324  str.push_back(CharType('\n'));
325  return print(str);
326  }
327 
332  {
333  pplx::task<void> result;
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 
365  pos_type tell() const
366  {
367  _verify_and_throw(details::_out_stream_msg);
368  return helper()->m_buffer.getpos(std::ios_base::out);
369  }
370 
375  bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); }
376 
381  bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); }
382 
386  operator bool() const { return is_valid(); }
387 
392  bool is_open() const { return is_valid() && m_helper->m_buffer.can_write(); }
393 
398  concurrency::streams::streambuf<CharType> streambuf() const
399  {
400  return helper()->m_buffer;
401  }
402 
403  protected:
404 
405  void set_helper(std::shared_ptr<details::basic_ostream_helper<CharType>> helper)
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 
495  _type_parser_base() { }
496 
497  protected:
498  // Aid in parsing input: skipping whitespace characters.
499  static pplx::task<void> _skip_whitespace(streams::streambuf<CharType> buffer);
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>
505  static pplx::task<ReturnType> _parse_input(streams::streambuf<CharType> buffer, AcceptFunctor accept_character, ExtractFunctor extract);
506  };
507 
512  template<typename CharType, typename T>
514  {
515  public:
516  static pplx::task<T> parse(streams::streambuf<CharType> buffer)
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:
523  static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::false_type, std::false_type)
524  {
525  _parse_floating_point(buffer);
526  }
527 
528  static pplx::task<T> _parse(streams::streambuf<CharType>, std::false_type, std::true_type)
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 
537  static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::true_type, std::false_type)
538  {
539  return type_parser<CharType,int64_t>::parse(buffer).then(
540  [] (pplx::task<int64_t> op) -> T
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 
550  static pplx::task<T> _parse(streams::streambuf<CharType> buffer, std::true_type, std::true_type)
551  {
552  return type_parser<CharType,uint64_t>::parse(buffer).then(
553  [] (pplx::task<uint64_t> op) -> T
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>
568  class basic_istream
569  {
570  public:
571 
572  typedef char_traits<CharType> traits;
573  typedef typename char_traits<CharType>::int_type int_type;
574  typedef typename traits::pos_type pos_type;
575  typedef typename traits::off_type off_type;
576 
577 
582 
590  basic_istream(streams::streambuf<CharType> buffer) : m_helper(std::make_shared<details::basic_istream_helper<CharType>>(buffer))
591  {
592  _verify_and_throw(details::_in_streambuf_msg);
593  }
594 
599  basic_istream(const basic_istream &other) : m_helper(other.m_helper) { }
600 
607  {
608  m_helper = other.m_helper;
609  return *this;
610  }
611 
616  {
617  return is_valid() ?
618  helper()->m_buffer.close(std::ios_base::in) :
619  pplx::task_from_result();
620  }
621 
626  pplx::task<void> close(std::exception_ptr eptr) const
627  {
628  return is_valid() ?
629  m_helper->m_buffer.close(std::ios_base::in, eptr) :
630  pplx::task_from_result();
631  }
632 
637  bool is_eof() const
638  {
639  return is_valid() ? m_helper->m_buffer.is_eof() : false;
640  }
641 
647  {
648  pplx::task<int_type> result;
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.")
667  pplx::task<T> read() const
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 
672  pplx::task<T> result;
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  {
690  pplx::task<size_t> result;
691  if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
692  if ( !target.can_write() )
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;
706  t.commit(op.get());
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 =
719  [buffer,data](pplx::task<size_t> op)-> pplx::task<size_t>
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 =
743  [buf,target,post_write](pplx::task<size_t> op) -> pplx::task<size_t>
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  {
760  pplx::task<int_type> result;
761  if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
762  return helper()->m_buffer.getc();
763  }
764 
773  {
774  pplx::task<size_t> result;
775  if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
776  if ( !target.can_write() )
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 
814  auto loop = pplx::details::do_while([=]() mutable -> pplx::task<bool>
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  {
846  pplx::task<size_t> result;
847  if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
848  if ( !target.can_write() )
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 
905  auto loop = pplx::details::do_while([=]() mutable -> pplx::task<bool>
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  {
953  pplx::task<size_t> result;
954  if ( !_verify_and_return_task("stream not set up for output of data", result) ) return result;
955  if ( !target.can_write() )
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 
1001  pos_type seek(pos_type pos) const
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 
1023  pos_type tell() const
1024  {
1025  _verify_and_throw(details::_in_stream_msg);
1026  return helper()->m_buffer.getpos(std::ios_base::in);
1027  }
1028 
1033  bool can_seek() const { return is_valid() && m_helper->m_buffer.can_seek(); }
1034 
1038  bool is_valid() const { return (m_helper != nullptr) && ((bool)m_helper->m_buffer); }
1039 
1043  operator bool() const { return is_valid(); }
1044 
1049  bool is_open() const { return is_valid() && m_helper->m_buffer.can_read(); }
1050 
1054  concurrency::streams::streambuf<CharType> streambuf() const
1055  {
1056  return helper()->m_buffer;
1057  }
1058 
1070  template<typename T>
1072  {
1073  pplx::task<T> result;
1074  if ( !_verify_and_return_task(details::_in_stream_msg, result) ) return result;
1075  return type_parser<CharType,T>::parse(helper()->m_buffer);
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 
1162  auto loop = pplx::details::do_while([=]() mutable -> pplx::task<bool>
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 
1179  return loop.then([=](pplx::task<bool> op)
1180  {
1181  op.wait();
1182  });
1183 }
1184 
1185 template<typename CharType>
1186 template<typename StateType, typename ReturnType, typename AcceptFunctor, typename ExtractFunctor>
1187 pplx::task<ReturnType> concurrency::streams::_type_parser_base<CharType>::_parse_input(
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 
1194  auto update = [=] (pplx::task<int_type> op) -> pplx::task<bool>
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 
1206  auto peek_char = [=]() -> pplx::task<bool>
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  {
1229  op.wait();
1230  pplx::task<ReturnType> result = extract(state);
1231  return result;
1232  };
1233 
1234  return _skip_whitespace(buffer).then([=](pplx::task<void> op) -> pplx::task<ReturnType>
1235  {
1236  op.wait();
1237  return pplx::details::do_while(peek_char).then(finish);
1238  });
1239 }
1240 
1241 template<typename CharType>
1242 class type_parser<CharType,std::basic_string<CharType>> : public _type_parser_base<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  }
1258  static pplx::task<std::basic_string<CharType>> _extract_result(std::shared_ptr<std::basic_string<CharType>> state)
1259  {
1260  return pplx::task_from_result(*state);
1261  }
1262 };
1263 
1264 template<typename CharType>
1265 class type_parser<CharType,int64_t> : public _type_parser_base<CharType>
1266 {
1267 public:
1268  typedef typename _type_parser_base<CharType>::int_type int_type;
1270  {
1271  return _type_parser_base<CharType>::template _parse_input<_int64_state, int64_t>(buffer, _accept_char, _extract_result);
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 
1327  static pplx::task<int64_t> _extract_result(std::shared_ptr<_int64_state> state)
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>
1462 static pplx::task<FloatingPoint> _extract_result(std::shared_ptr<_double_state<FloatingPoint>> state)
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>
1504 class type_parser<CharType,double> : public _type_parser_base<CharType>
1505 {
1506 public:
1507  typedef typename _type_parser_base<CharType>::int_type int_type;
1509  {
1510  return _type_parser_base<CharType>::template _parse_input<_double_state<double>, double>(buffer, _accept_char<double, int_type>, _extract_result<double>);
1511  }
1512 protected:
1513 };
1514 
1515 template<typename CharType>
1516 class type_parser<CharType,float> : public _type_parser_base<CharType>
1517 {
1518 public:
1519  typedef typename _type_parser_base<CharType>::int_type int_type;
1520  static pplx::task<float> parse(streams::streambuf<CharType> buffer)
1521  {
1522  return _type_parser_base<CharType>::template _parse_input<_double_state<float>, float>(buffer, _accept_char<float, int_type>, _extract_result<float>);
1523  }
1524 protected:
1525 };
1526 
1527 
1528 template<typename CharType>
1529 class type_parser<CharType,uint64_t> : public _type_parser_base<CharType>
1530 {
1531 public:
1532  typedef typename _type_parser_base<CharType>::int_type int_type;
1534  {
1535  return _type_parser_base<CharType>::template _parse_input<_uint64_state,uint64_t>(buffer, _accept_char, _extract_result);
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 
1560  static pplx::task<uint64_t> _extract_result(std::shared_ptr<_uint64_state> state)
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>
1569 class type_parser<CharType,bool> : public _type_parser_base<CharType>
1570 {
1571 public:
1572  typedef typename _type_parser_base<CharType>::int_type int_type;
1573  static pplx::task<bool> parse(streams::streambuf<CharType> buffer)
1574  {
1575  return _type_parser_base<CharType>::template _parse_input<_bool_state,bool>(buffer, _accept_char, _extract_result);
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>
1643 class type_parser<CharType,signed char> : public _type_parser_base<CharType>
1644 {
1645  typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
1646 public:
1648  {
1651  {
1652  op.wait();
1654  });
1655  }
1656 private:
1657  static pplx::task<signed char> _get_char(streams::streambuf<CharType> buffer)
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>
1672 class type_parser<CharType,unsigned char> : public _type_parser_base<CharType>
1673 {
1674  typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
1675 public:
1677  {
1680  {
1681  op.wait();
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>
1701 class type_parser<CharType,char> : public _type_parser_base<CharType>
1702 {
1703  typedef typename concurrency::streams::streambuf<CharType>::int_type int_type;
1704 public:
1705  static pplx::task<char> parse(streams::streambuf<CharType> buffer)
1706  {
1709  {
1710  op.wait();
1711  return _get_char(buffer);
1712  });
1713  }
1714 private:
1715  static pplx::task<char> _get_char(streams::streambuf<CharType> buffer)
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<>
1731 class type_parser<char,std::basic_string<wchar_t>> : public _type_parser_base<char>
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  }
1746  static pplx::task<std::basic_string<wchar_t>> _extract_result(std::shared_ptr<std::basic_string<char>> state)
1747  {
1748  return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state));
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:
1756  static pplx::task<std::wstring> parse(streams::streambuf<signed char> buffer)
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  }
1768  static pplx::task<std::basic_string<wchar_t>> _extract_result(std::shared_ptr<std::basic_string<char>> state)
1769  {
1770  return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state));
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:
1778  static pplx::task<std::wstring> parse(streams::streambuf<unsigned char> buffer)
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  }
1790  static pplx::task<std::basic_string<wchar_t>> _extract_result(std::shared_ptr<std::basic_string<char>> state)
1791  {
1792  return pplx::task_from_result(utility::conversions::utf8_to_utf16(*state));
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
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
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