Skip to content

Commit

Permalink
patch android + gcc locale issue
Browse files Browse the repository at this point in the history
SFINAE workaround for missing lconv support in Android (gcc + libstdc++)
See: fmtlib/fmt@2fd6c0b

Discussion: nlohmann#638 (comment)
Note: Clang + libc++ should work (where available)

Returns the thousands separator for the current locale.
On android (gcc/libstdc++) the lconv structure is stubbed using an empty structure
The test is for the size only, not for the presense of
thousands_sep in std::lconv, because if one would add thousands_sep
at some point, the size of structure would be at least sizeof(char*)

Ditto for decimal_point.
  • Loading branch information
headupinclouds committed Aug 9, 2017
1 parent 850d856 commit f7308e9
Showing 1 changed file with 42 additions and 5 deletions.
47 changes: 42 additions & 5 deletions src/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,44 @@ SOFTWARE.
#define JSON_UNLIKELY(x) x
#endif

namespace nlohmann
{
namespace internal
{
// SFINAE workaround for missing lconv support in Android (gcc + libstdc++)
// See: https://github.com/fmtlib/fmt/commit/2fd6c0b24524f7ef107090d08cd86cdeb98fdac0
//
// Discussion: https://github.com/nlohmann/json/issues/638#issuecomment-314079985
// Note: Clang + libc++ should work (where available)
//
// Returns the thousands separator for the current locale.
// On android (gcc/libstdc++) the lconv structure is stubbed using an empty structure
// The test is for the size only, not for the presense of
// thousands_sep in std::lconv, because if one would add thousands_sep
// at some point, the size of structure would be at least sizeof(char*)
//
// Ditto for decimal_point.
template<typename Lconv, bool=(sizeof(Lconv) >= sizeof(char*))>
struct Locale
{
static char * thousands_sep() { return ""; }
static char * decimal_point() { return "."; }
};

template<typename Lconv>
struct Locale<Lconv, true>
{
static char * thousands_sep() { return static_cast<Lconv*>(std::localeconv())->thousands_sep; }
static char * decimal_point() { return static_cast<Lconv*>(std::localeconv())->decimal_point; }
};

inline char first_or_null(const char *str)
{
return str == nullptr ? '\0' : str[0];
}
}
}

/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
Expand Down Expand Up @@ -1652,9 +1690,7 @@ class lexer
/// return the locale-dependent decimal point
static char get_decimal_point() noexcept
{
const auto loc = localeconv();
assert(loc != nullptr);
return (loc->decimal_point == nullptr) ? '.' : loc->decimal_point[0];
return first_or_null(internal::Locale<lconv>::decimal_point());
}

/////////////////////
Expand Down Expand Up @@ -6145,10 +6181,11 @@ class serializer
@param[in] s output stream to serialize to
@param[in] ichar indentation character to use
*/

serializer(output_adapter_t<char> s, const char ichar)
: o(s), loc(std::localeconv()),
thousands_sep(loc->thousands_sep == nullptr ? '\0' : loc->thousands_sep[0]),
decimal_point(loc->decimal_point == nullptr ? '\0' : loc->decimal_point[0]),
thousands_sep(first_or_null(internal::Locale<lconv>::thousands_sep())),
decimal_point(first_or_null(internal::Locale<lconv>::decimal_point())),
indent_char(ichar), indent_string(512, indent_char) {}

// delete because of pointer members
Expand Down

0 comments on commit f7308e9

Please sign in to comment.