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 #ifndef _LIBCPP_HAS_NO_THREADS 19 # include <shared_mutex> 20 #endif 21 22 #include "types_private.h" 23 #include "tzdb_private.h" 24 25 _LIBCPP_BEGIN_NAMESPACE_STD 26 27 namespace chrono { 28 29 //===----------------------------------------------------------------------===// 30 // Private API 31 //===----------------------------------------------------------------------===// 32 33 // The tzdb_list stores a list of "tzdb" entries. 34 // 35 // The public tzdb database does not store the RULE entries of the IANA 36 // database. These entries are considered an implementation detail. Since most 37 // of the tzdb_list interface is exposed as "a list of tzdb entries" it's not 38 // possible to use a helper struct that stores a tzdb and the RULE database. 39 // Instead this class stores these in parallel forward lists. 40 // 41 // Since the nodes of a forward_list are stable it's possible to store pointers 42 // and references to these nodes. 43 class tzdb_list::__impl { 44 public: __impl()45 __impl() { __load_no_lock(); } 46 __load()47 [[nodiscard]] const tzdb& __load() { 48 #ifndef _LIBCPP_HAS_NO_THREADS 49 unique_lock __lock{__mutex_}; 50 #endif 51 __load_no_lock(); 52 return __tzdb_.front(); 53 } 54 55 using const_iterator = tzdb_list::const_iterator; 56 __front()57 const tzdb& __front() const noexcept { 58 #ifndef _LIBCPP_HAS_NO_THREADS 59 shared_lock __lock{__mutex_}; 60 #endif 61 return __tzdb_.front(); 62 } 63 __erase_after(const_iterator __p)64 const_iterator __erase_after(const_iterator __p) { 65 #ifndef _LIBCPP_HAS_NO_THREADS 66 unique_lock __lock{__mutex_}; 67 #endif 68 69 __rules_.erase_after(std::next(__rules_.cbegin(), std::distance(__tzdb_.cbegin(), __p))); 70 return __tzdb_.erase_after(__p); 71 } 72 __begin()73 const_iterator __begin() const noexcept { 74 #ifndef _LIBCPP_HAS_NO_THREADS 75 shared_lock __lock{__mutex_}; 76 #endif 77 return __tzdb_.begin(); 78 } __end()79 const_iterator __end() const noexcept { 80 // forward_list<T>::end does not access the list, so no need to take a lock. 81 return __tzdb_.end(); 82 } 83 84 private: 85 // Loads the tzdbs 86 // pre: The caller ensures the locking, if needed, is done. __load_no_lock()87 void __load_no_lock() { chrono::__init_tzdb(__tzdb_.emplace_front(), __rules_.emplace_front()); } 88 89 #ifndef _LIBCPP_HAS_NO_THREADS 90 mutable shared_mutex __mutex_; 91 #endif 92 forward_list<tzdb> __tzdb_; 93 94 forward_list<__tz::__rules_storage_type> __rules_; 95 }; 96 97 } // namespace chrono 98 99 _LIBCPP_END_NAMESPACE_STD 100 101 #endif // _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H 102