#ifndef THORSANVIL_SERIALIZE_FORMAT_H
#define THORSANVIL_SERIALIZE_FORMAT_H
#include <cstddef>
#include <format>
#include <string>
#include <sstream>
#include "ThorSerialize/JsonThor.h"
#include "ThorSerialize/BsonThor.h"
#include "ThorSerialize/YamlThor.h"
namespace TA
{
template<typename T>
struct Ser
{
T const& value;
Ser(T const& value)
: value(value)
{}
Ser(Ser const&) = default;
Ser(Ser&&) = default;
};
};
template<typename T>
struct std::formatter<TA::Ser<T>>
{
enum Format {Json, Bson, Yaml};
Format form = Json;
ThorsAnvil::Serialize::OutputType type = ThorsAnvil::Serialize::OutputType::Stream;
std::size_t indentSize = 0;
std::size_t blockIndent = 0;
constexpr bool isDigit(char val)
{
return val >= '0' && val <= '9';
}
constexpr auto parse(std::format_parse_context& ctx)
{
// Format specifier
// {:<Type>?<Stream>?<TabSize>?[.<blockIndent>]?}
//
// Type: Stream Type: Optional. Default Json
// J => Json
// B => Bson
// Y => Yaml
// Stream format: (Does not apply to Bson) Optional. Default Stream.
// - => Stream (no extra white space single line. Good for Web Interface or log files)
// * => Pretty print.
// TabSize: (Does not apply to Bson or Stream). Default 0: 0 is 4 space for JSON or 2 space for YAML
// [0-9]* => A positive value that represents the number of spaces used to indent each level.
// BlockIndent: (Does not apply to Bson or Stream). An indent applied before any printing.
// [0-9]* => A positive value that represents the space to inject on the left of an object.
// To separate this from the "TabSize" it must be preceded by a '.'
// loop: Is the current parse point of the format between the {} characters in the format string.
auto loop = ctx.begin();
// Check for the output type (Json/Bson/Yaml) specifier.
// This is an optional single letter. J | B | Y
switch (*loop)
{
case 'J': form = Json; ++loop; break;
case 'B': form = Bson; ++loop; break;
case 'Y': form = Yaml; ++loop; break;
default:
// Anything else fall through and out to the next test.
break;
}
// Check the stream output (Stream / Pretty print)
// This is an optional single letter. - | *
switch (*loop)
{
case '-': type = ThorsAnvil::Serialize::OutputType::Stream; ++loop; break;
case '*': type = ThorsAnvil::Serialize::OutputType::Config; ++loop; break;
default:
// Anything else fall through and out to the next test.
break;
}
// Extract the indent size.
// The default is 0. So it not supplied it will not change.
for (;isDigit(*loop); ++loop) {
indentSize = indentSize * 10 + (*loop - '0');
}
// Extract the block indent size.
// Must be proceeded by a full stop.
if (*loop == '.') {
++loop;
for (;isDigit(*loop); ++loop) {
blockIndent = blockIndent * 10 + (*loop - '0');
}
}
return loop;
}
auto format(const TA::Ser<T>& obj, auto& ctx) const
{
// Create a serialization config object.
E ThorsAnvil::Serialize::PrinterConfig config{type, indentSize, blockIndent}; ■ No matching constructor for initialization of 'ThorsAnvil::Serialize::PrinterConfig'
std::stringstream ser;
switch (form)
{
case Json: ser << ThorsAnvil::Serialize::jsonExporter(obj.value, config);break;
case Bson: ser << ThorsAnvil::Serialize::bsonExporter(obj.value, config);break;
case Yaml: ser << ThorsAnvil::Serialize::yamlExporter(obj.value, config);break;
}
std::string const& out = ser.str();
return ctx.advance_to(std::copy(std::begin(out), std::end(out), ctx.out()));
}
};
#endif
#ifndef THORSANVIL_SERIALIZE_FORMAT_H
#define THORSANVIL_SERIALIZE_FORMAT_H
#include <cstddef>
#include <format>
#include <string>
#include <sstream>
#include "ThorSerialize/JsonThor.h"
#include "ThorSerialize/BsonThor.h"
#include "ThorSerialize/YamlThor.h"
namespace TA
{
template<typename T>
struct Ser
{
T const& value;
Ser(T const& value)
: value(value)
{}
Ser(Ser const&) = default;
Ser(Ser&&) = default;
};
};
template<typename T>
struct std::formatter<TA::Ser<T>>
{
enum Format {Json, Bson, Yaml};
Format form = Json;
ThorsAnvil::Serialize::OutputType type = ThorsAnvil::Serialize::OutputType::Stream;
std::size_t indentSize = 0;
std::size_t blockIndent = 0;
constexpr bool isDigit(char val)
{
return val >= '0' && val <= '9';
}
constexpr auto parse(std::format_parse_context& ctx)
{
// Format specifier
// {:<Type>?<Stream>?<TabSize>?[.<blockIndent>]}
//
// Type: Stream Type: Optional. Default Json
// J => Json
// B => Bson
// Y => Yaml
// Stream format: (Does not apply to Bson) Optional. Default Stream.
// - => Stream (no extra white space single line. Good for Web Interface or log files)
// * => Pretty print.
// TabSize: (Does not apply to Bson or Stream). Default 0: 0 is 4 space for JSON or 2 space for YAML
// [0-9]* => A positive value that represents the number of spaces used to indent each level.
// BlockIndent: (Does not apply to Bson or Stream). An indent applied before any printing.
// [0-9]* => A positive value that represents the space to inject on the left of an object.
// To separate this from the "TabSize" it must be preceded by a '.'
// loop: Is the current parse point of the format between the {} characters in the format string.
auto loop = ctx.begin();
// Check for the output type (Json/Bson/Yaml) specifier.
// This is an optional single letter. J | B | Y
switch (*loop)
{
case 'J': form = Json; ++loop; break;
case 'B': form = Bson; ++loop; break;
case 'Y': form = Yaml; ++loop; break;
default:
// Anything else fall through and out to the next test.
break;
}
// Check the stream output (Stream / Pretty print)
// This is an optional single letter. - | *
switch (*loop)
{
case '-': type = ThorsAnvil::Serialize::OutputType::Stream; ++loop; break;
case '*': type = ThorsAnvil::Serialize::OutputType::Config; ++loop; break;
default:
// Anything else fall through and out to the next test.
break;
}
// Extract the indent size.
// The default is 0. So it not supplied it will not change.
for (;isDigit(*loop); ++loop) {
indentSize = indentSize * 10 + (*loop - '0');
}
// Extract the block indent size.
// Must be proceeded by a full stop.
if (*loop == '.') {
++loop;
for (;isDigit(*loop); ++loop) {
blockIndent = blockIndent * 10 + (*loop - '0');
}
}
return loop;
}
auto format(const TA::Ser<T>& obj, auto& ctx) const
{
// Create a serialization config object.
E ThorsAnvil::Serialize::PrinterConfig config{type, indentSize, blockIndent}; ■ No matching constructor for initialization of 'ThorsAnvil::Serialize::PrinterConfig'
std::stringstream ser;
switch (form)
{
case Json: ser << ThorsAnvil::Serialize::jsonExporter(obj.value, config);break;
case Bson: ser << ThorsAnvil::Serialize::bsonExporter(obj.value, config);break;
case Yaml: ser << ThorsAnvil::Serialize::yamlExporter(obj.value, config);break;
}
std::string const& out = ser.str();
return ctx.advance_to(std::copy(std::begin(out), std::end(out), ctx.out()));
}
};
#endif
#ifndef THORSANVIL_SERIALIZE_FORMAT_H
#define THORSANVIL_SERIALIZE_FORMAT_H
#include <cstddef>
#include <format>
#include <string>
#include <sstream>
#include "ThorSerialize/JsonThor.h"
#include "ThorSerialize/BsonThor.h"
#include "ThorSerialize/YamlThor.h"
namespace TA
{
template<typename T>
struct Ser
{
T const& value;
Ser(T const& value)
: value(value)
{}
Ser(Ser const&) = default;
Ser(Ser&&) = default;
};
};
template<typename T>
struct std::formatter<TA::Ser<T>>
{
enum Format {Json, Bson, Yaml};
Format form = Json;
ThorsAnvil::Serialize::OutputType type = ThorsAnvil::Serialize::OutputType::Stream;
std::size_t indentSize = 0;
std::size_t blockIndent = 0;
constexpr bool isDigit(char val)
{
return val >= '0' && val <= '9';
}
constexpr auto parse(std::format_parse_context& ctx)
{
// Format specifier
// {:<Type>?<Stream>?<TabSize>?[.<blockIndent>]?}
//
// Type: Stream Type: Optional. Default Json
// J => Json
// B => Bson
// Y => Yaml
// Stream format: (Does not apply to Bson) Optional. Default Stream.
// - => Stream (no extra white space single line. Good for Web Interface or log files)
// * => Pretty print.
// TabSize: (Does not apply to Bson or Stream). Default 0: 0 is 4 space for JSON or 2 space for YAML
// [0-9]* => A positive value that represents the number of spaces used to indent each level.
// BlockIndent: (Does not apply to Bson or Stream). An indent applied before any printing.
// [0-9]* => A positive value that represents the space to inject on the left of an object.
// To separate this from the "TabSize" it must be preceded by a '.'
// loop: Is the current parse point of the format between the {} characters in the format string.
auto loop = ctx.begin();
// Check for the output type (Json/Bson/Yaml) specifier.
// This is an optional single letter. J | B | Y
switch (*loop)
{
case 'J': form = Json; ++loop; break;
case 'B': form = Bson; ++loop; break;
case 'Y': form = Yaml; ++loop; break;
default:
// Anything else fall through and out to the next test.
break;
}
// Check the stream output (Stream / Pretty print)
// This is an optional single letter. - | *
switch (*loop)
{
case '-': type = ThorsAnvil::Serialize::OutputType::Stream; ++loop; break;
case '*': type = ThorsAnvil::Serialize::OutputType::Config; ++loop; break;
default:
// Anything else fall through and out to the next test.
break;
}
// Extract the indent size.
// The default is 0. So it not supplied it will not change.
for (;isDigit(*loop); ++loop) {
indentSize = indentSize * 10 + (*loop - '0');
}
// Extract the block indent size.
// Must be proceeded by a full stop.
if (*loop == '.') {
++loop;
for (;isDigit(*loop); ++loop) {
blockIndent = blockIndent * 10 + (*loop - '0');
}
}
return loop;
}
auto format(const TA::Ser<T>& obj, auto& ctx) const
{
// Create a serialization config object.
ThorsAnvil::Serialize::PrinterConfig config{type, indentSize, blockIndent};
std::stringstream ser;
switch (form)
{
case Json: ser << ThorsAnvil::Serialize::jsonExporter(obj.value, config);break;
case Bson: ser << ThorsAnvil::Serialize::bsonExporter(obj.value, config);break;
case Yaml: ser << ThorsAnvil::Serialize::yamlExporter(obj.value, config);break;
}
std::string const& out = ser.str();
return ctx.advance_to(std::copy(std::begin(out), std::end(out), ctx.out()));
}
};
#endif
Serialize with `std::format` follow up
Follow up to Serialize with `std::format`
#ifndef THORSANVIL_SERIALIZE_FORMAT_H
#define THORSANVIL_SERIALIZE_FORMAT_H
#include <cstddef>
#include <format>
#include <string>
#include <sstream>
#include "ThorSerialize/JsonThor.h"
#include "ThorSerialize/BsonThor.h"
#include "ThorSerialize/YamlThor.h"
namespace TA
{
template<typename T>
struct Ser
{
T const& value;
Ser(T const& value)
: value(value)
{}
Ser(Ser const&) = default;
Ser(Ser&&) = default;
};
};
template<typename T>
struct std::formatter<TA::Ser<T>>
{
enum Format {Json, Bson, Yaml};
Format form = Json;
ThorsAnvil::Serialize::OutputType type = ThorsAnvil::Serialize::OutputType::Stream;
std::size_t indentSize = 0;
std::size_t blockIndent = 0;
constexpr bool isDigit(char val)
{
return val >= '0' && val <= '9';
}
constexpr auto parse(std::format_parse_context& ctx)
{
// Format specifier
// {:<Type>?<Stream>?<TabSize>?[.<blockIndent>]}
//
// Type: Stream Type: Optional. Default Json
// J => Json
// B => Bson
// Y => Yaml
// Stream format: (Does not apply to Bson) Optional. Default Stream.
// - => Stream (no extra white space single line. Good for Web Interface or log files)
// * => Pretty print.
// TabSize: (Does not apply to Bson or Stream). Default 0: 0 is 4 space for JSON or 2 space for YAML
// [0-9]* => A positive value that represents the number of spaces used to indent each level.
// BlockIndent: (Does not apply to Bson or Stream). An indent applied before any printing.
// [0-9]* => A positive value that represents the space to inject on the left of an object.
// To separate this from the "TabSize" it must be preceded by a '.'
// loop: Is the current parse point of the format between the {} characters in the format string.
auto loop = ctx.begin();
// Check for the output type (Json/Bson/Yaml) specifier.
// This is an optional single letter. J | B | Y
switch (*loop)
{
case 'J': form = Json; ++loop; break;
case 'B': form = Bson; ++loop; break;
case 'Y': form = Yaml; ++loop; break;
default:
// Anything else fall through and out to the next test.
break;
}
// Check the stream output (Stream / Pretty print)
// This is an optional single letter. - | *
switch (*loop)
{
case '-': type = ThorsAnvil::Serialize::OutputType::Stream; ++loop; break;
case '*': type = ThorsAnvil::Serialize::OutputType::Config; ++loop; break;
default:
// Anything else fall through and out to the next test.
break;
}
// Extract the indent size.
// The default is 0. So it not supplied it will not change.
for (;isDigit(*loop); ++loop) {
indentSize = indentSize * 10 + (*loop - '0');
}
// Extract the block indent size.
// Must be proceeded by a full stop.
if (*loop == '.') {
++loop;
for (;isDigit(*loop); ++loop) {
blockIndent = blockIndent * 10 + (*loop - '0');
}
}
return loop;
}
auto format(const TA::Ser<T>& obj, auto& ctx) const
{
// Create a serialization config object.
E ThorsAnvil::Serialize::PrinterConfig config{type, indentSize, blockIndent}; ■ No matching constructor for initialization of 'ThorsAnvil::Serialize::PrinterConfig'
std::stringstream ser;
switch (form)
{
case Json: ser << ThorsAnvil::Serialize::jsonExporter(obj.value, config);break;
case Bson: ser << ThorsAnvil::Serialize::bsonExporter(obj.value, config);break;
case Yaml: ser << ThorsAnvil::Serialize::yamlExporter(obj.value, config);break;
}
std::string const& out = ser.str();
return ctx.advance_to(std::copy(std::begin(out), std::end(out), ctx.out()));
}
};
#endif
The main change is changing: std::format_context& ctx to auto& ctx. It compiles and seems to work. But I don't like the lack of type information.
auto format(const TA::Ser<T>& obj, auto& ctx) const
Is this best practice or should I be using a templated version:
template<typename I, typename C>
auto format(const TA::Ser<T>& obj, std::basic_format_context<I, C>& ctx) const
lang-cpp