souffle  2.0.2-371-g6315b36
Data Structures | Functions
tinyformat::detail Namespace Reference

Data Structures

struct  convertToInt
 
struct  convertToInt< T, true >
 
class  FormatArg
 
class  FormatListN
 
class  FormatListN< 0 >
 
struct  formatValueAsType
 
struct  formatValueAsType< T, fmtT, true >
 
struct  is_convertible
 
struct  is_wchar
 
struct  is_wchar< const wchar_t * >
 
struct  is_wchar< const wchar_t[n]>
 
struct  is_wchar< wchar_t * >
 
struct  is_wchar< wchar_t[n]>
 

Functions

void formatImpl (std::ostream &out, const char *fmt, const detail::FormatArg *args, int numArgs)
 
template<typename T >
void formatTruncated (std::ostream &out, const T &value, int ntrunc)
 
int parseIntAndAdvance (const char *&c)
 
bool parseWidthOrPrecision (int &n, const char *&c, bool positionalMode, const detail::FormatArg *args, int &argIndex, int numArgs)
 
const char * printFormatStringLiteral (std::ostream &out, const char *fmt)
 
const char * streamStateFromFormat (std::ostream &out, bool &positionalMode, bool &spacePadPositive, int &ntrunc, const char *fmtStart, const detail::FormatArg *args, int &argIndex, int numArgs)
 

Function Documentation

◆ formatImpl()

void tinyformat::detail::formatImpl ( std::ostream &  out,
const char *  fmt,
const detail::FormatArg args,
int  numArgs 
)
inline

Definition at line 867 of file tinyformat.h.

870 {
871  // Saved stream state
872  std::streamsize origWidth = out.width();
873  std::streamsize origPrecision = out.precision();
874  std::ios::fmtflags origFlags = out.flags();
875  char origFill = out.fill();
876 
877  // "Positional mode" means all format specs should be of the form "%n$..."
878  // with `n` an integer. We detect this in `streamStateFromFormat`.
879  bool positionalMode = false;
880  int argIndex = 0;
881  while (true) {
882  fmt = printFormatStringLiteral(out, fmt);
883  if (*fmt == '\0') {
884  if (!positionalMode && argIndex < numArgs) {
885  TINYFORMAT_ERROR("tinyformat: Not enough conversion specifiers in format string");
886  }
887  break;
888  }
889  bool spacePadPositive = false;
890  int ntrunc = -1;
891  const char* fmtEnd = streamStateFromFormat(out, positionalMode, spacePadPositive, ntrunc, fmt,
892  args, argIndex, numArgs);
893  // NB: argIndex may be incremented by reading variable width/precision
894  // in `streamStateFromFormat`, so do the bounds check here.
895  if (argIndex >= numArgs) {
896  TINYFORMAT_ERROR("tinyformat: Too many conversion specifiers in format string");
897  return;
898  }
899  const FormatArg& arg = args[argIndex];
900  // Format the arg into the stream.
901  if (!spacePadPositive) {
902  arg.format(out, fmt, fmtEnd, ntrunc);
903  }
904  else {
905  // The following is a special case with no direct correspondence
906  // between stream formatting and the printf() behaviour. Simulate
907  // it crudely by formatting into a temporary string stream and
908  // munging the resulting string.
909  std::ostringstream tmpStream;
910  tmpStream.copyfmt(out);
911  tmpStream.setf(std::ios::showpos);
912  arg.format(tmpStream, fmt, fmtEnd, ntrunc);
913  std::string result = tmpStream.str(); // allocates... yuck.
914  for (char & i : result) {
915  if (i == '+')
916  i = ' ';
917  }
918  out << result;
919  }
920  if (!positionalMode)
921  ++argIndex;
922  fmt = fmtEnd;
923  }
924 
925  // Restore stream state
926  out.width(origWidth);
927  out.precision(origPrecision);
928  out.flags(origFlags);
929  out.fill(origFill);
930 }

