LCOV - code coverage report
Current view: top level - boost/beast2 - format.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 97.7 % 86 84
Test Date: 2025-12-24 17:07:59 Functions: 64.3 % 42 27

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/beast2
       8              : //
       9              : 
      10              : #ifndef BOOST_BEAST2_FORMAT_HPP
      11              : #define BOOST_BEAST2_FORMAT_HPP
      12              : 
      13              : #include <boost/beast2/detail/config.hpp>
      14              : #include <boost/beast2/detail/except.hpp>
      15              : #include <boost/core/detail/string_view.hpp>
      16              : 
      17              : #include <memory>
      18              : #include <ostream>
      19              : #include <streambuf>
      20              : #include <string>
      21              : 
      22              : namespace boost {
      23              : namespace beast2 {
      24              : 
      25              : namespace detail {
      26              : 
      27              : struct format_impl
      28              : {
      29              :     std::ostream& os;
      30              :     core::string_view fs;
      31              :     char const* p;
      32              :     char const* p0;
      33              :     char const* end;
      34              :     bool has_placeholder = false;
      35              : 
      36           27 :     format_impl(
      37              :         std::ostream& os_,
      38              :         core::string_view fs_)
      39           27 :         : os(os_)
      40           27 :         , fs(fs_)
      41           27 :         , p(fs.data())
      42           27 :         , p0(p)
      43           27 :         , end(p + fs.size())
      44              :     {
      45           27 :     }
      46              : 
      47              :     core::string_view
      48           57 :     next()
      49              :     {
      50           57 :         has_placeholder = false;
      51           57 :         bool unmatched_open = false;
      52           57 :         bool unmatched_close = false;
      53          116 :         while (p != end)
      54              :         {
      55           85 :             if(unmatched_open)
      56              :             {
      57           18 :                 if(*p == '{')
      58              :                 {
      59            5 :                     p++;
      60            5 :                     core::string_view seg(p0, (p - 1) - p0);
      61            5 :                     p0 = p;
      62            5 :                     return seg;
      63              :                 }
      64           13 :                 if(*p == '}')
      65              :                 {
      66           13 :                     p++;
      67           13 :                     core::string_view seg(p0, (p - 2) - p0);
      68           13 :                     p0 = p;
      69           13 :                     has_placeholder = true;
      70           13 :                     return seg;
      71              :                 }
      72            0 :                 detail::throw_invalid_argument(
      73              :                     "invalid format string, unmatched {");
      74              :             }
      75           67 :             if(unmatched_close)
      76              :             {
      77            8 :                 if(*p == '}')
      78              :                 {
      79            5 :                     p++;
      80            5 :                     core::string_view seg(p0, (p - 1) - p0);
      81            5 :                     p0 = p;
      82            5 :                     return seg;
      83              :                 }
      84            3 :                 detail::throw_invalid_argument(
      85              :                     "invalid format string, unmatched }");
      86              :             }
      87           59 :             if (*p == '{')
      88              :             {
      89           21 :                 unmatched_open = true;
      90              :             }
      91           59 :             if(*p == '}')
      92              :             {
      93           11 :                 unmatched_close = true;
      94              :             }
      95           59 :             p++;
      96              :         }
      97           31 :         if (unmatched_open)
      98            3 :             detail::throw_invalid_argument(
      99              :                 "invalid format string, unmatched {");
     100           28 :         if(unmatched_close)
     101            3 :             detail::throw_invalid_argument(
     102              :                 "invalid format string, unmatched }");
     103              : 
     104              :         core::string_view seg(
     105           25 :             p0, end - p0);
     106           25 :         p0 = end;
     107           25 :         return seg;
     108              :     }
     109              : 
     110              :     template<class Arg>
     111           20 :     void do_arg(Arg const& arg)
     112              :     {
     113           20 :         core::string_view seg = next();
     114           19 :         while(seg.size())
     115              :         {
     116           12 :             os.write(seg.data(), static_cast<std::streamsize>(seg.size()));
     117           12 :             if(has_placeholder)
     118            7 :                 break;
     119            5 :             seg = next();
     120              :         }
     121           14 :         if(has_placeholder)
     122           10 :             os << arg;
     123           14 :     };
     124              : 
     125              :     template<class... Args>
     126           27 :     void operator()(Args const&... args)
     127              :     {
     128              :         using expander = int[];
     129           27 :         (void)expander{0, (do_arg(args), 0)...};
     130              : 
     131           21 :         core::string_view seg;
     132              :         do
     133              :         {
     134           32 :             seg = next();
     135           29 :             if(has_placeholder)
     136            3 :                 detail::throw_invalid_argument(
     137              :                     "too few format arguments provided");
     138           26 :             if(seg.size())
     139           11 :                 os.write(seg.data(), static_cast<std::streamsize>(seg.size()));
     140              :         }
     141           26 :         while(seg.size());
     142           15 :     }
     143              : };
     144              : 
     145              : class appendbuf : public std::streambuf
     146              : {
     147              :     std::string* s_;
     148              : 
     149              : protected:
     150              :     // Called when a single character is to be written
     151            1 :     virtual int_type overflow(int_type ch) override
     152              :     {
     153            1 :         if (ch != traits_type::eof())
     154              :         {
     155            1 :             s_->push_back(static_cast<char>(ch));
     156            1 :             return ch;
     157              :         }
     158            0 :         return traits_type::eof();
     159              :     }
     160              : 
     161              :     // Called when multiple characters are to be written
     162           32 :     virtual std::streamsize xsputn(const char* s, std::streamsize n) override
     163              :     {
     164           32 :         s_->append(s, static_cast<std::size_t>(n));
     165           32 :         return n;
     166              :     }
     167              : 
     168              : public:
     169           27 :     explicit appendbuf(std::string& s)
     170           27 :         : s_(&s)
     171              :     {
     172           27 :     }
     173              : };
     174              : 
     175              : class appendstream : public std::ostream
     176              : {
     177              :     appendbuf buf_;
     178              : 
     179              : public:
     180           27 :     explicit appendstream(std::string& s)
     181           27 :         : std::ostream(&buf_)
     182           27 :         , buf_(s)
     183              :     {
     184           27 :     }
     185              : };
     186              : 
     187              : } // detail
     188              : 
     189              : /** Format arguments using a format string
     190              : */
     191              : template<class... Args>
     192              : void
     193           27 : format_to(
     194              :     std::ostream& os,
     195              :     core::string_view fs,
     196              :     Args const&... args)
     197              : {
     198           27 :     detail::format_impl(os, fs)(args...);
     199           15 : }
     200              : 
     201              : /** Format arguments using a format string
     202              : */
     203              : template<class... Args>
     204              : void
     205           27 : format_to(
     206              :     std::string& dest,
     207              :     core::string_view fs,
     208              :     Args const&... args)
     209              : {
     210           27 :     detail::appendstream ss(dest);
     211           27 :     format_to(ss, fs, args...);
     212           27 : }
     213              : 
     214              : } // beast2
     215              : } // boost
     216              : 
     217              : #endif
        

Generated by: LCOV version 2.1