aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/cxxsupp/libcxx/include/__chrono/exception.h
blob: 266f8fac441760672b982777ed5607c220b09998 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html

#ifndef _LIBCPP___CHRONO_EXCEPTION_H
#define _LIBCPP___CHRONO_EXCEPTION_H

#include <version>
// Enable the contents of the header only when libc++ was built with experimental features enabled.
#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)

#  include <__chrono/calendar.h>
#  include <__chrono/local_info.h>
#  include <__chrono/time_point.h>
#  include <__config>
#  include <__configuration/availability.h>
#  include <__verbose_abort>
#  include <format>
#  include <stdexcept>
#  include <string>

#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#    pragma GCC system_header
#  endif

_LIBCPP_BEGIN_NAMESPACE_STD

#  if _LIBCPP_STD_VER >= 20

namespace chrono {

class nonexistent_local_time : public runtime_error {
public:
  template <class _Duration>
  _LIBCPP_HIDE_FROM_ABI nonexistent_local_time(const local_time<_Duration>& __time, const local_info& __info)
      : runtime_error{__create_message(__time, __info)} {
    // [time.zone.exception.nonexist]/2
    //   Preconditions: i.result == local_info::nonexistent is true.
    // The value of __info.result is not used.
    _LIBCPP_ASSERT_PEDANTIC(__info.result == local_info::nonexistent,
                            "creating an nonexistent_local_time from a local_info that is not non-existent");
  }

  _LIBCPP_HIDE_FROM_ABI nonexistent_local_time(const nonexistent_local_time&)            = default;
  _LIBCPP_HIDE_FROM_ABI nonexistent_local_time& operator=(const nonexistent_local_time&) = default;

  _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI ~nonexistent_local_time() override; // exported as key function

private:
  template <class _Duration>
  _LIBCPP_HIDE_FROM_ABI string __create_message(const local_time<_Duration>& __time, const local_info& __info) {
    return std::format(
        R"({} is in a gap between
{} {} and
{} {} which are both equivalent to
{} UTC)",
        __time,
        local_seconds{__info.first.end.time_since_epoch()} + __info.first.offset,
        __info.first.abbrev,
        local_seconds{__info.second.begin.time_since_epoch()} + __info.second.offset,
        __info.second.abbrev,
        __info.first.end);
  }
};

template <class _Duration>
_LIBCPP_NORETURN _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI void __throw_nonexistent_local_time(
    [[maybe_unused]] const local_time<_Duration>& __time, [[maybe_unused]] const local_info& __info) {
#    ifndef _LIBCPP_HAS_NO_EXCEPTIONS
  throw nonexistent_local_time(__time, __info);
#    else
  _LIBCPP_VERBOSE_ABORT("nonexistent_local_time was thrown in -fno-exceptions mode");
#    endif
}

class ambiguous_local_time : public runtime_error {
public:
  template <class _Duration>
  _LIBCPP_HIDE_FROM_ABI ambiguous_local_time(const local_time<_Duration>& __time, const local_info& __info)
      : runtime_error{__create_message(__time, __info)} {
    // [time.zone.exception.ambig]/2
    //   Preconditions: i.result == local_info::ambiguous is true.
    // The value of __info.result is not used.
    _LIBCPP_ASSERT_PEDANTIC(__info.result == local_info::ambiguous,
                            "creating an ambiguous_local_time from a local_info that is not ambiguous");
  }

  _LIBCPP_HIDE_FROM_ABI ambiguous_local_time(const ambiguous_local_time&)            = default;
  _LIBCPP_HIDE_FROM_ABI ambiguous_local_time& operator=(const ambiguous_local_time&) = default;

  _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI ~ambiguous_local_time() override; // exported as key function

private:
  template <class _Duration>
  _LIBCPP_HIDE_FROM_ABI string __create_message(const local_time<_Duration>& __time, const local_info& __info) {
    return std::format(
        // There are two spaces after the full-stop; this has been verified
        // in the sources of the Standard.
        R"({0} is ambiguous.  It could be
{0} {1} == {2} UTC or
{0} {3} == {4} UTC)",
        __time,
        __info.first.abbrev,
        __time - __info.first.offset,
        __info.second.abbrev,
        __time - __info.second.offset);
  }
};

template <class _Duration>
_LIBCPP_NORETURN _LIBCPP_AVAILABILITY_TZDB _LIBCPP_HIDE_FROM_ABI void __throw_ambiguous_local_time(
    [[maybe_unused]] const local_time<_Duration>& __time, [[maybe_unused]] const local_info& __info) {
#    ifndef _LIBCPP_HAS_NO_EXCEPTIONS
  throw ambiguous_local_time(__time, __info);
#    else
  _LIBCPP_VERBOSE_ABORT("ambiguous_local_time was thrown in -fno-exceptions mode");
#    endif
}

} // namespace chrono

#  endif // _LIBCPP_STD_VER >= 20

_LIBCPP_END_NAMESPACE_STD

#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)

#endif // _LIBCPP___CHRONO_EXCEPTION_H