Coverage Report

Created: 2025-12-03 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/abseil-cpp/absl/time/internal/cctz/src/time_zone_impl.cc
Line
Count
Source
1
// Copyright 2016 Google Inc. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//   https://www.apache.org/licenses/LICENSE-2.0
8
//
9
//   Unless required by applicable law or agreed to in writing, software
10
//   distributed under the License is distributed on an "AS IS" BASIS,
11
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//   See the License for the specific language governing permissions and
13
//   limitations under the License.
14
15
#include "absl/time/internal/cctz/src/time_zone_impl.h"
16
17
#include <deque>
18
#include <memory>
19
#include <mutex>
20
#include <string>
21
#include <unordered_map>
22
#include <utility>
23
24
#include "absl/base/config.h"
25
#include "absl/time/internal/cctz/src/time_zone_fixed.h"
26
27
namespace absl {
28
ABSL_NAMESPACE_BEGIN
29
namespace time_internal {
30
namespace cctz {
31
32
namespace {
33
34
// time_zone::Impls are linked into a map to support fast lookup by name.
35
using TimeZoneImplByName =
36
    std::unordered_map<std::string, const time_zone::Impl*>;
37
TimeZoneImplByName* time_zone_map = nullptr;
38
39
// Mutual exclusion for time_zone_map.
40
0
std::mutex& TimeZoneMutex() {
41
  // This mutex is intentionally "leaked" to avoid the static deinitialization
42
  // order fiasco (std::mutex's destructor is not trivial on many platforms).
43
0
  static std::mutex* time_zone_mutex = new std::mutex;
44
0
  return *time_zone_mutex;
45
0
}
46
47
}  // namespace
48
49
0
time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); }
50
51
0
bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
52
0
  const Impl* const utc_impl = UTCImpl();
53
54
  // Check for UTC (which is never a key in time_zone_map).
55
0
  auto offset = seconds::zero();
56
0
  if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
57
0
    *tz = time_zone(utc_impl);
58
0
    return true;
59
0
  }
60
61
  // Check whether the time zone has already been loaded.
62
0
  {
63
0
    std::lock_guard<std::mutex> lock(TimeZoneMutex());
64
0
    if (time_zone_map != nullptr) {
65
0
      TimeZoneImplByName::const_iterator itr = time_zone_map->find(name);
66
0
      if (itr != time_zone_map->end()) {
67
0
        *tz = time_zone(itr->second);
68
0
        return itr->second != utc_impl;
69
0
      }
70
0
    }
71
0
  }
72
73
  // Load the new time zone (outside the lock).
74
0
  std::unique_ptr<const Impl> new_impl(new Impl(name));
75
76
  // Add the new time zone to the map.
77
0
  std::lock_guard<std::mutex> lock(TimeZoneMutex());
78
0
  if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
79
0
  const Impl*& impl = (*time_zone_map)[name];
80
0
  if (impl == nullptr) {  // this thread won any load race
81
0
    impl = new_impl->zone_ ? new_impl.release() : utc_impl;
82
0
  }
83
0
  *tz = time_zone(impl);
84
0
  return impl != utc_impl;
85
0
}
86
87
0
void time_zone::Impl::ClearTimeZoneMapTestOnly() {
88
0
  std::lock_guard<std::mutex> lock(TimeZoneMutex());
89
0
  if (time_zone_map != nullptr) {
90
    // Existing time_zone::Impl* entries are in the wild, so we can't delete
91
    // them. Instead, we move them to a private container, where they are
92
    // logically unreachable but not "leaked".  Future requests will result
93
    // in reloading the data.
94
0
    static auto* cleared = new std::deque<const time_zone::Impl*>;
95
0
    for (const auto& element : *time_zone_map) {
96
0
      cleared->push_back(element.second);
97
0
    }
98
0
    time_zone_map->clear();
99
0
  }
100
0
}
101
102
0
time_zone::Impl::Impl() : name_("UTC"), zone_(TimeZoneIf::UTC()) {}
103
104
time_zone::Impl::Impl(const std::string& name)
105
0
    : name_(name), zone_(TimeZoneIf::Make(name_)) {}
106
107
0
const time_zone::Impl* time_zone::Impl::UTCImpl() {
108
0
  static const Impl* utc_impl = new Impl;
109
0
  return utc_impl;
110
0
}
111
112
}  // namespace cctz
113
}  // namespace time_internal
114
ABSL_NAMESPACE_END
115
}  // namespace absl