// baljsn_printutil.h -*-C++-*- #ifndef INCLUDED_BALJSN_PRINTUTIL #define INCLUDED_BALJSN_PRINTUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a utility for encoding simple types in the JSON format. // //@CLASSES: // baljsn::PrintUtil: utility for printing simple types in JSON // //@SEE_ALSO: baljsn_encoder, baljsn_parserutil // //@DESCRIPTION: This component provides a 'struct' of utility functions, // 'baljsn::PrintUtil', for encoding a 'bdeat' Simple type in the JSON format. // The primary method is 'printValue', which encodes a specified object and is // overloaded for all 'bdeat' Simple types. The following table describes the // format in which various Simple types are encoded. // // Refer to the details of the JSON encoding format supported by this utility // in the package documentation file (doc/baljsn.txt). // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Encoding a Simple 'struct' into JSON ///----------------------------------------------- // Suppose we want to serialize some data into JSON. // // First, we define a struct, 'Employee', to contain the data: //.. // struct Employee { // const char *d_firstName; // const char *d_lastName; // int d_age; // }; //.. // Then, we create an 'Employee' object and populate it with data: //.. // Employee john; // john.d_firstName = "John"; // john.d_lastName = "Doe"; // john.d_age = 20; //.. // Now, we create an output stream and manually construct the JSON string // using 'baljsn::PrintUtil': //.. // bsl::ostringstream oss; // oss << '{' << '\n'; // baljsn::PrintUtil::printValue(oss, "firstName"); // oss << ':'; // baljsn::PrintUtil::printValue(oss, john.d_firstName); // oss << ',' << '\n'; // baljsn::PrintUtil::printValue(oss, "lastName"); // oss << ':'; // baljsn::PrintUtil::printValue(oss, john.d_lastName); // oss << ',' << '\n'; // baljsn::PrintUtil::printValue(oss, "age"); // oss << ':'; // baljsn::PrintUtil::printValue(oss, john.d_age); // oss << '\n' << '}'; //.. // Finally, we print out the JSON string: //.. // if (verbose) { // bsl::cout << oss.str(); // } //.. // The output should look like: //.. // { // "firstName":"John", // "lastName":"Doe", // "age":20 // } //.. #include <balscm_version.h> #include <baljsn_encoderoptions.h> #include <bdlb_float.h> #include <bdlb_variant.h> #include <bdldfp_decimal.h> #include <bdldfp_decimalconvertutil.h> #include <bdldfp_decimalutil.h> #include <bdljsn_stringutil.h> #include <bdlt_datetimeinterval.h> #include <bdlt_iso8601util.h> #include <bslalg_numericformatterutil.h> #include <bsls_platform.h> #include <bsls_types.h> #include <bsl_c_stdio.h> #include <bsl_cmath.h> #include <bsl_iomanip.h> #include <bsl_ios.h> #include <bsl_limits.h> #include <bsl_ostream.h> #include <bsl_string.h> #include <bsl_string_view.h> namespace BloombergLP { namespace baljsn { // =============== // class PrintUtil // =============== struct PrintUtil { // This 'struct' provides functions for printing objects to output streams // in JSON format. private: // PRIVATE CLASS METHODS template <class TYPE> static int maxStreamPrecision(const baljsn::EncoderOptions *options); // If the specified 'options' is 0, return 0, otherwise return either // 'options->maxFloatPrecision()' if the template parameter 'TYPE' is // 'float', and 'options->maxDoublePrecision()' is 'double'. The // supplied 'TYPE' must be either 'float' or 'double'. public: // TYPES typedef bdlb::Variant2<bdlt::Date, bdlt::DateTz> DateOrDateTz; // 'DateOrDateTz' is a convenient alias for // 'bdlb::Variant2<Date, DateTz>'. typedef bdlb::Variant2<bdlt::Time, bdlt::TimeTz> TimeOrTimeTz; // 'TimeOrTimeTz' is a convenient alias for // 'bdlb::Variant2<Time, TimeTz>'. typedef bdlb::Variant2<bdlt::Datetime, bdlt::DatetimeTz> DatetimeOrDatetimeTz; // 'DatetimeOrDatetimeTz' is a convenient alias for // 'bdlb::Variant2<Datetime, DatetimeTz>'. // CLASS METHODS template <class TYPE> static int printDateAndTime(bsl::ostream& stream, const TYPE& value, const EncoderOptions *options); // Encode the specified 'value' into JSON using ISO 8601 format and // output the result to the specified 'stream' using the specified // 'options'. template <class TYPE> static int printFloatingPoint(bsl::ostream& stream, TYPE value, const EncoderOptions *options); // Encode the specified floating point 'value' into JSON and output the // result to the specified 'stream'. Use the optionally-specified // 'options' to decide how 'value' is encoded. static int printString(bsl::ostream& stream, const bsl::string_view& value); // Encode the specified string 'value' into JSON format and output the // result to the specified 'stream'. static int printValue(bsl::ostream& stream, bool value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, char value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, signed char value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, unsigned char value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, short value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, unsigned short value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, int value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, unsigned int value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, bsls::Types::Int64 value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, bsls::Types::Uint64 value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, float value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, double value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, bdldfp::Decimal64 value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const char *value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const bsl::string_view& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const bdlt::Time& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const bdlt::Date& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const bdlt::Datetime& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const bdlt::DatetimeInterval& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const bdlt::TimeTz& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const bdlt::DateTz& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const bdlt::DatetimeTz& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const TimeOrTimeTz& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const DateOrDateTz& value, const EncoderOptions *options = 0); static int printValue(bsl::ostream& stream, const DatetimeOrDatetimeTz& value, const EncoderOptions *options = 0); // Encode the specified 'value' into JSON format and output the result // to the specified 'stream' using the optionally specified 'options'. // Return 0 on success and a non-zero value otherwise. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ---------------- // struct PrintUtil // ---------------- // PRIVATE CLASS METHODS template <> inline int PrintUtil::maxStreamPrecision<float>(const baljsn::EncoderOptions *options) { return options ? options->maxFloatPrecision() : 0; } template <> inline int PrintUtil::maxStreamPrecision<double>(const baljsn::EncoderOptions *options) { return options ? options->maxDoublePrecision() : 0; } // CLASS METHODS template <class TYPE> inline int PrintUtil::printDateAndTime(bsl::ostream& stream, const TYPE& value, const EncoderOptions *options) { char buffer[bdlt::Iso8601Util::k_MAX_STRLEN + 1]; bdlt::Iso8601UtilConfiguration config; if (options) { config.setFractionalSecondPrecision( options->datetimeFractionalSecondPrecision()); } else { config.setFractionalSecondPrecision(3); } bdlt::Iso8601Util::generate(buffer, sizeof buffer, value, config); return printValue(stream, buffer); } template <class TYPE> int PrintUtil::printFloatingPoint(bsl::ostream& stream, TYPE value, const baljsn::EncoderOptions *options) { switch (bdlb::Float::classifyFine(value)) { case bdlb::Float::k_POSITIVE_INFINITY: { if (options && options->encodeInfAndNaNAsStrings()) { stream << "\"+inf\""; } else { return -1; // RETURN } } break; case bdlb::Float::k_NEGATIVE_INFINITY: { if (options && options->encodeInfAndNaNAsStrings()) { stream << "\"-inf\""; } else { return -1; // RETURN } } break; case bdlb::Float::k_QNAN: // FALL-THROUGH case bdlb::Float::k_SNAN: { if (options && options->encodeInfAndNaNAsStrings()) { stream << "\"nan\""; } else { return -1; // RETURN } } break; default: { const int precision = maxStreamPrecision<TYPE>(options); if (0 == precision) { typedef bslalg::NumericFormatterUtil NumFmt; char buffer[NumFmt::ToCharsMaxLength<TYPE>::k_VALUE]; const char * const endPtr = NumFmt::toChars(buffer, buffer + sizeof buffer, value); BSLS_ASSERT(0 != endPtr); const size_t len = endPtr - buffer; stream.write(buffer, len); } else { const int k_SIZE = 32; char buffer[k_SIZE]; #if defined(BSLS_PLATFORM_CMP_MSVC) #define snprintf _snprintf #endif const int len = snprintf(buffer, k_SIZE, "%-1.*g", precision, value); #if defined(BSLS_PLATFORM_CMP_MSVC) #undef snprintf #endif stream.write(buffer, len); } } } return 0; } inline int PrintUtil::printString(bsl::ostream& stream, const bsl::string_view& value) { return bdljsn::StringUtil::writeString(stream, value); } inline int PrintUtil::printValue(bsl::ostream& stream, bool value, const EncoderOptions *) { stream << (value ? "true" : "false"); return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, short value, const EncoderOptions *) { stream << value; return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, int value, const EncoderOptions *) { stream << value; return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, bsls::Types::Int64 value, const EncoderOptions *) { stream << value; return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, unsigned char value, const EncoderOptions *) { stream << static_cast<int>(value); return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, unsigned short value, const EncoderOptions *) { stream << value; return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, unsigned int value, const EncoderOptions *) { stream << value; return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, bsls::Types::Uint64 value, const EncoderOptions *) { stream << value; return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, float value, const EncoderOptions *options) { return printFloatingPoint(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, double value, const EncoderOptions *options) { return printFloatingPoint(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const char *value, const EncoderOptions *) { return bdljsn::StringUtil::writeString(stream, value); } inline int PrintUtil::printValue(bsl::ostream& stream, char value, const EncoderOptions *) { signed char tmp(value); // Note that 'char' is unsigned on IBM. stream << static_cast<int>(tmp); return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, signed char value, const EncoderOptions *) { stream << static_cast<int>(value); return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, const bsl::string_view& value, const EncoderOptions *) { return bdljsn::StringUtil::writeString(stream, value); } inline int PrintUtil::printValue(bsl::ostream& stream, const bdlt::Time& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const bdlt::Date& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const bdlt::Datetime& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const bdlt::DatetimeInterval& value, const EncoderOptions *) { stream << '"' << value << '"'; return 0; } inline int PrintUtil::printValue(bsl::ostream& stream, const bdlt::TimeTz& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const bdlt::DateTz& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const bdlt::DatetimeTz& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const TimeOrTimeTz& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const DateOrDateTz& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } inline int PrintUtil::printValue(bsl::ostream& stream, const DatetimeOrDatetimeTz& value, const EncoderOptions *options) { return printDateAndTime(stream, value, options); } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 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 ----------------------------------