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