Repository: fmtlib/fmt
File: include/fmt/chrono.h (C/C++)

Code before:
// Prevents expansion of a preceding token as a function-style macro.
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO

namespace detail {
template <typename T = void> struct null {};
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }

inline auto do_write(const std::tm& time, const std::locale& loc, char format,
                     char modifier) -> std::string {
  auto&& os = std::ostringstream();
  os.imbue(loc);
  using iterator = std::ostreambuf_iterator<char>;
  const auto& facet = std::use_facet<std::time_put<char, iterator>>(loc);
  auto end = facet.put(os, os, ' ', &time, format, modifier);
  if (end.failed()) FMT_THROW(format_error("failed to format time"));
  auto str = os.str();
  if (!detail::is_utf8() || loc == std::locale::classic()) return str;
    // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
    // gcc-4.
#if FMT_MSC_VER != 0 || \
    (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
  // macro _GLIBCXX_USE_DUAL_ABI is always defined in libstdc++ from gcc-5+
  using code_unit = wchar_t;
#else
  using code_unit = char32_t;
#endif
  auto& f = std::use_facet<std::codecvt<code_unit, char, std::mbstate_t>>(loc);
  auto mb = std::mbstate_t();
  const char* from_next = nullptr;
  code_unit* to_next = nullptr;
  constexpr size_t buf_size = 32;
  code_unit buf[buf_size] = {};
  auto result = f.in(mb, str.data(), str.data() + str.size(), from_next, buf,
                     buf + buf_size, to_next);
  if (result != std::codecvt_base::ok)
    FMT_THROW(format_error("failed to format time"));
  str.clear();
  for (code_unit* p = buf; p != to_next; ++p) {
    uint32_t c = static_cast<uint32_t>(*p);
    if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) {
      // surrogate pair
      ++p;
      if (p == to_next || (c & 0xfffffc00) != 0xd800 ||
          (static_cast<uint32_t>(*p) & 0xfffffc00) != 0xdc00) {
        FMT_THROW(format_error("failed to format time"));
      }
      c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;

Review comment (suggestion):
I suggest checking `__GLIBCXX__` version instead of relying on some unrelated macro (`_GLIBCXX_USE_DUAL_ABI`).

Code after:
// Prevents expansion of a preceding token as a function-style macro.
// Usage: f FMT_NOMACRO()
#define FMT_NOMACRO

namespace detail {
template <typename T = void> struct null {};
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }

inline auto do_write(const std::tm& time, const std::locale& loc, char format,
                     char modifier) -> std::string {
  auto&& os = std::ostringstream();
  os.imbue(loc);
  using iterator = std::ostreambuf_iterator<char>;
  const auto& facet = std::use_facet<std::time_put<char, iterator>>(loc);
  auto end = facet.put(os, os, ' ', &time, format, modifier);
  if (end.failed()) FMT_THROW(format_error("failed to format time"));
  auto str = os.str();
  if (!detail::is_utf8() || loc == std::locale::classic()) return str;
    // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
    // gcc-4.
#if FMT_MSC_VER != 0 || \
    (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
  // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
  // and newer.
  using code_unit = wchar_t;
#else
  using code_unit = char32_t;
#endif
  auto& f = std::use_facet<std::codecvt<code_unit, char, std::mbstate_t>>(loc);
  auto mb = std::mbstate_t();
  const char* from_next = nullptr;
  code_unit* to_next = nullptr;
  constexpr size_t buf_size = 32;
  code_unit buf[buf_size] = {};
  auto result = f.in(mb, str.data(), str.data() + str.size(), from_next, buf,
                     buf + buf_size, to_next);
  if (result != std::codecvt_base::ok)
    FMT_THROW(format_error("failed to format time"));
  str.clear();
  for (code_unit* p = buf; p != to_next; ++p) {
    uint32_t c = static_cast<uint32_t>(*p);
    if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) {
      // surrogate pair
      ++p;
      if (p == to_next || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
        FMT_THROW(format_error("failed to format time"));
      }
      c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;