References tinyformat::detail::FormatArg::format(), i, printFormatStringLiteral(), streamStateFromFormat(), and TINYFORMAT_ERROR.

Referenced by tinyformat::vformat().

Here is the call graph for this function:

◆ formatTruncated()

template<typename T >
void tinyformat::detail::formatTruncated ( std::ostream &  out,
const T &  value,
int  ntrunc 
)
inline

Definition at line 287 of file tinyformat.h.

288 {
289  std::ostringstream tmp;
290  tmp << value;
291  std::string result = tmp.str();
292  out.write(result.c_str(), (std::min)(ntrunc, static_cast<int>(result.size())));
293 }

Referenced by tinyformat::formatValue().

◆ parseIntAndAdvance()

int tinyformat::detail::parseIntAndAdvance ( const char *&  c)
inline

Definition at line 556 of file tinyformat.h.

557 {
558  int i = 0;
559  for (;*c >= '0' && *c <= '9'; ++c)
560  i = 10*i + (*c - '0');
561  return i;
562 }

References i.

Referenced by parseWidthOrPrecision(), and streamStateFromFormat().

◆ parseWidthOrPrecision()

bool tinyformat::detail::parseWidthOrPrecision ( int &  n,
const char *&  c,
bool  positionalMode,
const detail::FormatArg args,
int &  argIndex,
int  numArgs 
)
inline

Definition at line 569 of file tinyformat.h.

572 {
573  if (*c >= '0' && *c <= '9') {
574  n = parseIntAndAdvance(c);
575  }
576  else if (*c == '*') {
577  ++c;
578  n = 0;
579  if (positionalMode) {
580  int pos = parseIntAndAdvance(c) - 1;
581  if (*c != '$')
582  TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a positional one");
583  if (pos >= 0 && pos < numArgs)
584  n = args[pos].toInt();
585  else
586  TINYFORMAT_ERROR("tinyformat: Positional argument out of range");
587  ++c;
588  }
589  else {
590  if (argIndex < numArgs)
591  n = args[argIndex++].toInt();
592  else
593  TINYFORMAT_ERROR("tinyformat: Not enough arguments to read variable width or precision");
594  }
595  }
596  else {
597  return false;
598  }
599  return true;
600 }

References n, parseIntAndAdvance(), TINYFORMAT_ERROR, and tinyformat::detail::FormatArg::toInt().

Referenced by streamStateFromFormat().

Here is the call graph for this function:

◆ printFormatStringLiteral()

const char* tinyformat::detail::printFormatStringLiteral ( std::ostream &  out,
const char *  fmt 
)
inline

Definition at line 607 of file tinyformat.h.

608 {
609  const char* c = fmt;
610  for (;; ++c) {
611  if (*c == '\0') {
612  out.write(fmt, c - fmt);
613  return c;
614  }
615  else if (*c == '%') {
616  out.write(fmt, c - fmt);
617  if (*(c+1) != '%')
618  return c;
619  // for "%%", tack trailing % onto next literal section.
620  fmt = ++c;
621  }
622  }
623 }

Referenced by formatImpl().

◆ streamStateFromFormat()

const char* tinyformat::detail::streamStateFromFormat ( std::ostream &  out,
bool &  positionalMode,
bool &  spacePadPositive,
int &  ntrunc,
const char *  fmtStart,
const detail::FormatArg args,
int &  argIndex,
int  numArgs 
)
inline

Definition at line 659 of file tinyformat.h.

