Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:53:29

0001 
0002 //              Copyright Catch2 Authors
0003 // Distributed under the Boost Software License, Version 1.0.
0004 //   (See accompanying file LICENSE.txt or copy at
0005 //        https://www.boost.org/LICENSE_1_0.txt)
0006 
0007 // SPDX-License-Identifier: BSL-1.0
0008 #ifndef CATCH_TEXTFLOW_HPP_INCLUDED
0009 #define CATCH_TEXTFLOW_HPP_INCLUDED
0010 
0011 #include <catch2/internal/catch_console_width.hpp>
0012 #include <catch2/internal/catch_move_and_forward.hpp>
0013 
0014 #include <cassert>
0015 #include <string>
0016 #include <vector>
0017 
0018 namespace Catch {
0019     namespace TextFlow {
0020 
0021         class Columns;
0022 
0023         /**
0024          * Abstraction for a string with ansi escape sequences that
0025          * automatically skips over escapes when iterating. Only graphical
0026          * escape sequences are considered.
0027          *
0028          * Internal representation:
0029          * An escape sequence looks like \033[39;49m
0030          * We need bidirectional iteration and the unbound length of escape
0031          * sequences poses a problem for operator-- To make this work we'll
0032          * replace the last `m` with a 0xff (this is a codepoint that won't have
0033          * any utf-8 meaning).
0034          */
0035         class AnsiSkippingString {
0036             std::string m_string;
0037             std::size_t m_size = 0;
0038 
0039             // perform 0xff replacement and calculate m_size
0040             void preprocessString();
0041 
0042         public:
0043             class const_iterator;
0044             using iterator = const_iterator;
0045             // note: must be u-suffixed or this will cause a "truncation of
0046             // constant value" warning on MSVC
0047             static constexpr char sentinel = static_cast<char>( 0xffu );
0048 
0049             explicit AnsiSkippingString( std::string const& text );
0050             explicit AnsiSkippingString( std::string&& text );
0051 
0052             const_iterator begin() const;
0053             const_iterator end() const;
0054 
0055             size_t size() const { return m_size; }
0056 
0057             std::string substring( const_iterator begin,
0058                                    const_iterator end ) const;
0059         };
0060 
0061         class AnsiSkippingString::const_iterator {
0062             friend AnsiSkippingString;
0063             struct EndTag {};
0064 
0065             const std::string* m_string;
0066             std::string::const_iterator m_it;
0067 
0068             explicit const_iterator( const std::string& string, EndTag ):
0069                 m_string( &string ), m_it( string.end() ) {}
0070 
0071             void tryParseAnsiEscapes();
0072             void advance();
0073             void unadvance();
0074 
0075         public:
0076             using difference_type = std::ptrdiff_t;
0077             using value_type = char;
0078             using pointer = value_type*;
0079             using reference = value_type&;
0080             using iterator_category = std::bidirectional_iterator_tag;
0081 
0082             explicit const_iterator( const std::string& string ):
0083                 m_string( &string ), m_it( string.begin() ) {
0084                 tryParseAnsiEscapes();
0085             }
0086 
0087             char operator*() const { return *m_it; }
0088 
0089             const_iterator& operator++() {
0090                 advance();
0091                 return *this;
0092             }
0093             const_iterator operator++( int ) {
0094                 iterator prev( *this );
0095                 operator++();
0096                 return prev;
0097             }
0098             const_iterator& operator--() {
0099                 unadvance();
0100                 return *this;
0101             }
0102             const_iterator operator--( int ) {
0103                 iterator prev( *this );
0104                 operator--();
0105                 return prev;
0106             }
0107 
0108             bool operator==( const_iterator const& other ) const {
0109                 return m_it == other.m_it;
0110             }
0111             bool operator!=( const_iterator const& other ) const {
0112                 return !operator==( other );
0113             }
0114             bool operator<=( const_iterator const& other ) const {
0115                 return m_it <= other.m_it;
0116             }
0117 
0118             const_iterator oneBefore() const {
0119                 auto it = *this;
0120                 return --it;
0121             }
0122         };
0123 
0124         /**
0125          * Represents a column of text with specific width and indentation
0126          *
0127          * When written out to a stream, it will perform linebreaking
0128          * of the provided text so that the written lines fit within
0129          * target width.
0130          */
0131         class Column {
0132             // String to be written out
0133             AnsiSkippingString m_string;
0134             // Width of the column for linebreaking
0135             size_t m_width = CATCH_CONFIG_CONSOLE_WIDTH - 1;
0136             // Indentation of other lines (including first if initial indent is
0137             // unset)
0138             size_t m_indent = 0;
0139             // Indentation of the first line
0140             size_t m_initialIndent = std::string::npos;
0141 
0142         public:
0143             /**
0144              * Iterates "lines" in `Column` and returns them
0145              */
0146             class const_iterator {
0147                 friend Column;
0148                 struct EndTag {};
0149 
0150                 Column const& m_column;
0151                 // Where does the current line start?
0152                 AnsiSkippingString::const_iterator m_lineStart;
0153                 // How long should the current line be?
0154                 AnsiSkippingString::const_iterator m_lineEnd;
0155                 // How far have we checked the string to iterate?
0156                 AnsiSkippingString::const_iterator m_parsedTo;
0157                 // Should a '-' be appended to the line?
0158                 bool m_addHyphen = false;
0159 
0160                 const_iterator( Column const& column, EndTag ):
0161                     m_column( column ),
0162                     m_lineStart( m_column.m_string.end() ),
0163                     m_lineEnd( column.m_string.end() ),
0164                     m_parsedTo( column.m_string.end() ) {}
0165 
0166                 // Calculates the length of the current line
0167                 void calcLength();
0168 
0169                 // Returns current indentation width
0170                 size_t indentSize() const;
0171 
0172                 // Creates an indented and (optionally) suffixed string from
0173                 // current iterator position, indentation and length.
0174                 std::string addIndentAndSuffix(
0175                     AnsiSkippingString::const_iterator start,
0176                     AnsiSkippingString::const_iterator end ) const;
0177 
0178             public:
0179                 using difference_type = std::ptrdiff_t;
0180                 using value_type = std::string;
0181                 using pointer = value_type*;
0182                 using reference = value_type&;
0183                 using iterator_category = std::forward_iterator_tag;
0184 
0185                 explicit const_iterator( Column const& column );
0186 
0187                 std::string operator*() const;
0188 
0189                 const_iterator& operator++();
0190                 const_iterator operator++( int );
0191 
0192                 bool operator==( const_iterator const& other ) const {
0193                     return m_lineStart == other.m_lineStart &&
0194                            &m_column == &other.m_column;
0195                 }
0196                 bool operator!=( const_iterator const& other ) const {
0197                     return !operator==( other );
0198                 }
0199             };
0200             using iterator = const_iterator;
0201 
0202             explicit Column( std::string const& text ): m_string( text ) {}
0203             explicit Column( std::string&& text ):
0204                 m_string( CATCH_MOVE( text ) ) {}
0205 
0206             Column& width( size_t newWidth ) & {
0207                 assert( newWidth > 0 );
0208                 m_width = newWidth;
0209                 return *this;
0210             }
0211             Column&& width( size_t newWidth ) && {
0212                 assert( newWidth > 0 );
0213                 m_width = newWidth;
0214                 return CATCH_MOVE( *this );
0215             }
0216             Column& indent( size_t newIndent ) & {
0217                 m_indent = newIndent;
0218                 return *this;
0219             }
0220             Column&& indent( size_t newIndent ) && {
0221                 m_indent = newIndent;
0222                 return CATCH_MOVE( *this );
0223             }
0224             Column& initialIndent( size_t newIndent ) & {
0225                 m_initialIndent = newIndent;
0226                 return *this;
0227             }
0228             Column&& initialIndent( size_t newIndent ) && {
0229                 m_initialIndent = newIndent;
0230                 return CATCH_MOVE( *this );
0231             }
0232 
0233             size_t width() const { return m_width; }
0234             const_iterator begin() const { return const_iterator( *this ); }
0235             const_iterator end() const {
0236                 return { *this, const_iterator::EndTag{} };
0237             }
0238 
0239             friend std::ostream& operator<<( std::ostream& os,
0240                                              Column const& col );
0241 
0242             friend Columns operator+( Column const& lhs, Column const& rhs );
0243             friend Columns operator+( Column&& lhs, Column&& rhs );
0244         };
0245 
0246         //! Creates a column that serves as an empty space of specific width
0247         Column Spacer( size_t spaceWidth );
0248 
0249         class Columns {
0250             std::vector<Column> m_columns;
0251 
0252         public:
0253             class iterator {
0254                 friend Columns;
0255                 struct EndTag {};
0256 
0257                 std::vector<Column> const& m_columns;
0258                 std::vector<Column::const_iterator> m_iterators;
0259                 size_t m_activeIterators;
0260 
0261                 iterator( Columns const& columns, EndTag );
0262 
0263             public:
0264                 using difference_type = std::ptrdiff_t;
0265                 using value_type = std::string;
0266                 using pointer = value_type*;
0267                 using reference = value_type&;
0268                 using iterator_category = std::forward_iterator_tag;
0269 
0270                 explicit iterator( Columns const& columns );
0271 
0272                 auto operator==( iterator const& other ) const -> bool {
0273                     return m_iterators == other.m_iterators;
0274                 }
0275                 auto operator!=( iterator const& other ) const -> bool {
0276                     return m_iterators != other.m_iterators;
0277                 }
0278                 std::string operator*() const;
0279                 iterator& operator++();
0280                 iterator operator++( int );
0281             };
0282             using const_iterator = iterator;
0283 
0284             iterator begin() const { return iterator( *this ); }
0285             iterator end() const { return { *this, iterator::EndTag() }; }
0286 
0287             friend Columns& operator+=( Columns& lhs, Column const& rhs );
0288             friend Columns& operator+=( Columns& lhs, Column&& rhs );
0289             friend Columns operator+( Columns const& lhs, Column const& rhs );
0290             friend Columns operator+( Columns&& lhs, Column&& rhs );
0291 
0292             friend std::ostream& operator<<( std::ostream& os,
0293                                              Columns const& cols );
0294         };
0295 
0296     } // namespace TextFlow
0297 } // namespace Catch
0298 #endif // CATCH_TEXTFLOW_HPP_INCLUDED