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
30namespace 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.
46class tzdb_list::__impl {
47public:
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
87private:
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