664 {
665  TINYFORMAT_ASSERT(*fmtStart == '%');
666  // Reset stream state to defaults.
667  out.width(0);
668  out.precision(6);
669  out.fill(' ');
670  // Reset most flags; ignore irrelevant unitbuf & skipws.
671  out.unsetf(std::ios::adjustfield | std::ios::basefield |
672  std::ios::floatfield | std::ios::showbase | std::ios::boolalpha |
673  std::ios::showpoint | std::ios::showpos | std::ios::uppercase);
674  bool precisionSet = false;
675  bool widthSet = false;
676  int widthExtra = 0;
677  const char* c = fmtStart + 1;
678 
679  // 1) Parse an argument index (if followed by '$') or a width possibly
680  // preceded with '0' flag.
681  if (*c >= '0' && *c <= '9') {
682  const char tmpc = *c;
683  int value = parseIntAndAdvance(c);
684  if (*c == '$') {
685  // value is an argument index
686  if (value > 0 && value <= numArgs)
687  argIndex = value - 1;
688  else
689  TINYFORMAT_ERROR("tinyformat: Positional argument out of range");
690  ++c;
691  positionalMode = true;
692  }
693  else if (positionalMode) {
694  TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a positional one");
695  }
696  else {
697  if (tmpc == '0') {
698  // Use internal padding so that numeric values are
699  // formatted correctly, eg -00010 rather than 000-10
700  out.fill('0');
701  out.setf(std::ios::internal, std::ios::adjustfield);
702  }
703  if (value != 0) {
704  // Nonzero value means that we parsed width.
705  widthSet = true;
706  out.width(value);
707  }
708  }
709  }
710  else if (positionalMode) {
711  TINYFORMAT_ERROR("tinyformat: Non-positional argument used after a positional one");
712  }
713  // 2) Parse flags and width if we did not do it in previous step.
714  if (!widthSet) {
715  // Parse flags
716  for (;; ++c) {
717  switch (*c) {
718  case '#':
719  out.setf(std::ios::showpoint | std::ios::showbase);
720  continue;
721  case '0':
722  // overridden by left alignment ('-' flag)
723  if (!(out.flags() & std::ios::left)) {
724  // Use internal padding so that numeric values are
725  // formatted correctly, eg -00010 rather than 000-10
726  out.fill('0');
727  out.setf(std::ios::internal, std::ios::adjustfield);
728  }
729  continue;
730  case '-':
731  out.fill(' ');
732  out.setf(std::ios::left, std::ios::adjustfield);
733  continue;
734  case ' ':
735  // overridden by show positive sign, '+' flag.
736  if (!(out.flags() & std::ios::showpos))
737  spacePadPositive = true;
738  continue;
739  case '+':
740  out.setf(std::ios::showpos);
741  spacePadPositive = false;
742  widthExtra = 1;
743  continue;
744  default:
745  break;
746  }
747  break;
748  }
749  // Parse width
750  int width = 0;
751  widthSet = parseWidthOrPrecision(width, c, positionalMode,
752  args, argIndex, numArgs);
753  if (widthSet) {
754  if (width < 0) {
755  // negative widths correspond to '-' flag set
756  out.fill(' ');
757  out.setf(std::ios::left, std::ios::adjustfield);
758  width = -width;
759  }
760  out.width(width);
761  }
762  }
763  // 3) Parse precision
764  if (*c == '.') {
765  ++c;
766  int precision = 0;
767  parseWidthOrPrecision(precision, c, positionalMode,
768  args, argIndex, numArgs);
769  // Presence of `.` indicates precision set, unless the inferred value
770  // was negative in which case the default is used.
771  precisionSet = precision >= 0;
772  if (precisionSet)
773  out.precision(precision);
774  }
775  // 4) Ignore any C99 length modifier
776  while (*c == 'l' || *c == 'h' || *c == 'L' ||
777  *c == 'j' || *c == 'z' || *c == 't') {
778  ++c;
779  }
780  // 5) We're up to the conversion specifier character.
781  // Set stream flags based on conversion specifier (thanks to the
782  // boost::format class for forging the way here).
783  bool intConversion = false;
784  switch (*c) {
785  case 'u': case 'd': case 'i':
786  out.setf(std::ios::dec, std::ios::basefield);
787  intConversion = true;
788  break;
789  case 'o':
790  out.setf(std::ios::oct, std::ios::basefield);
791  intConversion = true;
792  break;
793  case 'X':
794  out.setf(std::ios::uppercase);
795  // Falls through
796  case 'x': case 'p':
797  out.setf(std::ios::hex, std::ios::basefield);
798  intConversion = true;
799  break;
800  case 'E':
801  out.setf(std::ios::uppercase);
802  // Falls through
803  case 'e':
804  out.setf(std::ios::scientific, std::ios::floatfield);
805  out.setf(std::ios::dec, std::ios::basefield);
806  break;
807  case 'F':
808  out.setf(std::ios::uppercase);
809  // Falls through
810  case 'f':
811  out.setf(std::ios::fixed, std::ios::floatfield);
812  break;
813  case 'A':
814  out.setf(std::ios::uppercase);
815  // Falls through
816  case 'a':
817 # ifdef _MSC_VER
818  // Workaround https://developercommunity.visualstudio.com/content/problem/520472/hexfloat-stream-output-does-not-ignore-precision-a.html
819  // by always setting maximum precision on MSVC to avoid precision
820  // loss for doubles.
821  out.precision(13);
822 # endif
823  out.setf(std::ios::fixed | std::ios::scientific, std::ios::floatfield);
824  break;
825  case 'G':
826  out.setf(std::ios::uppercase);
827  // Falls through
828  case 'g':
829  out.setf(std::ios::dec, std::ios::basefield);
830  // As in boost::format, let stream decide float format.
831  out.flags(out.flags() & ~std::ios::floatfield);
832  break;
833  case 'c':
834  // Handled as special case inside formatValue()
835  break;
836  case 's':
837  if (precisionSet)
838  ntrunc = static_cast<int>(out.precision());
839  // Make %s print Booleans as "true" and "false"
840  out.setf(std::ios::boolalpha);
841  break;
842  case 'n':
843  // Not supported - will cause problems!
844  TINYFORMAT_ERROR("tinyformat: %n conversion spec not supported");
845  break;
846  case '\0':
847  TINYFORMAT_ERROR("tinyformat: Conversion spec incorrectly "
848  "terminated by end of string");
849  return c;
850  default:
851  break;
852  }
853  if (intConversion && precisionSet && !widthSet) {
854  // "precision" for integers gives the minimum number of digits (to be
855  // padded with zeros on the left). This isn't really supported by the
856  // iostreams, but we can approximately simulate it with the width if
857  // the width isn't otherwise used.
858  out.width(out.precision() + widthExtra);
859  out.setf(std::ios::internal, std::ios::adjustfield);
860  out.fill('0');
861  }
862  return c+1;
863 }

