mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-02 04:04:19 +00:00
Add define/ifdef blocks, alternate sprintf implementation via FLATBUFFERS_PREFER_PRINTF [C++] (#4700)
* Add define/ifdef blocks for FLATBUFFERS_PREFER_PRINTF to avoid using std::*streams for idl_parser * Use string::size() as limit in snprintf * Refactored FLATBUFFERS_PREFER_PRINTF guarded feature into NumToStringImplWrapper around sprintf * Remove '.0' where not needed from IntToDigitCount * Remove leading dot from name in GetFullyQualifiedName when FLATBUFFERS_PREFER_PRINTF is enabled * Return string directly from conversion functions where possible when FLATBUFFERS_PREFER_PRINTF is enabled * Use string instead of stringstream for GetFullyQualifiedName * Revert removing leading dot from GetFullyQualifiedName, it does need to be there for parity with the stringstream implementation * Dot is single char in Namespace::GetFullyQualifiedName * Remove trailing (duplicate) null-byte from NumToStringImplWrapper when using FLATBUFFERS_PREFER_PRINTF. * Update preprocessor indenting (and use clang-format off/on) for FLATBUFFERS_PREFER_PRINTF * Reduce whitespace, unneeded braces in FLATBUFFERS_PREFER_PRINTF string width functions * Remove unneeded use of iostream from idl_parser.cpp, std::string is used instead * Tell snprintf to use the trailing null byte expected at the end of std::string buffer
This commit is contained in:
committed by
Wouter van Oortmerssen
parent
a0a33d94a7
commit
7c1203d44c
@@ -22,7 +22,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
# include <sstream>
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
# include <float.h>
|
||||
# include <stdio.h>
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
@@ -45,13 +50,53 @@
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
#ifdef FLATBUFFERS_PREFER_PRINTF
|
||||
template<typename T> size_t IntToDigitCount(T t) {
|
||||
size_t digit_count = 0;
|
||||
// Count the sign for negative numbers
|
||||
if (t < 0) digit_count++;
|
||||
// Count a single 0 left of the dot for fractional numbers
|
||||
if (-1 < t && t < 1) digit_count++;
|
||||
// Count digits until fractional part
|
||||
T eps = std::numeric_limits<float>::epsilon();
|
||||
while (t <= (-1 + eps) || (1 - eps) <= t) {
|
||||
t /= 10;
|
||||
digit_count++;
|
||||
}
|
||||
return digit_count;
|
||||
}
|
||||
|
||||
template<typename T> size_t NumToStringWidth(T t, int precision = 0) {
|
||||
size_t string_width = IntToDigitCount(t);
|
||||
// Count the dot for floating point numbers
|
||||
if (precision) string_width += (precision + 1);
|
||||
return string_width;
|
||||
}
|
||||
|
||||
template<typename T> std::string NumToStringImplWrapper(T t, const char* fmt,
|
||||
int precision = 0) {
|
||||
size_t string_width = NumToStringWidth(t, precision);
|
||||
std::string s(string_width, 0x00);
|
||||
// Allow snprintf to use std::string trailing null to detect buffer overflow
|
||||
snprintf(const_cast<char*>(s.data()), (s.size()+1), fmt, precision, t);
|
||||
return s;
|
||||
}
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
|
||||
// Convert an integer or floating point value to a string.
|
||||
// In contrast to std::stringstream, "char" values are
|
||||
// converted to a string of digits, and we don't use scientific notation.
|
||||
template<typename T> std::string NumToString(T t) {
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
return ss.str();
|
||||
// clang-format off
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
std::stringstream ss;
|
||||
ss << t;
|
||||
return ss.str();
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
auto v = static_cast<long long>(t);
|
||||
return NumToStringImplWrapper(v, "%.*lld");
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
// clang-format on
|
||||
}
|
||||
// Avoid char types used as character data.
|
||||
template<> inline std::string NumToString<signed char>(signed char t) {
|
||||
@@ -77,15 +122,22 @@ inline std::string NumToString<unsigned long long>(unsigned long long t) {
|
||||
|
||||
// Special versions for floats/doubles.
|
||||
template<typename T> std::string FloatToString(T t, int precision) {
|
||||
// to_string() prints different numbers of digits for floats depending on
|
||||
// platform and isn't available on Android, so we use stringstream
|
||||
std::stringstream ss;
|
||||
// Use std::fixed to surpress scientific notation.
|
||||
ss << std::fixed;
|
||||
// Default precision is 6, we want that to be higher for doubles.
|
||||
ss << std::setprecision(precision);
|
||||
ss << t;
|
||||
auto s = ss.str();
|
||||
// clang-format off
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
// to_string() prints different numbers of digits for floats depending on
|
||||
// platform and isn't available on Android, so we use stringstream
|
||||
std::stringstream ss;
|
||||
// Use std::fixed to suppress scientific notation.
|
||||
ss << std::fixed;
|
||||
// Default precision is 6, we want that to be higher for doubles.
|
||||
ss << std::setprecision(precision);
|
||||
ss << t;
|
||||
auto s = ss.str();
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
auto v = static_cast<double>(t);
|
||||
auto s = NumToStringImplWrapper(v, "%0.*f", precision);
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
// clang-format on
|
||||
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
|
||||
auto p = s.find_last_not_of('0');
|
||||
if (p != std::string::npos) {
|
||||
@@ -106,10 +158,16 @@ template<> inline std::string NumToString<float>(float t) {
|
||||
// The returned string length is always xdigits long, prefixed by 0 digits.
|
||||
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
|
||||
inline std::string IntToStringHex(int i, int xdigits) {
|
||||
std::stringstream ss;
|
||||
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
|
||||
<< i;
|
||||
return ss.str();
|
||||
// clang-format off
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
std::stringstream ss;
|
||||
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
|
||||
<< i;
|
||||
return ss.str();
|
||||
#else // FLATBUFFERS_PREFER_PRINTF
|
||||
return NumToStringImplWrapper(i, "%.*X", xdigits);
|
||||
#endif // FLATBUFFERS_PREFER_PRINTF
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Portable implementation of strtoll().
|
||||
@@ -353,6 +411,7 @@ inline int FromUTF8(const char **in) {
|
||||
return ucc;
|
||||
}
|
||||
|
||||
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||
// Wraps a string to a maximum length, inserting new lines where necessary. Any
|
||||
// existing whitespace will be collapsed down to a single space. A prefix or
|
||||
// suffix can be provided, which will be inserted before or after a wrapped
|
||||
@@ -379,6 +438,7 @@ inline std::string WordWrap(const std::string in, size_t max_length,
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
#endif // !FLATBUFFERS_PREFER_PRINTF
|
||||
|
||||
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
bool allow_non_utf8, bool natural_utf8) {
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@@ -177,13 +177,16 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
|
||||
size_t max_components) const {
|
||||
// Early exit if we don't have a defined namespace.
|
||||
if (components.empty() || !max_components) { return name; }
|
||||
std::stringstream stream;
|
||||
std::string stream_str;
|
||||
for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
|
||||
if (i) { stream << "."; }
|
||||
stream << components[i];
|
||||
if (i) { stream_str += '.'; }
|
||||
stream_str += std::string(components[i]);
|
||||
}
|
||||
if (name.length()) stream << "." << name;
|
||||
return stream.str();
|
||||
if (name.length()) {
|
||||
stream_str += '.';
|
||||
stream_str += name;
|
||||
}
|
||||
return stream_str;
|
||||
}
|
||||
|
||||
// Declare tokens we'll use. Single character tokens are represented by their
|
||||
|
||||
Reference in New Issue
Block a user