Home | History | Annotate | Download | only in performanced
      1 // Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
      2 // Copyright (c) 2016 Google, Inc.
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #ifndef ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_
     23 #define ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_
     24 
     25 #include <cstdio>
     26 #include <istream>
     27 #include <locale>
     28 #include <streambuf>
     29 
     30 namespace android {
     31 namespace dvr {
     32 
     33 // An implementation of std::basic_streambuf backed by a FILE pointer. This is
     34 // ported from the internal llvm-libc++ support for std::cin. It's really
     35 // unfortunate that we have to do this, but the C++11 standard is too pendantic
     36 // to support creating streams from file descriptors or FILE pointers. This
     37 // implementation uses all standard interfaces, except for the call to
     38 // std::__throw_runtime_error(), which is only needed to deal with exceeding
     39 // locale encoding limits. This class is meant to be used for reading system
     40 // files, which don't require exotic locale support, so this call could be
     41 // removed in the future, if necessary.
     42 //
     43 // Original source file: llvm-libcxx/llvm-libc++/include/__std_stream
     44 // Original class name: __stdinbuf
     45 //
     46 template <class _CharT>
     47 class stdio_filebuf
     48     : public std::basic_streambuf<_CharT, std::char_traits<_CharT> > {
     49  public:
     50   typedef _CharT char_type;
     51   typedef std::char_traits<char_type> traits_type;
     52   typedef typename traits_type::int_type int_type;
     53   typedef typename traits_type::pos_type pos_type;
     54   typedef typename traits_type::off_type off_type;
     55   typedef typename traits_type::state_type state_type;
     56 
     57   explicit stdio_filebuf(FILE* __fp);
     58   ~stdio_filebuf() override;
     59 
     60  protected:
     61   virtual int_type underflow() override;
     62   virtual int_type uflow() override;
     63   virtual int_type pbackfail(int_type __c = traits_type::eof()) override;
     64   virtual void imbue(const std::locale& __loc) override;
     65 
     66  private:
     67   FILE* __file_;
     68   const std::codecvt<char_type, char, state_type>* __cv_;
     69   state_type __st_;
     70   int __encoding_;
     71   int_type __last_consumed_;
     72   bool __last_consumed_is_next_;
     73   bool __always_noconv_;
     74 
     75   stdio_filebuf(const stdio_filebuf&);
     76   stdio_filebuf& operator=(const stdio_filebuf&);
     77 
     78   int_type __getchar(bool __consume);
     79 
     80   static const int __limit = 8;
     81 };
     82 
     83 template <class _CharT>
     84 stdio_filebuf<_CharT>::stdio_filebuf(FILE* __fp)
     85     : __file_(__fp),
     86       __last_consumed_(traits_type::eof()),
     87       __last_consumed_is_next_(false) {
     88   imbue(this->getloc());
     89 }
     90 
     91 template <class _CharT>
     92 stdio_filebuf<_CharT>::~stdio_filebuf() {
     93   if (__file_)
     94     fclose(__file_);
     95 }
     96 
     97 template <class _CharT>
     98 void stdio_filebuf<_CharT>::imbue(const std::locale& __loc) {
     99   __cv_ = &std::use_facet<std::codecvt<char_type, char, state_type> >(__loc);
    100   __encoding_ = __cv_->encoding();
    101   __always_noconv_ = __cv_->always_noconv();
    102   if (__encoding_ > __limit)
    103     std::__throw_runtime_error("unsupported locale for standard io");
    104 }
    105 
    106 template <class _CharT>
    107 typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::underflow() {
    108   return __getchar(false);
    109 }
    110 
    111 template <class _CharT>
    112 typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::uflow() {
    113   return __getchar(true);
    114 }
    115 
    116 template <class _CharT>
    117 typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::__getchar(
    118     bool __consume) {
    119   if (__last_consumed_is_next_) {
    120     int_type __result = __last_consumed_;
    121     if (__consume) {
    122       __last_consumed_ = traits_type::eof();
    123       __last_consumed_is_next_ = false;
    124     }
    125     return __result;
    126   }
    127   char __extbuf[__limit];
    128   int __nread = std::max(1, __encoding_);
    129   for (int __i = 0; __i < __nread; ++__i) {
    130     int __c = getc(__file_);
    131     if (__c == EOF)
    132       return traits_type::eof();
    133     __extbuf[__i] = static_cast<char>(__c);
    134   }
    135   char_type __1buf;
    136   if (__always_noconv_)
    137     __1buf = static_cast<char_type>(__extbuf[0]);
    138   else {
    139     const char* __enxt;
    140     char_type* __inxt;
    141     std::codecvt_base::result __r;
    142     do {
    143       state_type __sv_st = __st_;
    144       __r = __cv_->in(__st_, __extbuf, __extbuf + __nread, __enxt, &__1buf,
    145                       &__1buf + 1, __inxt);
    146       switch (__r) {
    147         case std::codecvt_base::ok:
    148           break;
    149         case std::codecvt_base::partial:
    150           __st_ = __sv_st;
    151           if (__nread == sizeof(__extbuf))
    152             return traits_type::eof();
    153           {
    154             int __c = getc(__file_);
    155             if (__c == EOF)
    156               return traits_type::eof();
    157             __extbuf[__nread] = static_cast<char>(__c);
    158           }
    159           ++__nread;
    160           break;
    161         case std::codecvt_base::error:
    162           return traits_type::eof();
    163         case std::codecvt_base::noconv:
    164           __1buf = static_cast<char_type>(__extbuf[0]);
    165           break;
    166       }
    167     } while (__r == std::codecvt_base::partial);
    168   }
    169   if (!__consume) {
    170     for (int __i = __nread; __i > 0;) {
    171       if (ungetc(traits_type::to_int_type(__extbuf[--__i]), __file_) == EOF)
    172         return traits_type::eof();
    173     }
    174   } else
    175     __last_consumed_ = traits_type::to_int_type(__1buf);
    176   return traits_type::to_int_type(__1buf);
    177 }
    178 
    179 template <class _CharT>
    180 typename stdio_filebuf<_CharT>::int_type stdio_filebuf<_CharT>::pbackfail(
    181     int_type __c) {
    182   if (traits_type::eq_int_type(__c, traits_type::eof())) {
    183     if (!__last_consumed_is_next_) {
    184       __c = __last_consumed_;
    185       __last_consumed_is_next_ =
    186           !traits_type::eq_int_type(__last_consumed_, traits_type::eof());
    187     }
    188     return __c;
    189   }
    190   if (__last_consumed_is_next_) {
    191     char __extbuf[__limit];
    192     char* __enxt;
    193     const char_type __ci = traits_type::to_char_type(__last_consumed_);
    194     const char_type* __inxt;
    195     switch (__cv_->out(__st_, &__ci, &__ci + 1, __inxt, __extbuf,
    196                        __extbuf + sizeof(__extbuf), __enxt)) {
    197       case std::codecvt_base::ok:
    198         break;
    199       case std::codecvt_base::noconv:
    200         __extbuf[0] = static_cast<char>(__last_consumed_);
    201         __enxt = __extbuf + 1;
    202         break;
    203       case std::codecvt_base::partial:
    204       case std::codecvt_base::error:
    205         return traits_type::eof();
    206     }
    207     while (__enxt > __extbuf)
    208       if (ungetc(*--__enxt, __file_) == EOF)
    209         return traits_type::eof();
    210   }
    211   __last_consumed_ = __c;
    212   __last_consumed_is_next_ = true;
    213   return __c;
    214 }
    215 
    216 }  // namespace dvr
    217 }  // namespace android
    218 
    219 #endif  // ANDROID_DVR_PERFORMANCED_STDIO_FILEBUF_H_
    220