558namespace ArgumentBinding
561template <
typename Arg>
565 using Decayed =
typename Traits::Decayed;
566 using Normalized =
typename Traits::Normalized;
568 if constexpr (std::is_same_v<Decayed, bool>)
572 else if constexpr (std::is_same_v<Decayed, char>)
576 else if constexpr (Traits::is_string_like)
580 else if constexpr (Traits::is_pointer_like)
584 else if constexpr (Traits::is_signed_integer)
587 .kind = BoundKind::Signed,
588 .uses_64bit_storage =
sizeof(Normalized) >
sizeof(int32_t),
591 else if constexpr (Traits::is_unsigned_integer)
594 .kind = BoundKind::Unsigned,
595 .uses_64bit_storage =
sizeof(Normalized) >
sizeof(uint32_t),
598 else if constexpr (std::is_same_v<Decayed, float>)
602 else if constexpr (std::is_same_v<Decayed, double>)
606 else if constexpr (std::is_same_v<Decayed, long double>)
616template <
typename... Args>
617[[nodiscard]]
consteval auto DescribeArgs()
619 return std::array<
BoundArgument,
sizeof...(Args)>{DescribeArg<Args>()...};
622[[nodiscard]]
constexpr bool HasSignOption(
const ParsedField& field)
627[[nodiscard]]
constexpr uint8_t UnspecifiedPrecision()
629 return std::numeric_limits<uint8_t>::max();
632[[nodiscard]]
constexpr uint8_t BuildFlags(
const ParsedField& parsed,
bool upper_case)
635 if (parsed.
align == Align::Left)
637 flags |=
static_cast<uint8_t
>(FormatFlag::LeftAlign);
639 if (parsed.
align == Align::Center)
641 flags |=
static_cast<uint8_t
>(FormatFlag::CenterAlign);
645 flags |=
static_cast<uint8_t
>(FormatFlag::ForceSign);
649 flags |=
static_cast<uint8_t
>(FormatFlag::SpaceSign);
653 flags |=
static_cast<uint8_t
>(FormatFlag::Alternate);
657 flags |=
static_cast<uint8_t
>(FormatFlag::ZeroPad);
661 flags |=
static_cast<uint8_t
>(FormatFlag::UpperCase);
667 FormatPackKind pack,
bool upper_case =
false)
672 .rule = FormatArgumentRule::None,
673 .flags = BuildFlags(parsed, upper_case),
675 .width = parsed.
width,
680[[nodiscard]]
constexpr bool IsDefaultOr(
char presentation,
char expected)
682 return presentation == 0 || presentation == expected;
685[[nodiscard]]
constexpr bool IsNonDecimalPresentation(
char presentation)
687 return presentation ==
'b' || presentation ==
'B' || presentation ==
'o' ||
688 presentation ==
'x' || presentation ==
'X';
691[[nodiscard]]
constexpr char DefaultFloatPresentation()
693 if (Config::enable_float_general)
697 if (Config::enable_float_fixed)
701 if (Config::enable_float_scientific)
710 bool uses_64bit_storage)
712 if (!Config::enable_integer)
714 return LoweredField{.error = Error::ArgumentTypeMismatch};
716 if (uses_64bit_storage && !Config::enable_integer_64bit)
718 return LoweredField{.error = Error::ArgumentTypeMismatch};
723 return LoweredField{.error = Error::ArgumentTypeMismatch};
730 return LoweredField{.error = Error::ArgumentTypeMismatch};
732 return LoweredField{.field = MakeField(parsed, FormatType::Character,
733 FormatPackKind::Character)};
740 return LoweredField{.error = Error::ArgumentTypeMismatch};
742 if (!signed_decimal && HasSignOption(parsed))
744 return LoweredField{.error = Error::ArgumentTypeMismatch};
751 uses_64bit_storage ? FormatType::Signed64
752 : FormatType::Signed32,
753 uses_64bit_storage ? FormatPackKind::I64
754 : FormatPackKind::I32)};
759 uses_64bit_storage ? FormatType::Unsigned64
760 : FormatType::Unsigned32,
761 uses_64bit_storage ? FormatPackKind::U64
762 : FormatPackKind::U32)};
765 if (!Config::enable_integer_base8_16 || HasSignOption(parsed))
767 return LoweredField{.error = Error::ArgumentTypeMismatch};
775 uses_64bit_storage ? FormatType::Binary64
776 : FormatType::Binary32,
777 uses_64bit_storage ? FormatPackKind::U64
778 : FormatPackKind::U32)};
782 uses_64bit_storage ? FormatType::Binary64
783 : FormatType::Binary32,
784 uses_64bit_storage ? FormatPackKind::U64
785 : FormatPackKind::U32,
790 uses_64bit_storage ? FormatType::Octal64
791 : FormatType::Octal32,
792 uses_64bit_storage ? FormatPackKind::U64
793 : FormatPackKind::U32)};
797 uses_64bit_storage ? FormatType::HexLower64
798 : FormatType::HexLower32,
799 uses_64bit_storage ? FormatPackKind::U64
800 : FormatPackKind::U32)};
804 uses_64bit_storage ? FormatType::HexUpper64
805 : FormatType::HexUpper32,
806 uses_64bit_storage ? FormatPackKind::U64
807 : FormatPackKind::U32,
810 return LoweredField{.error = Error::ArgumentTypeMismatch};
818 return LoweredField{.error = Error::ArgumentTypeMismatch};
820 return LowerIntegerLike(parsed,
false,
false);
827 return LoweredField{.error = Error::ArgumentTypeMismatch};
831 return LoweredField{.error = Error::ArgumentTypeMismatch};
833 if (!Config::enable_text)
835 return LoweredField{.error = Error::ArgumentTypeMismatch};
839 if (adjusted.
align == Align::None)
841 adjusted.
align = Align::Left;
845 .field = MakeField(adjusted, FormatType::Character, FormatPackKind::Character)};
852 return LoweredField{.error = Error::ArgumentTypeMismatch};
856 return LoweredField{.error = Error::ArgumentTypeMismatch};
858 if (!Config::enable_text)
860 return LoweredField{.error = Error::ArgumentTypeMismatch};
864 if (adjusted.
align == Align::None)
866 adjusted.
align = Align::Left;
870 .field = MakeField(adjusted, FormatType::String, FormatPackKind::StringView)};
877 return LoweredField{.error = Error::ArgumentTypeMismatch};
881 return LoweredField{.error = Error::ArgumentTypeMismatch};
883 if (!Config::enable_pointer)
885 return LoweredField{.error = Error::ArgumentTypeMismatch};
889 .field = MakeField(parsed, FormatType::Pointer, FormatPackKind::Pointer)};
897 if (presentation == 0)
899 return LoweredField{.error = Error::ArgumentTypeMismatch};
902 presentation ==
'F' || presentation ==
'E' || presentation ==
'G';
904 FormatType type = FormatType::End;
905 FormatPackKind pack = FormatPackKind::F32;
907 auto pick_type = [&](FormatType f32_type, FormatType f64_type,
908 FormatType ld_type)
consteval ->
bool {
911 case BoundKind::Float32:
913 pack = FormatPackKind::F32;
915 case BoundKind::Float64:
916 type = Config::enable_float_double ? f64_type : f32_type;
917 pack = Config::enable_float_double ? FormatPackKind::F64 : FormatPackKind::F32;
919 case BoundKind::LongDouble:
920 if (!Config::enable_float_long_double)
925 pack = FormatPackKind::LongDouble;
932 switch (presentation)
936 if (!Config::enable_float_fixed ||
937 !pick_type(FormatType::FloatFixed, FormatType::DoubleFixed,
938 FormatType::LongDoubleFixed))
940 return LoweredField{.error = Error::ArgumentTypeMismatch};
945 if (!Config::enable_float_scientific ||
946 !pick_type(FormatType::FloatScientific, FormatType::DoubleScientific,
947 FormatType::LongDoubleScientific))
949 return LoweredField{.error = Error::ArgumentTypeMismatch};
954 if (!Config::enable_float_general ||
955 !pick_type(FormatType::FloatGeneral, FormatType::DoubleGeneral,
956 FormatType::LongDoubleGeneral))
958 return LoweredField{.error = Error::ArgumentTypeMismatch};
962 return LoweredField{.error = Error::ArgumentTypeMismatch};
965 return LoweredField{.field = MakeField(parsed, type, pack, upper_case)};
968template <
typename... Args>
971 constexpr auto bound_arguments = DescribeArgs<Args...>();
972 if (parsed.
arg_index >= bound_arguments.size())
977 auto argument = bound_arguments[parsed.
arg_index];
978 switch (argument.kind)
980 case BoundKind::Bool:
981 return LowerBool(parsed);
982 case BoundKind::Character:
983 return LowerCharacter(parsed);
984 case BoundKind::Signed:
985 return LowerIntegerLike(parsed,
true, argument.uses_64bit_storage);
986 case BoundKind::Unsigned:
987 return LowerIntegerLike(parsed,
false, argument.uses_64bit_storage);
988 case BoundKind::String:
989 return LowerString(parsed);
990 case BoundKind::Pointer:
991 return LowerPointer(parsed);
992 case BoundKind::Float32:
993 case BoundKind::Float64:
994 case BoundKind::LongDouble:
995 return LowerFloat(parsed, argument.kind);
996 case BoundKind::Unsupported:
998 return LoweredField{.error = Error::UnsupportedArgumentType};