Skip to content

Commit

Permalink
GH-43095: [C++] Update bundled vendor/datetime to support for buildin…
Browse files Browse the repository at this point in the history
…g with libc++ and C++20 (#43094)

### Rationale for this change

We can't build with libc++ and C++20:

CMake command line:

```bash
cmake -DARROW_ENABLE_THREADING=OFF \
 -DARROW_JEMALLOC=OFF \
-DCMAKE_CXX_STANDARD=20 \
-DCXX_ONLY_FLAGS="-stdlib=libc++" \
-DCMAKE_TOOLCHAIN_FILE=toolchain.cmake  --preset ninja-debug-minimal   ../cpp/
```

Error log:

```
In file included from ~/.conan2/p/b/arrowe39f77e638649/b/src/cpp/src/arrow/vendored/datetime/tz.cpp:90:
~/.conan2/p/b/arrowe39f77e638649/b/src/cpp/src/arrow/vendored/datetime/tz_private.h:295:12: error: use of overloaded operator '<<' is ambiguous (with operand types 'std::ostream' (aka 'basic_ostream<char>') and 'const sys_seconds' (aka 'const time_point<std::chrono::system_clock, std::chrono::duration<long long, std::ratio<1, 1>>>'))
  295 |         os << t.timepoint << "Z ";
      |         ~~ ^  ~~~~~~~~~~~
/usr/lib/llvm-17/bin/../include/c++/v1/__chrono/ostream.h:46:1: note: candidate function [with _CharT = char, _Traits = std::char_traits<char>, _Duration = std::chrono::duration<long long>]
   46 | operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_time<_Duration> __tp) {
      | ^
~/.conan2/p/b/arrowe39f77e638649/b/src/cpp/src/arrow/vendored/datetime/date.h:4214:1: note: candidate function [with CharT = char, Traits = std::char_traits<char>, Duration = std::chrono::duration<long long>]
 4214 | operator<<(std::basic_ostream<CharT, Traits>& os, const sys_time<Duration>& tp)
```

### What changes are included in this PR?

Update the bundled vendor/datetime because the upstream has changes for this case:
HowardHinnant/date#827

### Are these changes tested?

### Are there any user-facing changes?

* GitHub Issue: #43095

Authored-by: Benjamin Freist <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
  • Loading branch information
ben-freist authored Jul 12, 2024
1 parent 2d4c80b commit 7184150
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 23 deletions.
2 changes: 1 addition & 1 deletion cpp/src/arrow/vendored/datetime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ copies or substantial portions of the Software.
Sources for datetime are adapted from Howard Hinnant's date library
(https://github.com/HowardHinnant/date).

Sources are taken from changeset cc4685a21e4a4fdae707ad1233c61bbaff241f93
Sources are taken from changeset 1ead6715dec030d340a316c927c877a3c4e5a00c
of the above project.

The following changes are made:
Expand Down
27 changes: 19 additions & 8 deletions cpp/src/arrow/vendored/datetime/date.h
Original file line number Diff line number Diff line change
Expand Up @@ -4230,7 +4230,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const local_time<Duration>& ut)
{
return (os << sys_time<Duration>{ut.time_since_epoch()});
return (date::operator<<(os, sys_time<Duration>{ut.time_since_epoch()}));
}

namespace detail
Expand Down Expand Up @@ -6353,7 +6353,10 @@ read_signed(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M =
if (('0' <= c && c <= '9') || c == '-' || c == '+')
{
if (c == '-' || c == '+')
{
(void)is.get();
--M;
}
auto x = static_cast<int>(read_unsigned(is, std::max(m, 1u), M));
if (!is.fail())
{
Expand Down Expand Up @@ -6526,7 +6529,14 @@ read(std::basic_istream<CharT, Traits>& is, int a0, Args&& ...args)
*e++ = static_cast<CharT>(CharT(u % 10) + CharT{'0'});
u /= 10;
} while (u > 0);
#if defined(__GNUC__) && __GNUC__ >= 11
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
std::reverse(buf, e);
#if defined(__GNUC__) && __GNUC__ >= 11
#pragma GCC diagnostic pop
#endif
for (auto p = buf; p != e && is.rdstate() == std::ios::goodbit; ++p)
read(is, *p);
}
Expand Down Expand Up @@ -6592,7 +6602,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,

CONSTDATA int not_a_year = numeric_limits<short>::min();
CONSTDATA int not_a_2digit_year = 100;
CONSTDATA int not_a_century = not_a_year / 100;
CONSTDATA int not_a_century = numeric_limits<int>::min();
CONSTDATA int not_a_month = 0;
CONSTDATA int not_a_day = 0;
CONSTDATA int not_a_hour = numeric_limits<int>::min();
Expand Down Expand Up @@ -7519,7 +7529,12 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
{
auto c = static_cast<char>(Traits::to_char_type(ic));
if (c == '-')
{
neg = true;
(void)is.get();
}
else if (c == '+')
(void)is.get();
}
if (modified == CharT{})
{
Expand Down Expand Up @@ -7735,9 +7750,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
year_month_day ymd_trial = sys_days(year{Y}/January/Sunday[1]) +
weeks{U-1} +
(weekday{static_cast<unsigned>(wd)} - Sunday);
if (Y == not_a_year)
Y = static_cast<int>(ymd_trial.year());
else if (year{Y} != ymd_trial.year())
if (year{Y} != ymd_trial.year())
goto broken;
if (m == not_a_month)
m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
Expand All @@ -7754,9 +7767,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
year_month_day ymd_trial = sys_days(year{Y}/January/Monday[1]) +
weeks{W-1} +
(weekday{static_cast<unsigned>(wd)} - Monday);
if (Y == not_a_year)
Y = static_cast<int>(ymd_trial.year());
else if (year{Y} != ymd_trial.year())
if (year{Y} != ymd_trial.year())
goto broken;
if (m == not_a_month)
m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
Expand Down
95 changes: 85 additions & 10 deletions cpp/src/arrow/vendored/datetime/tz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@
# define TARGET_OS_SIMULATOR 0
#endif

#if defined(ANDROID) || defined(__ANDROID__)
#include <sys/system_properties.h>
#endif

#if USE_OS_TZDB
# include <dirent.h>
#endif
Expand Down Expand Up @@ -2709,7 +2713,8 @@ operator<<(std::ostream& os, const time_zone& z)
os.width(8);
os << s.format_ << " ";
os << s.until_year_ << ' ' << s.until_date_;
os << " " << s.until_utc_ << " UTC";
os << " ";
date::operator<<(os, s.until_utc_) << " UTC";
os << " " << s.until_std_ << " STD";
os << " " << s.until_loc_;
os << " " << make_time(s.initial_save_);
Expand All @@ -2734,8 +2739,7 @@ operator<<(std::ostream& os, const time_zone& z)
std::ostream&
operator<<(std::ostream& os, const leap_second& x)
{
using namespace date;
return os << x.date_ << " +";
return date::operator<<(os, x.date_) << " +";
}

#if USE_OS_TZDB
Expand Down Expand Up @@ -3716,13 +3720,78 @@ get_tzdb()
return get_tzdb_list().front();
}

namespace {

class recursion_limiter
{
unsigned depth_ = 0;
unsigned limit_;

class restore_recursion_depth;

public:
recursion_limiter(recursion_limiter const&) = delete;
recursion_limiter& operator=(recursion_limiter const&) = delete;

explicit constexpr recursion_limiter(unsigned limit) noexcept;

restore_recursion_depth count();
};

class recursion_limiter::restore_recursion_depth
{
recursion_limiter* rc_;

public:
~restore_recursion_depth();
restore_recursion_depth(restore_recursion_depth&&) = default;

explicit restore_recursion_depth(recursion_limiter* rc) noexcept;
};

inline
recursion_limiter::restore_recursion_depth::~restore_recursion_depth()
{
--(rc_->depth_);
}

inline
recursion_limiter::restore_recursion_depth::restore_recursion_depth(recursion_limiter* rc)
noexcept
: rc_{rc}
{}

inline
constexpr
recursion_limiter::recursion_limiter(unsigned limit) noexcept
: limit_{limit}
{
}

inline
recursion_limiter::restore_recursion_depth
recursion_limiter::count()
{
++depth_;
if (depth_ > limit_)
throw std::runtime_error("recursion limit of " +
std::to_string(limit_) + " exceeded");
return restore_recursion_depth{this};
}

} // unnamed namespace

const time_zone*
#if HAS_STRING_VIEW
tzdb::locate_zone(std::string_view tz_name) const
#else
tzdb::locate_zone(const std::string& tz_name) const
#endif
{
// If a link-to-link chain exceeds this limit, give up
thread_local recursion_limiter rc{10};
auto restore_count = rc.count();

auto zi = std::lower_bound(zones.begin(), zones.end(), tz_name,
#if HAS_STRING_VIEW
[](const time_zone& z, const std::string_view& nm)
Expand All @@ -3746,13 +3815,7 @@ tzdb::locate_zone(const std::string& tz_name) const
});
if (li != links.end() && li->name() == tz_name)
{
zi = std::lower_bound(zones.begin(), zones.end(), li->target(),
[](const time_zone& z, const std::string& nm)
{
return z.name() < nm;
});
if (zi != zones.end() && zi->name() == li->target())
return &*zi;
return locate_zone(li->target());
}
#endif // !USE_OS_TZDB
throw std::runtime_error(std::string(tz_name) + " not found in timezone database");
Expand Down Expand Up @@ -4038,6 +4101,18 @@ tzdb::current_zone() const
if (!result.empty())
return locate_zone(result);
#endif
// Fall through to try other means.
}
{
// On Android, it is not possible to use file based approach either,
// we have to ask the value of `persist.sys.timezone` system property
#if defined(ANDROID) || defined(__ANDROID__)
char sys_timezone[PROP_VALUE_MAX];
if (__system_property_get("persist.sys.timezone", sys_timezone) > 0)
{
return locate_zone(sys_timezone);
}
#endif // defined(ANDROID) || defined(__ANDROID__)
// Fall through to try other means.
}
{
Expand Down
4 changes: 2 additions & 2 deletions cpp/src/arrow/vendored/datetime/tz.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ nonexistent_local_time::make_msg(local_time<Duration> tp, const local_info& i)
<< i.first.abbrev << " and\n"
<< local_seconds{i.second.begin.time_since_epoch()} + i.second.offset << ' '
<< i.second.abbrev
<< " which are both equivalent to\n"
<< i.first.end << " UTC";
<< " which are both equivalent to\n";
date::operator<<(os, i.first.end) << " UTC";
return os.str();
}

Expand Down
3 changes: 1 addition & 2 deletions cpp/src/arrow/vendored/datetime/tz_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,7 @@ struct transition
std::ostream&
operator<<(std::ostream& os, const transition& t)
{
using date::operator<<;
os << t.timepoint << "Z ";
date::operator<<(os, t.timepoint) << "Z ";
if (t.info->offset >= std::chrono::seconds{0})
os << '+';
os << make_time(t.info->offset);
Expand Down

0 comments on commit 7184150

Please sign in to comment.