Commit e1ab6bc0 authored by Victor Zverovich's avatar Victor Zverovich

Simplify format string compilation

parent 24a88545
......@@ -15,79 +15,51 @@ FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Char> struct format_part {
public:
struct named_argument_id {
FMT_CONSTEXPR named_argument_id(internal::string_view_metadata id)
: id(id) {}
internal::string_view_metadata id;
struct named_arg_id {
FMT_CONSTEXPR named_arg_id(string_view_metadata id) : id(id) {}
string_view_metadata id;
};
struct argument_id {
FMT_CONSTEXPR argument_id() : argument_id(0u) {}
FMT_CONSTEXPR argument_id(unsigned id)
: which(which_arg_id::index), val(id) {}
FMT_CONSTEXPR argument_id(internal::string_view_metadata id)
: which(which_arg_id::named_index), val(id) {}
enum class which_arg_id { index, named_index };
struct replacement {
FMT_CONSTEXPR replacement() : arg_id(0u) {}
FMT_CONSTEXPR replacement(unsigned id) : arg_id(id) {}
which_arg_id which;
FMT_CONSTEXPR replacement(string_view_metadata id) : arg_id(id) {}
union value {
FMT_CONSTEXPR value() : index(0u) {}
FMT_CONSTEXPR value(unsigned id) : index(id) {}
FMT_CONSTEXPR value(internal::string_view_metadata id)
: named_index(id) {}
unsigned index;
internal::string_view_metadata named_index;
} val;
arg_ref<Char> arg_id;
dynamic_format_specs<Char> parsed_specs;
};
struct specification {
FMT_CONSTEXPR specification() : arg_id(0u) {}
FMT_CONSTEXPR specification(unsigned id) : arg_id(id) {}
FMT_CONSTEXPR specification(internal::string_view_metadata id)
: arg_id(id) {}
enum class kind { arg_index, arg_name, text, replacement };
argument_id arg_id;
internal::dynamic_format_specs<Char> parsed_specs;
};
kind part_kind;
std::size_t end_of_argument_id;
union value {
FMT_CONSTEXPR value() : arg_index(0u) {}
FMT_CONSTEXPR value(unsigned id) : arg_index(id) {}
FMT_CONSTEXPR value(named_arg_id named_id) : arg_name(named_id.id) {}
FMT_CONSTEXPR value(string_view_metadata t) : text(t) {}
FMT_CONSTEXPR value(replacement r) : repl(r) {}
unsigned arg_index;
string_view_metadata arg_name;
string_view_metadata text;
replacement repl;
} val;
FMT_CONSTEXPR format_part()
: which(kind::argument_id), end_of_argument_id(0u), val(0u) {}
: part_kind(kind::arg_index), end_of_argument_id(0u), val(0u) {}
FMT_CONSTEXPR format_part(internal::string_view_metadata text)
: which(kind::text), end_of_argument_id(0u), val(text) {}
FMT_CONSTEXPR format_part(unsigned arg_index)
: part_kind(kind::arg_index), end_of_argument_id(0u), val(arg_index) {}
FMT_CONSTEXPR format_part(unsigned id)
: which(kind::argument_id), end_of_argument_id(0u), val(id) {}
FMT_CONSTEXPR format_part(named_arg_id arg_name)
: part_kind(kind::arg_name), end_of_argument_id(0u), val(arg_name) {}
FMT_CONSTEXPR format_part(named_argument_id arg_id)
: which(kind::named_argument_id), end_of_argument_id(0u), val(arg_id) {}
FMT_CONSTEXPR format_part(string_view_metadata text)
: part_kind(kind::text), end_of_argument_id(0u), val(text) {}
FMT_CONSTEXPR format_part(specification spec)
: which(kind::specification), end_of_argument_id(0u), val(spec) {}
enum class kind { argument_id, named_argument_id, text, specification };
kind which;
std::size_t end_of_argument_id;
union value {
FMT_CONSTEXPR value() : arg_id(0u) {}
FMT_CONSTEXPR value(unsigned id) : arg_id(id) {}
FMT_CONSTEXPR value(named_argument_id named_id)
: named_arg_id(named_id.id) {}
FMT_CONSTEXPR value(internal::string_view_metadata t) : text(t) {}
FMT_CONSTEXPR value(specification s) : spec(s) {}
unsigned arg_id;
internal::string_view_metadata named_arg_id;
internal::string_view_metadata text;
specification spec;
} val;
FMT_CONSTEXPR format_part(replacement repl)
: part_kind(kind::replacement), end_of_argument_id(0u), val(repl) {}
};
template <typename Char, typename PartsContainer>
......@@ -96,8 +68,6 @@ class format_preparation_handler : public internal::error_handler {
using part = format_part<Char>;
public:
using iterator = typename basic_string_view<Char>::iterator;
FMT_CONSTEXPR format_preparation_handler(basic_string_view<Char> format,
PartsContainer& parts)
: parts_(parts), format_(format), parse_context_(format) {}
......@@ -120,7 +90,7 @@ class format_preparation_handler : public internal::error_handler {
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) {
const auto view = string_view_metadata(format_, id);
const auto arg_id = typename part::named_argument_id(view);
const auto arg_id = typename part::named_arg_id(view);
parts_.push_back(part(arg_id));
}
......@@ -140,9 +110,9 @@ class format_preparation_handler : public internal::error_handler {
if (*begin != '}') on_error("missing '}' in format string");
auto& last_part = parts_.back();
auto specs = last_part.which == part::kind::argument_id
? typename part::specification(last_part.val.arg_id)
: typename part::specification(last_part.val.named_arg_id);
auto specs = last_part.part_kind == part::kind::arg_index
? typename part::replacement(last_part.val.arg_index)
: typename part::replacement(last_part.val.arg_name);
specs.parsed_specs = parsed_specs;
last_part = part(specs);
last_part.end_of_argument_id = specs_offset;
......@@ -156,15 +126,15 @@ class format_preparation_handler : public internal::error_handler {
};
template <typename Format, typename PreparedPartsProvider, typename... Args>
class prepared_format {
class compiled_format {
public:
using char_type = char_t<Format>;
using format_part_t = format_part<char_type>;
constexpr prepared_format(Format f)
constexpr compiled_format(Format f)
: format_(std::move(f)), parts_provider_(to_string_view(format_)) {}
prepared_format() = delete;
compiled_format() = delete;
using context = buffer_context<char_type>;
......@@ -180,7 +150,7 @@ class prepared_format {
const auto& part = *part_it;
const auto& value = part.val;
switch (part.which) {
switch (part.part_kind) {
case format_part_t::kind::text: {
const auto text = value.text.to_view(format_view.data());
auto output = ctx.out();
......@@ -189,26 +159,24 @@ class prepared_format {
ctx.advance_to(output);
} break;
case format_part_t::kind::argument_id: {
case format_part_t::kind::arg_index: {
advance_parse_context_to_specification(parse_ctx, part);
format_arg<Range>(parse_ctx, ctx, value.arg_id);
format_arg<Range>(parse_ctx, ctx, value.arg_index);
} break;
case format_part_t::kind::named_argument_id: {
case format_part_t::kind::arg_name: {
advance_parse_context_to_specification(parse_ctx, part);
const auto named_arg_id =
value.named_arg_id.to_view(format_view.data());
const auto named_arg_id = value.arg_name.to_view(format_view.data());
format_arg<Range>(parse_ctx, ctx, named_arg_id);
} break;
case format_part_t::kind::specification: {
const auto& arg_id_value = value.spec.arg_id.val;
const auto arg = value.spec.arg_id.which ==
format_part_t::argument_id::which_arg_id::index
case format_part_t::kind::replacement: {
const auto& arg_id_value = value.repl.arg_id.val;
const auto arg = value.repl.arg_id.kind == arg_id_kind::index
? ctx.arg(arg_id_value.index)
: ctx.arg(arg_id_value.named_index.to_view(
: ctx.arg(arg_id_value.name.to_view(
to_string_view(format_).data()));
auto specs = value.spec.parsed_specs;
auto specs = value.repl.parsed_specs;
handle_dynamic_spec<internal::width_checker>(
specs.width, specs.width_ref, ctx, format_view.begin());
......@@ -352,14 +320,6 @@ template <typename Parts> class compiletime_prepared_parts_collector {
unsigned counter_;
};
template <typename PartsContainer, typename Char>
FMT_CONSTEXPR PartsContainer prepare_parts(basic_string_view<Char> format) {
PartsContainer parts;
internal::parse_format_string</*IS_CONSTEXPR=*/false>(
format, format_preparation_handler<Char, PartsContainer>(format, parts));
return parts;
}
template <typename PartsContainer, typename Char>
FMT_CONSTEXPR PartsContainer
prepare_compiletime_parts(basic_string_view<Char> format) {
......@@ -372,30 +332,33 @@ prepare_compiletime_parts(basic_string_view<Char> format) {
return parts;
}
template <typename PartsContainer> class runtime_parts_provider {
template <typename Char> class runtime_parts_provider {
public:
runtime_parts_provider() = delete;
template <typename Char>
runtime_parts_provider(basic_string_view<Char> format)
: parts_(prepare_parts<PartsContainer>(format)) {}
using parts_container = std::vector<internal::format_part<Char>>;
runtime_parts_provider(basic_string_view<Char> format) {
internal::parse_format_string<false>(
format,
format_preparation_handler<Char, parts_container>(format, parts_));
}
const PartsContainer& parts() const { return parts_; }
const parts_container& parts() const { return parts_; }
private:
PartsContainer parts_;
parts_container parts_;
};
template <typename Format, typename PartsContainer>
struct compiletime_parts_provider {
compiletime_parts_provider() = delete;
template <typename Format> struct compiletime_parts_provider {
using parts_container =
typename internal::compiletime_prepared_parts_type_provider<Format>::type;
template <typename Char>
FMT_CONSTEXPR compiletime_parts_provider(basic_string_view<Char>) {}
const PartsContainer& parts() const {
static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts =
prepare_compiletime_parts<PartsContainer>(
internal::to_string_view(Format{}));
const parts_container& parts() const {
static FMT_CONSTEXPR_DECL const parts_container prepared_parts =
prepare_compiletime_parts<parts_container>(
internal::to_string_view(Format()));
return prepared_parts;
}
};
......@@ -404,21 +367,16 @@ struct compiletime_parts_provider {
#if FMT_USE_CONSTEXPR
template <typename... Args, typename S,
FMT_ENABLE_IF(is_compile_string<S>::value)>
FMT_CONSTEXPR auto compile(S format_str) -> internal::prepared_format<
S,
internal::compiletime_parts_provider<
S,
typename internal::compiletime_prepared_parts_type_provider<S>::type>,
Args...> {
FMT_CONSTEXPR auto compile(S format_str)
-> internal::compiled_format<S, internal::compiletime_parts_provider<S>,
Args...> {
return format_str;
}
#endif
template <typename... Args, typename Char, size_t N>
auto compile(const Char (&format_str)[N]) -> internal::prepared_format<
std::basic_string<Char>,
internal::runtime_parts_provider<std::vector<internal::format_part<Char>>>,
Args...> {
auto compile(const Char (&format_str)[N]) -> internal::compiled_format<
std::basic_string<Char>, internal::runtime_parts_provider<Char>, Args...> {
return std::basic_string<Char>(format_str, N - 1);
}
......
......@@ -34,192 +34,6 @@
using testing::Return;
using testing::StrictMock;
FMT_BEGIN_NAMESPACE
namespace internal {
bool operator==(const internal::string_view_metadata& lhs,
const internal::string_view_metadata& rhs) {
return std::tie(lhs.offset_, lhs.size_) == std::tie(rhs.offset_, rhs.size_);
}
bool operator!=(const internal::string_view_metadata& lhs,
const internal::string_view_metadata& rhs) {
return !(lhs == rhs);
}
bool operator==(const format_part<char>::specification& lhs,
const format_part<char>::specification& rhs) {
if (lhs.arg_id.which != rhs.arg_id.which) {
return false;
}
typedef format_part<char>::argument_id::which_arg_id which_arg_id;
switch (lhs.arg_id.which) {
case which_arg_id::index: {
if (lhs.arg_id.val.index != rhs.arg_id.val.index) {
return false;
}
} break;
case which_arg_id::named_index: {
if (lhs.arg_id.val.named_index != rhs.arg_id.val.named_index) {
return false;
}
} break;
}
return std::tie(lhs.parsed_specs.width, lhs.parsed_specs.fill[0],
lhs.parsed_specs.align, lhs.parsed_specs.precision,
lhs.parsed_specs.sign, lhs.parsed_specs.type) ==
std::tie(rhs.parsed_specs.width, rhs.parsed_specs.fill[0],
rhs.parsed_specs.align, rhs.parsed_specs.precision,
rhs.parsed_specs.sign, rhs.parsed_specs.type);
}
bool operator!=(const format_part<char>::specification& lhs,
const format_part<char>::specification& rhs) {
return !(lhs == rhs);
}
bool operator==(const format_part<char>& lhs,
const fmt::internal::format_part<char>& rhs) {
typedef format_part<char>::kind kind;
if (lhs.which != rhs.which ||
lhs.end_of_argument_id != rhs.end_of_argument_id) {
return false;
}
switch (lhs.which) {
case kind::argument_id: {
return lhs.val.arg_id == rhs.val.arg_id;
}
case kind::named_argument_id: {
return lhs.val.named_arg_id == rhs.val.named_arg_id;
}
case kind::text: {
return lhs.val.text == rhs.val.text;
}
case kind::specification: {
return lhs.val.spec == rhs.val.spec;
}
}
return false;
}
bool operator!=(const fmt::internal::format_part<char>& lhs,
const fmt::internal::format_part<char>& rhs) {
return !(lhs == rhs);
}
}
FMT_END_NAMESPACE
TEST(CompileTest, FormatPart_ComparisonOperators) {
typedef fmt::internal::format_part<char> format_part;
typedef fmt::internal::dynamic_format_specs<char> prepared_specs;
{
const auto part = format_part(0u);
const auto other = format_part(0u);
EXPECT_EQ(part, other);
}
{
const auto lhs = format_part(0u);
const auto rhs = format_part(1u);
EXPECT_NE(lhs, rhs);
}
{
const auto lhs = format_part(fmt::internal::string_view_metadata(0, 42));
const auto rhs = format_part(fmt::internal::string_view_metadata(0, 42));
EXPECT_EQ(lhs, rhs);
}
{
const auto lhs = format_part(fmt::internal::string_view_metadata(0, 42));
const auto rhs = format_part(fmt::internal::string_view_metadata(0, 4422));
EXPECT_NE(lhs, rhs);
}
{
auto lhs = format_part(0u);
auto rhs = format_part(fmt::internal::string_view_metadata(0, 42));
EXPECT_NE(lhs, rhs);
rhs = format_part(fmt::internal::string_view_metadata(0, 0));
EXPECT_NE(lhs, rhs);
}
{
auto lhs = format_part(0u);
lhs.end_of_argument_id = 42;
auto rhs = format_part(0u);
rhs.end_of_argument_id = 42;
EXPECT_EQ(lhs, rhs);
rhs.end_of_argument_id = 13;
EXPECT_NE(lhs, rhs);
}
{
const auto specs_argument_id = 0u;
const auto specs_named_argument_id =
fmt::internal::string_view_metadata(0, 42);
auto specs = format_part::specification(0u);
auto lhs = format_part(specs);
auto rhs = format_part(specs);
EXPECT_EQ(lhs, rhs);
specs.parsed_specs = prepared_specs();
lhs = format_part(specs);
rhs = format_part(specs);
EXPECT_EQ(lhs, rhs);
specs = format_part::specification(specs_named_argument_id);
lhs = format_part(specs);
rhs = format_part(specs);
EXPECT_EQ(lhs, rhs);
specs.parsed_specs = prepared_specs();
lhs = format_part(specs);
rhs = format_part(specs);
EXPECT_EQ(lhs, rhs);
auto lhs_spec = format_part::specification(specs_argument_id);
auto rhs_spec = format_part::specification(specs_named_argument_id);
lhs = format_part(lhs_spec);
rhs = format_part(rhs_spec);
EXPECT_NE(lhs, rhs);
lhs_spec = format_part::specification(specs_argument_id);
rhs_spec = format_part::specification(specs_argument_id);
lhs_spec.parsed_specs.precision = 1;
rhs_spec.parsed_specs.precision = 2;
lhs = format_part(lhs_spec);
rhs = format_part(rhs_spec);
EXPECT_NE(lhs, rhs);
}
{
const auto specs_argument_id = 0u;
const auto specs_named_argument_id =
fmt::internal::string_view_metadata(0, 42);
auto specs = format_part::specification(specs_argument_id);
auto lhs = format_part(specs);
auto rhs = format_part(0u);
auto rhs2 = format_part(fmt::internal::string_view_metadata(0, 42));
EXPECT_NE(lhs, rhs);
EXPECT_NE(lhs, rhs2);
specs.parsed_specs = prepared_specs();
lhs = format_part{specs};
EXPECT_NE(lhs, rhs);
EXPECT_NE(lhs, rhs2);
specs = format_part::specification(specs_named_argument_id);
EXPECT_NE(lhs, rhs);
EXPECT_NE(lhs, rhs2);
specs.parsed_specs = prepared_specs();
lhs = format_part(specs);
EXPECT_NE(lhs, rhs);
EXPECT_NE(lhs, rhs2);
}
}
// compiletime_prepared_parts_type_provider is useful only with relaxed
// constexpr.
#if FMT_USE_CONSTEXPR
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment