master
  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#if _LIBCPP_HAS_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#if _LIBCPP_HAS_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#if _LIBCPP_HAS_THREADS
 62    unique_lock __lock{__mutex_};
 63#endif
 64    return __tzdb_.front();
 65  }
 66
 67  const_iterator __erase_after(const_iterator __p) {
 68#if _LIBCPP_HAS_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#if _LIBCPP_HAS_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#if _LIBCPP_HAS_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