// balxml_formatter_prettyimpl.h -*-C++-*- #ifndef INCLUDED_BALXML_FORMATTER_PRETTYIMPL #define INCLUDED_BALXML_FORMATTER_PRETTYIMPL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide pretty-printing implementation for 'balxml_formatter'. // //@CLASSES: // balxml::Formatter_PrettyImplState: state of formatter state machine // balxml::Formatter_PrettyImplStateId: labels for formatter state // balxml::Formatter_PrettyImplUtil: actions of formatter state machine // //@DESCRIPTION: This private, subordinate component to 'balxml_formatter' // provides an in-core value semantic attribute class, // 'balxml::Formatter_PrettyImplState', and a utility 'struct', // 'balxml::Formatter_PrettyImplUtil', that implements XML pretty-printing // operations using the state value type. These two classes work in // conjunction to implement a state machine for pretty-printing an XML document // given a sequence of tokens to emit. The class // 'balxml::Formatter_PrettyImplStateId' enumerates the set of labels for // distinct states of 'balxml::Formatter_PrettyImplState', upon which most // control-flow decisions of 'balxml::Formatter_PrettyImplUtil' are based. #include <balscm_version.h> #include <balxml_encoderoptions.h> #include <balxml_formatterwhitespacetype.h> #include <balxml_typesprintutil.h> #include <bdlma_localsequentialallocator.h> #include <bdlsb_memoutstreambuf.h> #include <bslma_stdallocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_nestedtraitdeclaration.h> #include <bsl_ios.h> #include <bsl_ostream.h> #include <bsl_string_view.h> #include <bsl_vector.h> namespace BloombergLP { namespace balxml { // ================================== // struct Formatter_PrettyImplStateId // ================================== struct Formatter_PrettyImplStateId { // This 'struct' provides a namespace for enumerating the set of labels for // distinct states of 'Formatter_PrettyImplState'. // TYPES enum Enum { e_AT_START, // This state indicates that the current write position of the // formatter is at the start of the document. The formatter is // only allowed to add an XML header when in this state. e_AFTER_START_NO_TAG, // This state indicates that the current write position of the // formatter is after some tokens have been emitted, such as an XML // header and/or some comments, but before any XML tags have been // emitted. The formatter is not allowed to emit an XML header // when in this state. e_IN_TAG, // This state indicates that the current write position of the // formatter is immediately after the name of an opening tag, or // otherwise immediately after the value of an attribute of an // opening tag. In this state, most token printing operations, // other than adding attributes, need to emit a ">" character to // close the currently open tag before emitting their content. For // example: //.. // 1| <someTag // `---------^ // // * Note that there is no '>' character yet //.. // or: //.. // 1| <someTag attr="value" otherAttr="42" // `-------------------------------------^ //.. e_FIRST_DATA_BETWEEN_TAGS, // This state indicates that the current write position of the // formatter is after a complete opening tag, before any data for // the tag, and that there are tokens already emitted on the // current line (i.e., that the current write position is not at // the start of the line). In this state, whether or not token // printing operations need to emit a new line and indentation // generally depends on the whitespace mode set for the // currently-open tag. Note that comments are not considered data. // For example: //.. // 1| <someTag> // `----------^ //.. // or: //.. // 1| <someTag> <!-- comment --> // `---------------------------^ //.. // or: //.. // 1| <someTag attr="value"> // 2| <!-- comment --> // `-------------------^ //.. e_FIRST_DATA_AT_LINE_BETWEEN_TAGS, // This state indicates that the current write position of the // formatter is at column 0 (i.e., that it is at the start of a new // line) and either 1) after a closing tag, or 2) after a complete // opening tag and optional data. In this state, most token // printing operations need to emit indentation before their // content. For example: //.. // 1| <someTag> // 2| // `^ //.. // or: //.. // 1| <someTag> // 2| </someTag> // 3| // `^ // // * Note that the 'closeElement' operation, which is used to // print closing tags, e.g., "</example>", *always* writes a // newline character after the closing tag. //.. // or: //.. // 1| <someTag> // 2| some list data // 3| some more list data // 4| // `^ //.. e_TRAILING_DATA_BETWEEN_TAGS, // This state indicates that the current write position of the // formatter is after one or more data tokens for the // currently-open tag, and that there are tokens already emitted on // the current line (i.e., that the current write position is not // at the start of a new line). In this state, data printing // operations must put delimiting whitespace before their data. // What whitespace they emit may depend on the whitespace mode of // the currently-open tag. For example: //.. // 1| <someTag> someData // `-------------------^ //.. // or //.. // 1| <someTag> // 2| some list data // 3| some more list data // `----------------------^ //.. e_AT_END // This state indicates that the current write position of the // formatter is immediately after the top-level closing tag of the // document. }; }; // =============================== // class Formatter_PrettyImplState // =============================== class Formatter_PrettyImplState { // This class provides an in-core, value-semantic attribute type that // maintains all of the state information needed to pretty-print an XML // document using the operations provided by 'Formatter_PrettyImplUtil'. public: // TYPES typedef bsl::allocator<char> allocator_type; typedef Formatter_PrettyImplStateId Id; typedef FormatterWhitespaceType WhitespaceType; private: // DATA Id::Enum d_id; // the canonical "state" in the state machine, upon which most // control-flow decisions are based when printing int d_indentLevel; // number of indentations to perform when printing an element on a new // line int d_spacesPerLevel; // number of spaces to print per level of indentation int d_column; // the current column number int d_wrapColumn; // the column number at which an element will be printed on the next // line and optionally indented depending on the requested whitespace // mode bsl::vector<WhitespaceType::Enum> d_elementNesting; // a stack of names of currently nested elements with the whitespace // handling constraint for each element in the stack public: // TRAITS BSLMF_NESTED_TRAIT_DECLARATION(Formatter_PrettyImplState, bslma::UsesBslmaAllocator); // CREATORS Formatter_PrettyImplState(); explicit Formatter_PrettyImplState(const allocator_type& allocator); // Create a 'Formatter_PrettyImplState' having an 'id' attribute of // 'Id::e_AT_START', 'indentLevel', 'spacesPerLevel', 'column', and // 'wrapColumn' attributes of 0, and an empty 'elementNesting' // attribute. Optionally specify an 'allocator' (e.g., the address of // a 'bslma::Allocator' object) to supply memory; otherwise, the // default allocator is used. Formatter_PrettyImplState( int indentLevel, int spacesPerLevel, int wrapColumn, const allocator_type& allocator = allocator_type()); // Create a 'Formatter_PrettyImplState' having an 'id' attribute of // 'Id::e_AT_START', the specified 'indentLevel', the specified // 'spacesPerLevel', and the specified 'wrapColumn', a 'column' // attribute of 0, and an empty 'elementNesting' attribute. Optionally // specify an 'allocator' (e.g., the address of a 'bslma::Allocator' // object) to supply memory; otherwise, the default allocator is used. Formatter_PrettyImplState( Id::Enum id, int indentLevel, int spacesPerLevel, int column, int wrapColumn, const bsl::vector<WhitespaceType::Enum>& elementNesting, const allocator_type& allocator = allocator_type()); // Create a 'Formatter_PrettyImplState' having the specified 'id', // 'indentLevel', 'spacesPerLevel', 'column', 'wrapColumn', and // 'elementNesting' attributes. Optionally specify an 'allocator' // (e.g., the address of a 'bslma::Allocator' object) to supply memory; // otherwise, the default allocator is used. Formatter_PrettyImplState( const Formatter_PrettyImplState& original, const allocator_type& allocator = allocator_type()); // Create a 'Formatter_PrettyImplState' object having the same value as // the specified 'original' object. Optionally specify an 'allocator' // (e.g., the address of a 'bslma::Allocator' object) to supply memory; // otherwise, the default allocator is used. // MANIPULATORS int& column(); // Return a reference providing modifiable access to the 'column' // attribute of this object. bsl::vector<WhitespaceType::Enum>& elementNesting(); // Return a reference providing modifiable access to the // 'elementNesting' attribute of this object. Id::Enum& id(); // Return a reference providing modifiable access to the 'id' attribute // of this object. int& indentLevel(); // Return a reference providing modifiable access to the 'indentLevel' // attribute of this object. int& spacesPerLevel(); // Return a reference providing modifiable access to the // 'spacesPerLevel' attribute of this object. int& wrapColumn(); // Return a reference providing modifiable access to the 'wrapColumn' // attribute of this object. // ACCESSORS const int& column() const; // Return a reference providing non-modifiable access to the 'column' // attribute of this object. const bsl::vector<WhitespaceType::Enum>& elementNesting() const ; // Return a reference providing non-modifiable access to the // 'elementNesting' attribute of this object. allocator_type get_allocator() const; // Return the allocator associated with this object. const Id::Enum& id() const; // Return a reference providing non-modifiable access to the 'id' // attribute of this object. const int& indentLevel() const; // Return a reference providing non-modifiable access to the // 'indentLevel' attribute of this object. const int& spacesPerLevel() const; // Return a reference providing non-modifiable access to the // 'spacesPerLevel' attribute of this object. const int& wrapColumn() const; // Return a reference providing non-modifiable access to the // 'wrapColumn' attribute of this object. }; // ============================== // class Formatter_PrettyImplUtil // ============================== struct Formatter_PrettyImplUtil { // This utility 'struct' provides a namespace for a suite of operations // used to pretty-print XML documents given a sequence of tokens to emit. // Together with 'Formatter_PrettyImplState', this 'struct' provides an // implementation of a state machine for such pretty-printing. // TYPES typedef Formatter_PrettyImplState State; typedef Formatter_PrettyImplStateId StateId; typedef FormatterWhitespaceType WhitespaceType; private: // PRIVATE TYPES enum { k_VALUE_STRING_BUFFER_SIZE = 256, k_INFINITE_WRAP_COLUMN = 0 }; typedef bdlma::LocalSequentialAllocator<k_VALUE_STRING_BUFFER_SIZE> BufferedAllocator; // PRIVATE CLASS METHODS static void addAttributeImpl(bsl::ostream& stream, State *state, const bsl::string_view& name, const bsl::string_view& value); // Add an attribute of the specified 'name' and 'value' to the // currently open element in the specified 'stream', with formatting // depending on the specified 'state', and update the 'state' // accordingly. Precede this name="value" pair with a single space. // Wrap line (write the attribute on next line with proper // indentation), if the length of name="value" is too long. 'value' is // truncated at any invalid UTF-8 byte-sequence or any control // character. The list of invalid control characters includes // characters in the range '[0x00, 0x20)' and '0x7F' (DEL) but does not // include '0x9', '0xA', and '0x0D'. The five special characters: // apostrophe, double quote, ampersand, less than, and greater than are // escaped in the output XML. The behavior is undefined unless the // last manipulator was 'openElement' or 'addAttribute'. static void addCommentImpl(bsl::ostream& stream, State *state, const bsl::string_view& comment, const bsl::string_view& openMarker, const bsl::string_view& closeMarker); // Write the specified 'openMarker', 'comment', and then 'closeMarker' // into the specified 'stream', with formatting depending on the // specified 'state', and update the 'state' accordingly. If an // element-opening tag is not completed with a '>', 'addCommentImpl' // will add '>'. static void addCommentOnNewLineImpl(bsl::ostream& stream, State *state, const bsl::string_view& comment, const bsl::string_view& openMarker, const bsl::string_view& closeMarker); // Write the specified 'openMarker', 'comment', and then 'closeMarker' // into the specified 'stream' on their own line, with formatting // depending on the specified 'state', and update the 'state' // accordingly. If an element-opening tag is not completed with a '>', // 'addCommentImpl' will add '>'. static void addDataImpl(bsl::ostream& stream, State *state, const bsl::string_view& value); static void addListDataImpl(bsl::ostream& stream, State *state, const bsl::string_view& value); // Add the specified 'value' as the data content to the specified // 'stream', with formatting depending on the specified 'state', and // update 'state' accordingly. 'addListData' prefixes the 'value' with // a space('0x20') unless the data being added is the first data on a // line. In the case of 'addData', perform no line-wrapping or // indentation as if the whitespace constraint were always // 'BAEXML_PRESERVE_WHITESPACE' in 'openElement', with the only // exception that an initial newline and an initial indent is added // when 'openElement' specifies 'BAEXML_NEWLINE_INDENT' option. In the // case of 'addListData', when adding the data makes the line too long, // perform line-wrapping and indentation as determined by the // whitespace constraint used when the current element is opened with // 'openElement'. 'value' is truncated at any invalid UTF-8 // byte-sequence or any control character. The list of invalid control // characters includes characters in the range '[0x00, 0x20)' and // '0x7F' (DEL) but does not include '0x9', '0xA', and '0x0D'. The // five special characters: apostrophe, double quote, ampersand, less // than, and greater than are escaped in the output XML. The behavior // is undefined if the call is made when there are no opened elements. public: // CLASS METHODS template <class VALUE_TYPE> static bsl::ostream& addAttribute( bsl::ostream& stream, State *state, const bsl::string_view& name, const VALUE_TYPE& value, int formattingMode = 0, const EncoderOptions& encoderOptions = EncoderOptions()); // Add an attribute of the specified 'name' and specified 'value' to // the currently open element in the specified 'stream', with // formatting depending on the specified 'state', and update the // 'state' accordingly. Return the 'stream'. 'value' can be of the // following types: 'char', 'short', 'int', 'bsls::Types::Int64', // 'float', 'double', 'bsl::string', 'bdlt::Datetime', 'bdlt::Date', // and 'bdlt::Time'. Precede this name="value" pair with a single // space. Wrap line (write the attribute on next line with proper // indentation), if the length of name="value" is too long. Optionally // specify 'formattingMode' and 'encoderOptions' to control the // formatting of 'value'. If 'value' is of type 'bsl::string', it is // truncated at any invalid UTF-8 byte-sequence or any control // character. The list of invalid control characters includes // characters in the range '[0x00, 0x20)' and '0x7F' (DEL) but does not // include '0x9', '0xA', and '0x0D'. The five special characters: // apostrophe, double quote, ampersand, less than, and greater than are // escaped in the output XML. If 'value' is of type 'char', it is cast // to a signed byte value with a range '[ -128 .. 127 ]'. The // behavior is undefined unless the last manipulator was 'openElement' // or 'addAttribute'. static bsl::ostream& addBlankLine(bsl::ostream& stream, State *state); // Insert one or two newline characters into the specified 'stream' // stream such that a blank line results, depending on the specified // 'state', and update the 'state' accordingly. Return the 'stream'. // If the last output was a newline, then only one newline is added, // otherwise two newlines are added. If following a call to // 'openElement', or 'addAttribute', add a closing '>' to the opened // tag. static bsl::ostream& addComment( bsl::ostream& stream, State *state, const bsl::string_view& comment, bool forceNewline = true); // !DEPRECATED!: Use 'addValidComment' instead. // // Write the specified 'comment' into the specified 'stream', with // formatting depending on the specified 'state', and update the // 'state' accordingly. Return the 'stream'. The optionally specified // 'forceNewline', if true, forces to start a new line solely for the // comment if it's not on a new line already. Otherwise, comments // continue on current line. If an element-opening tag is not // completed with a '>', 'addComment' will add '>'. template <class VALUE_TYPE> static bsl::ostream& addData( bsl::ostream& stream, State *state, const VALUE_TYPE& value, int formattingMode = 0, const EncoderOptions& encoderOptions = EncoderOptions()); // Add the specified 'value' as the data content to the specified // 'stream', with formatting depending on the specified 'state', and // update 'state' accordingly. Return the 'stream'. Return the // 'stream'. 'value' can be of the following types: 'char', 'short', // 'int', 'bsls::Types::Int64', 'float', 'double', 'bsl::string', // 'bdlt::Datetime', 'bdlt::Date', and 'bdlt::Time'. Perform no // line-wrapping or indentation as if the whitespace constraint were // always 'BAEXML_PRESERVE_WHITESPACE' in 'openElement', with the only // exception that an initial newline and an initial indent is added // when 'openElement' specifies 'BAEXML_NEWLINE_INDENT' option. If // 'value' is of type 'bsl::string', it is truncated at any invalid // UTF-8 byte-sequence or any control character. The list of invalid // control characters includes characters in the range '[0x00, 0x20)' // and '0x7F' (DEL) but does not include '0x9', '0xA', and '0x0D'. The // five special characters: apostrophe, double quote, ampersand, less // than, and greater than are escaped in the output XML. If 'value' is // of type 'char', it is cast to a signed byte value with a range of '[ // -128 .. 127 ]'. Optionally specify the 'formattingMode' and // 'encoderOptions' to specify the format used to encode 'value'. The // behavior is undefined if the call is made when there are no opened // elements. template <class TYPE> static bsl::ostream& addElementAndData( bsl::ostream& stream, State *state, const bsl::string_view& name, const TYPE& value, int formattingMode = 0, const EncoderOptions& encoderOptions = EncoderOptions()); // Add element of the specified 'name' and the specified 'value' as the // data content to the specified 'stream', with formatting depending on // the specified 'state' and the optionally specified 'encoderOptions', // and update 'state' accordingly. Return the 'stream'. This has the // same effect as calling the following sequence: 'openElement(name); // addData(value), closeElement(name);'. Optionally specify the // 'formattingMode'. static bsl::ostream& addHeader(bsl::ostream& stream, State *state, const bsl::string_view& encoding); // Add XML header with optionally specified 'encoding' to the specified // 'stream', with formatting depending on the specified 'state', and // update 'state' accordingly. Return the 'stream'. Version is always // "1.0". The behavior is undefined unless 'addHeader' is the first // manipulator (with the exception of 'rawOutputStream') after // construction or 'reset'. template <class VALUE_TYPE> static bsl::ostream& addListData( bsl::ostream& stream, State *state, const VALUE_TYPE& value, int formattingMode = 0, const EncoderOptions& encoderOptions = EncoderOptions()); // Add the specified 'value' as the data content to the specified // 'stream', with formatting depending on the specified 'state', and // update 'state' accordingly. Return the 'stream'. 'value' can be of // the following types: 'char', 'short', 'int', 'bsls::Types::Int64', // 'float', 'double', 'bsl::string', 'bdlt::Datetime', 'bdlt::Date', // and 'bdlt::Time'. Prefix the 'value' with a space('0x20') unless // the data being added is the first data on a line. When adding the // data makes the line too long, perform line-wrapping and indentation // as determined by the whitespace constraint used when the current // element is opened with 'openElement'. If 'value' is of type // 'bsl::string', it is truncated at any invalid UTF-8 byte-sequence or // any control character. The list of invalid control characters // includes characters in the range '[0x00, 0x20)' and '0x7F' (DEL) but // does not include '0x9', '0xA', and '0x0D'. The five special // characters: apostrophe, double quote, ampersand, less than, and // greater than are escaped in the output XML. If 'value' is of type // 'char', it is cast to a signed byte value with a range of '[ -128 .. // 127 ]'. Optionally specify the 'formattingMode' and // 'encoderOptions' to specify the format used to encode 'value'. The // behavior is undefined if the call is made when there are no opened // elements. static bsl::ostream& addNewline(bsl::ostream& stream, State *state); // Insert a literal newline into the XML output of the specified // 'stream', with formatting depending on the specified 'state', and // update 'state' accordingly. Return the 'stream'. If following a // call to 'openElement', or 'addAttribute', add a closing '>' to the // opened tag. static int addValidComment( bsl::ostream& stream, State *state, const bsl::string_view& comment, bool forceNewline = true, bool omitEnclosingWhitespace = false); // Write the specified 'comment' into the specified 'stream', with // formatting depending on the specified 'state', and update the // 'state' accordingly. If the optionally specified 'forceNewline' is // 'true' then a new line is inserted for comments not already on a new // line. Also optionally specify an 'omitEnclosingWhitespace' that // specifies if a space character should be omitted before and after // 'comment'. If 'omitEnclosingWhitespace' is not specified then a // space character is inserted before and after 'comment'. Return 0 on // success, and non-zero value otherwise. Note that a non-zero return // value is returned if either 'comment' contains '--' or if // 'omitEnclosingWhitespace' is 'true' and 'comment' ends with '-'. // Also note that if an element-opening tag is not completed with a // '>', 'addValidComment' will add '>'. static bsl::ostream& closeElement(bsl::ostream& stream, State *state, const bsl::string_view& name); // Decrement the indent level and add the closing tag for the element // of the specified 'name' to the specified 'stream', with formatting // depending on the specified 'state', and update 'state' accordingly. // Return the 'stream'. If the element does not have content, write // '/>' and a newline into stream. Otherwise, write '</name>' and a // newline. If this '</name>' does not share the same line with data, // or it follows another element's closing tag, indent properly before // writing '</name>' and the newline. If 'name' is root element, flush // the output stream. The behavior is undefined if 'name' is not the // most recently opened element that's yet to be closed. static bsl::ostream& flush(bsl::ostream& stream, State *state); // Insert the closing '>' if there is an incomplete tag, and flush the // specified output 'stream', with formatting depending on the // specified 'state', and update 'state' accordingly. Return the // 'stream'. static bsl::ostream& openElement(bsl::ostream& stream, State *state, const bsl::string_view& name, WhitespaceType::Enum whitespaceMode = WhitespaceType::e_PRESERVE_WHITESPACE); // Open an element of the specified 'name' at current indent level with // the optionally specified whitespace constraint 'whitespaceMode' for // its textual data to the specified 'stream', with formatting // depending on the specified 'state', and update 'state' accordingly, // incrementing the indent level. Return the 'stream'. // 'whitespaceMode' constrains how textual data is written with // 'addListData' for the current element, but not its nested elements. // The behavior is undefined if 'openElement' is called after the root // element is closed and there is no subsequent call to 'reset'. static void reset(State *state); // Reset the specified formatter 'state' such that it can be used to // format a new XML document as if the formatter were just constructed }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------------------- // class Formatter_PrettyImplState // ------------------------------- // CREATORS inline Formatter_PrettyImplState::Formatter_PrettyImplState() : d_id(Id::e_AT_START) , d_indentLevel(0) , d_spacesPerLevel(0) , d_column(0) , d_wrapColumn(0) , d_elementNesting() { } inline Formatter_PrettyImplState::Formatter_PrettyImplState( const allocator_type& allocator) : d_id(Id::e_AT_START) , d_indentLevel(0) , d_spacesPerLevel(0) , d_column(0) , d_wrapColumn(0) , d_elementNesting(allocator) { } inline Formatter_PrettyImplState::Formatter_PrettyImplState( const Formatter_PrettyImplState& original, const allocator_type& allocator) : d_id(original.d_id) , d_indentLevel(original.d_indentLevel) , d_spacesPerLevel(original.d_spacesPerLevel) , d_column(original.d_column) , d_wrapColumn(original.d_wrapColumn) , d_elementNesting(original.d_elementNesting, allocator) { } inline Formatter_PrettyImplState::Formatter_PrettyImplState( int indentLevel, int spacesPerLevel, int wrapColumn, const allocator_type& allocator) : d_id(Id::e_AT_START) , d_indentLevel(indentLevel) , d_spacesPerLevel(spacesPerLevel) , d_column() , d_wrapColumn(wrapColumn) , d_elementNesting(allocator) { } inline Formatter_PrettyImplState::Formatter_PrettyImplState( Id::Enum id, int indentLevel, int spacesPerLevel, int column, int wrapColumn, const bsl::vector<WhitespaceType::Enum>& elementNesting, const allocator_type& allocator) : d_id(id) , d_indentLevel(indentLevel) , d_spacesPerLevel(spacesPerLevel) , d_column(column) , d_wrapColumn(wrapColumn) , d_elementNesting(elementNesting, allocator) { } // MANIPULATORS inline int& Formatter_PrettyImplState::column() { return d_column; } inline bsl::vector<FormatterWhitespaceType::Enum>& Formatter_PrettyImplState::elementNesting() { return d_elementNesting; } inline Formatter_PrettyImplStateId::Enum& Formatter_PrettyImplState::id() { return d_id; } inline int& Formatter_PrettyImplState::indentLevel() { return d_indentLevel; } inline int& Formatter_PrettyImplState::spacesPerLevel() { return d_spacesPerLevel; } inline int& Formatter_PrettyImplState::wrapColumn() { return d_wrapColumn; } // ACCESSORS inline const int& Formatter_PrettyImplState::column() const { return d_column; } inline const bsl::vector<FormatterWhitespaceType::Enum>& Formatter_PrettyImplState::elementNesting() const { return d_elementNesting; } inline Formatter_PrettyImplState::allocator_type Formatter_PrettyImplState::get_allocator() const { return d_elementNesting.get_allocator(); } inline const Formatter_PrettyImplStateId::Enum& Formatter_PrettyImplState::id() const { return d_id; } inline const int& Formatter_PrettyImplState::indentLevel() const { return d_indentLevel; } inline const int& Formatter_PrettyImplState::spacesPerLevel() const { return d_spacesPerLevel; } inline const int& Formatter_PrettyImplState::wrapColumn() const { return d_wrapColumn; } // ------------------------------ // class Formatter_PrettyImplUtil // ------------------------------ // CLASS METHODS template <class VALUE_TYPE> bsl::ostream& Formatter_PrettyImplUtil::addAttribute( bsl::ostream& stream, State *state, const bsl::string_view& name, const VALUE_TYPE& value, int formattingMode, const EncoderOptions& encoderOptions) { BufferedAllocator allocator; bdlsb::MemOutStreamBuf sb(&allocator); bsl::ostream ss(&sb); TypesPrintUtil::print(ss, value, formattingMode, &encoderOptions); if (!ss.good()) { stream.setstate(bsl::ios_base::failbit); return stream; // RETURN } const bsl::string_view valueString(sb.data(), sb.length()); addAttributeImpl(stream, state, name, valueString); return stream; } template <class VALUE_TYPE> bsl::ostream& Formatter_PrettyImplUtil::addData( bsl::ostream& stream, State *state, const VALUE_TYPE& valueData, int formattingMode, const EncoderOptions& encoderOptions) { BufferedAllocator allocator; bdlsb::MemOutStreamBuf sb(&allocator); bsl::ostream ss(&sb); TypesPrintUtil::print(ss, valueData, formattingMode, &encoderOptions); if (!ss.good()) { stream.setstate(bsl::ios_base::failbit); return stream; // RETURN } const bsl::string_view valueString(sb.data(), sb.length()); addDataImpl(stream, state, valueString); return stream; } template <class TYPE> bsl::ostream& Formatter_PrettyImplUtil::addElementAndData( bsl::ostream& stream, State *state, const bsl::string_view& name, const TYPE& value, int formattingMode, const EncoderOptions& encoderOptions) { openElement(stream, state, name, WhitespaceType::e_PRESERVE_WHITESPACE); addData(stream, state, value, formattingMode, encoderOptions); closeElement(stream, state, name); return stream; } template <class VALUE_TYPE> bsl::ostream& Formatter_PrettyImplUtil::addListData( bsl::ostream& stream, State *state, const VALUE_TYPE& value, int formattingMode, const EncoderOptions& encoderOptions) { BufferedAllocator allocator; bdlsb::MemOutStreamBuf sb(&allocator); bsl::ostream ss(&sb); TypesPrintUtil::print(ss, value, formattingMode, &encoderOptions); if (!ss.good()) { stream.setstate(bsl::ios_base::failbit); return stream; // RETURN } const bsl::string_view valueString(sb.data(), sb.length()); addListDataImpl(stream, state, valueString); return stream; } inline void Formatter_PrettyImplUtil::reset(State *state) { state->column() = 0; state->id() = StateId::e_AT_START; state->indentLevel() -= static_cast<int>(state->elementNesting().size()); state->elementNesting().clear(); } } // close package namespace } // close enterprise namespace #endif // INCLUDED_BALXML_FORMATTER_PRETTYIMPL // ---------------------------------------------------------------------------- // Copyright 2021 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------