References parseIntAndAdvance(), parseWidthOrPrecision(), TINYFORMAT_ASSERT, and TINYFORMAT_ERROR.

Referenced by formatImpl().

Here is the call graph for this function:
tinyformat::detail::parseWidthOrPrecision
bool parseWidthOrPrecision(int &n, const char *&c, bool positionalMode, const detail::FormatArg *args, int &argIndex, int numArgs)
Definition: tinyformat.h:569
tinyformat::detail::streamStateFromFormat
const char * streamStateFromFormat(std::ostream &out, bool &positionalMode, bool &spacePadPositive, int &ntrunc, const char *fmtStart, const detail::FormatArg *args, int &argIndex, int numArgs)
Definition: tinyformat.h:659
n
var n
Definition: htmlJsChartistMin.h:15
tinyformat::detail::printFormatStringLiteral
const char * printFormatStringLiteral(std::ostream &out, const char *fmt)
Definition: tinyformat.h:607
i
size_t i
Definition: json11.h:663
tinyformat::detail::parseIntAndAdvance
int parseIntAndAdvance(const char *&c)
Definition: tinyformat.h:556
TINYFORMAT_ASSERT
#define TINYFORMAT_ASSERT(cond)
Definition: tinyformat.h:154
TINYFORMAT_ERROR
#define TINYFORMAT_ERROR(reason)
Definition: tinyformat.h:159