mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-28 20:20:00 +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 <stdlib.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iomanip>
|
#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>
|
#include <string>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# ifndef WIN32_LEAN_AND_MEAN
|
# ifndef WIN32_LEAN_AND_MEAN
|
||||||
@@ -45,13 +50,53 @@
|
|||||||
|
|
||||||
namespace flatbuffers {
|
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.
|
// Convert an integer or floating point value to a string.
|
||||||
// In contrast to std::stringstream, "char" values are
|
// In contrast to std::stringstream, "char" values are
|
||||||
// converted to a string of digits, and we don't use scientific notation.
|
// converted to a string of digits, and we don't use scientific notation.
|
||||||
template<typename T> std::string NumToString(T t) {
|
template<typename T> std::string NumToString(T t) {
|
||||||
std::stringstream ss;
|
// clang-format off
|
||||||
ss << t;
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
return ss.str();
|
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.
|
// Avoid char types used as character data.
|
||||||
template<> inline std::string NumToString<signed char>(signed char t) {
|
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.
|
// Special versions for floats/doubles.
|
||||||
template<typename T> std::string FloatToString(T t, int precision) {
|
template<typename T> std::string FloatToString(T t, int precision) {
|
||||||
// to_string() prints different numbers of digits for floats depending on
|
// clang-format off
|
||||||
// platform and isn't available on Android, so we use stringstream
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
std::stringstream ss;
|
// to_string() prints different numbers of digits for floats depending on
|
||||||
// Use std::fixed to surpress scientific notation.
|
// platform and isn't available on Android, so we use stringstream
|
||||||
ss << std::fixed;
|
std::stringstream ss;
|
||||||
// Default precision is 6, we want that to be higher for doubles.
|
// Use std::fixed to suppress scientific notation.
|
||||||
ss << std::setprecision(precision);
|
ss << std::fixed;
|
||||||
ss << t;
|
// Default precision is 6, we want that to be higher for doubles.
|
||||||
auto s = ss.str();
|
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.
|
// Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
|
||||||
auto p = s.find_last_not_of('0');
|
auto p = s.find_last_not_of('0');
|
||||||
if (p != std::string::npos) {
|
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.
|
// The returned string length is always xdigits long, prefixed by 0 digits.
|
||||||
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
|
// For example, IntToStringHex(0x23, 8) returns the string "00000023".
|
||||||
inline std::string IntToStringHex(int i, int xdigits) {
|
inline std::string IntToStringHex(int i, int xdigits) {
|
||||||
std::stringstream ss;
|
// clang-format off
|
||||||
ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
<< i;
|
std::stringstream ss;
|
||||||
return ss.str();
|
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().
|
// Portable implementation of strtoll().
|
||||||
@@ -353,6 +411,7 @@ inline int FromUTF8(const char **in) {
|
|||||||
return ucc;
|
return ucc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef FLATBUFFERS_PREFER_PRINTF
|
||||||
// Wraps a string to a maximum length, inserting new lines where necessary. Any
|
// 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
|
// 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
|
// 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;
|
return wrapped;
|
||||||
}
|
}
|
||||||
|
#endif // !FLATBUFFERS_PREFER_PRINTF
|
||||||
|
|
||||||
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||||
bool allow_non_utf8, bool natural_utf8) {
|
bool allow_non_utf8, bool natural_utf8) {
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@@ -177,13 +177,16 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
|
|||||||
size_t max_components) const {
|
size_t max_components) const {
|
||||||
// Early exit if we don't have a defined namespace.
|
// Early exit if we don't have a defined namespace.
|
||||||
if (components.empty() || !max_components) { return name; }
|
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++) {
|
for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
|
||||||
if (i) { stream << "."; }
|
if (i) { stream_str += '.'; }
|
||||||
stream << components[i];
|
stream_str += std::string(components[i]);
|
||||||
}
|
}
|
||||||
if (name.length()) stream << "." << name;
|
if (name.length()) {
|
||||||
return stream.str();
|
stream_str += '.';
|
||||||
|
stream_str += name;
|
||||||
|
}
|
||||||
|
return stream_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Declare tokens we'll use. Single character tokens are represented by their
|
// Declare tokens we'll use. Single character tokens are represented by their
|
||||||
|
|||||||
Reference in New Issue
Block a user