xref: /freebsd/contrib/llvm-project/libcxx/src/experimental/include/tzdb/tzdb_list_private.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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:
__impl()48   __impl() { __load_no_lock(); }
49 
__load()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 
__front()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 
__erase_after(const_iterator __p)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 
__begin()76   const_iterator __begin() const noexcept {
77 #ifndef _LIBCPP_HAS_NO_THREADS
78     unique_lock __lock{__mutex_};
79 #endif
80     return __tzdb_.begin();
81   }
__end()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.
__load_no_lock()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