1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html |
10 | |
11 | #ifndef _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H |
12 | #define _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H |
13 | |
14 | #include <__mutex/unique_lock.h> |
15 | #include <forward_list> |
16 | |
17 | // When threads are not available the locking is not required. |
18 | // When threads are available, we use std::mutex over std::shared_mutex |
19 | // due to the increased overhead of std::shared_mutex. |
20 | // See shared_mutex_vs_mutex.bench.cpp |
21 | #ifndef _LIBCPP_HAS_NO_THREADS |
22 | # include <mutex> |
23 | #endif |
24 | |
25 | #include "types_private.h" |
26 | #include "tzdb_private.h" |
27 | |
28 | _LIBCPP_BEGIN_NAMESPACE_STD |
29 | |
30 | namespace chrono { |
31 | |
32 | //===----------------------------------------------------------------------===// |
33 | // Private API |
34 | //===----------------------------------------------------------------------===// |
35 | |
36 | // The tzdb_list stores a list of "tzdb" entries. |
37 | // |
38 | // The public tzdb database does not store the RULE entries of the IANA |
39 | // database. These entries are considered an implementation detail. Since most |
40 | // of the tzdb_list interface is exposed as "a list of tzdb entries" it's not |
41 | // possible to use a helper struct that stores a tzdb and the RULE database. |
42 | // Instead this class stores these in parallel forward lists. |
43 | // |
44 | // Since the nodes of a forward_list are stable it's possible to store pointers |
45 | // and references to these nodes. |
46 | class tzdb_list::__impl { |
47 | public: |
48 | __impl() { __load_no_lock(); } |
49 | |
50 | [[nodiscard]] const tzdb& __load() { |
51 | #ifndef _LIBCPP_HAS_NO_THREADS |
52 | unique_lock __lock{__mutex_}; |
53 | #endif |
54 | __load_no_lock(); |
55 | return __tzdb_.front(); |
56 | } |
57 | |
58 | using const_iterator = tzdb_list::const_iterator; |
59 | |
60 | const tzdb& __front() const noexcept { |
61 | #ifndef _LIBCPP_HAS_NO_THREADS |
62 | unique_lock __lock{__mutex_}; |
63 | #endif |
64 | return __tzdb_.front(); |
65 | } |
66 | |
67 | const_iterator __erase_after(const_iterator __p) { |
68 | #ifndef _LIBCPP_HAS_NO_THREADS |
69 | unique_lock __lock{__mutex_}; |
70 | #endif |
71 | |
72 | __rules_.erase_after(std::next(__rules_.cbegin(), std::distance(__tzdb_.cbegin(), __p))); |
73 | return __tzdb_.erase_after(__p); |
74 | } |
75 | |
76 | const_iterator __begin() const noexcept { |
77 | #ifndef _LIBCPP_HAS_NO_THREADS |
78 | unique_lock __lock{__mutex_}; |
79 | #endif |
80 | return __tzdb_.begin(); |
81 | } |
82 | const_iterator __end() const noexcept { |
83 | // forward_list<T>::end does not access the list, so no need to take a lock. |
84 | return __tzdb_.end(); |
85 | } |
86 | |
87 | private: |
88 | // Loads the tzdbs |
89 | // pre: The caller ensures the locking, if needed, is done. |
90 | void __load_no_lock() { chrono::__init_tzdb(__tzdb_.emplace_front(), __rules_.emplace_front()); } |
91 | |
92 | #ifndef _LIBCPP_HAS_NO_THREADS |
93 | mutable mutex __mutex_; |
94 | #endif |
95 | forward_list<tzdb> __tzdb_; |
96 | |
97 | forward_list<__tz::__rules_storage_type> __rules_; |
98 | }; |
99 | |
100 | } // namespace chrono |
101 | |
102 | _LIBCPP_END_NAMESPACE_STD |
103 | |
104 | #endif // _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H |
105 | |