AceTime  1.2
Date and time classes for Arduino that support timezones from the TZ Database, and a system clock that can synchronize from an NTP server or an RTC chip.
ZoneRegistrar.h
1 /*
2  * MIT License
3  * Copyright (c) 2019 Brian T. Park
4  */
5 
6 #ifndef ACE_TIME_ZONE_REGISTRAR_H
7 #define ACE_TIME_ZONE_REGISTRAR_H
8 
9 #include <stdint.h>
10 #include <string.h> // strcmp(), strcmp_P()
11 #include <AceCommon.h> // strcmp_PP()
12 #include "common/compat.h"
13 #include "internal/ZoneInfo.h"
14 #include "internal/Brokers.h"
15 
16 class BasicZoneRegistrarTest_Sorted_isSorted;
17 class BasicZoneRegistrarTest_Sorted_linearSearch;
18 class BasicZoneRegistrarTest_Sorted_linearSearch_not_found;
19 class BasicZoneRegistrarTest_Sorted_binarySearch;
20 class BasicZoneRegistrarTest_Sorted_binarySearch_not_found;
21 class BasicZoneRegistrarTest_Unsorted_isSorted;
22 class BasicZoneRegistrarTest_Unsorted_linearSearch;
23 
24 namespace ace_time {
25 
27 typedef int (*strcmp_t)(const char*, const char*);
28 
41 template<typename ZI, typename ZRB, typename ZIB, strcmp_t STRCMP_P,
42  strcmp_t STRCMP_PP>
44  public:
46  ZoneRegistrar(uint16_t registrySize, const ZI* const* zoneRegistry):
47  mRegistrySize(registrySize),
48  mZoneRegistry(zoneRegistry),
49  mIsSorted(isSorted(zoneRegistry, registrySize)) {}
50 
52  uint16_t registrySize() const { return mRegistrySize; }
53 
58  bool isSorted() const { return mIsSorted; }
59 
60  /* Return the ZoneInfo at index i. Return nullptr if i is out of range. */
61  const ZI* getZoneInfoForIndex(uint16_t i) const {
62  return (i < mRegistrySize) ? ZRB(mZoneRegistry).zoneInfo(i) : nullptr;
63  }
64 
69  const ZI* getZoneInfoForName(const char* name) const {
70  if (mIsSorted && mRegistrySize >= kBinarySearchThreshold) {
71  return binarySearch(mZoneRegistry, mRegistrySize, name);
72  } else {
73  return linearSearch(mZoneRegistry, mRegistrySize, name);
74  }
75  }
76 
77  /* Return the ZoneInfo using the zoneId. Return nullptr if not found. */
78  const ZI* getZoneInfoForId(uint32_t zoneId) const {
79  return linearSearchUsingId(mZoneRegistry, mRegistrySize, zoneId);
80  }
81 
82  protected:
83  friend class ::BasicZoneRegistrarTest_Sorted_isSorted;
84  friend class ::BasicZoneRegistrarTest_Sorted_linearSearch;
85  friend class ::BasicZoneRegistrarTest_Sorted_linearSearch_not_found;
86  friend class ::BasicZoneRegistrarTest_Sorted_binarySearch;
87  friend class ::BasicZoneRegistrarTest_Sorted_binarySearch_not_found;
88  friend class ::BasicZoneRegistrarTest_Unsorted_isSorted;
89  friend class ::BasicZoneRegistrarTest_Unsorted_linearSearch;
90 
92  static const uint8_t kBinarySearchThreshold = 6;
93 
94  static bool isSorted(const ZI* const* zr, uint16_t registrySize) {
95  if (registrySize == 0) {
96  return false;
97  }
98 
99  const ZRB zoneRegistry(zr);
100  const char* prevName = ZIB(zoneRegistry.zoneInfo(0)).name();
101  for (uint16_t i = 1; i < registrySize; ++i) {
102  const char* currName = ZIB(zoneRegistry.zoneInfo(i)).name();
103  if (STRCMP_PP(prevName, currName) > 0) {
104  return false;
105  }
106  prevName = currName;
107  }
108  return true;
109  }
110 
111  static const ZI* linearSearch(const ZI* const* zr,
112  uint16_t registrySize, const char* name) {
113  const ZRB zoneRegistry(zr);
114  for (uint16_t i = 0; i < registrySize; ++i) {
115  const ZI* zoneInfo = zoneRegistry.zoneInfo(i);
116  if (STRCMP_P(name, ZIB(zoneInfo).name()) == 0) {
117  return zoneInfo;
118  }
119  }
120  return nullptr;
121  }
122 
123  static const ZI* binarySearch(const ZI* const* zr,
124  uint16_t registrySize, const char* name) {
125  uint16_t a = 0;
126  uint16_t b = registrySize - 1;
127  const ZRB zoneRegistry(zr);
128  while (true) {
129  uint16_t c = (a + b) / 2;
130  const ZI* zoneInfo = zoneRegistry.zoneInfo(c);
131  int8_t compare = STRCMP_P(name, ZIB(zoneInfo).name());
132  if (compare == 0) return zoneInfo;
133  if (a == b) return nullptr;
134  if (compare < 0) {
135  b = c - 1;
136  } else {
137  a = c + 1;
138  }
139  }
140  }
141 
142  static const ZI* linearSearchUsingId(const ZI* const* zr,
143  uint16_t registrySize, uint32_t zoneId) {
144  const ZRB zoneRegistry(zr);
145  for (uint16_t i = 0; i < registrySize; ++i) {
146  const ZI* zoneInfo = zoneRegistry.zoneInfo(i);
147  if (zoneId == ZIB(zoneInfo).zoneId()) {
148  return zoneInfo;
149  }
150  }
151  return nullptr;
152  }
153 
154  uint16_t const mRegistrySize;
155  const ZI* const* const mZoneRegistry;
156  bool const mIsSorted;
157 };
158 
163 #if ACE_TIME_USE_PROGMEM
164 typedef ZoneRegistrar<basic::ZoneInfo, basic::ZoneRegistryBroker,
165  basic::ZoneInfoBroker, acetime_strcmp_P, ace_common::strcmp_PP>
166  BasicZoneRegistrar;
167 #else
168 typedef ZoneRegistrar<basic::ZoneInfo, basic::ZoneRegistryBroker,
169  basic::ZoneInfoBroker, strcmp, strcmp> BasicZoneRegistrar;
170 #endif
171 
176 #if ACE_TIME_USE_PROGMEM
177 typedef ZoneRegistrar<extended::ZoneInfo, extended::ZoneRegistryBroker,
178  extended::ZoneInfoBroker, acetime_strcmp_P, ace_common::strcmp_PP>
179  ExtendedZoneRegistrar;
180 #else
181 typedef ZoneRegistrar<extended::ZoneInfo, extended::ZoneRegistryBroker,
182  extended::ZoneInfoBroker, strcmp, strcmp> ExtendedZoneRegistrar;
183 #endif
184 
185 }
186 
187 #endif
ace_time::ZoneRegistrar::kBinarySearchThreshold
static const uint8_t kBinarySearchThreshold
Use binarySearch() if registrySize >= threshold.
Definition: ZoneRegistrar.h:92
Brokers.h
ace_time::ZoneRegistrar
Class that allows looking up the ZoneInfo (ZI) from its TZDB identifier (e.g.
Definition: ZoneRegistrar.h:43
compat.h
ace_time::ZoneRegistrar::isSorted
bool isSorted() const
Return true if zoneRegistry is sorted, and eligible to use a binary search.
Definition: ZoneRegistrar.h:58
ace_time::ZoneRegistrar::ZoneRegistrar
ZoneRegistrar(uint16_t registrySize, const ZI *const *zoneRegistry)
Constructor.
Definition: ZoneRegistrar.h:46
ace_time::ZoneRegistrar::getZoneInfoForName
const ZI * getZoneInfoForName(const char *name) const
Return the ZoneInfo corresponding to the given zone name.
Definition: ZoneRegistrar.h:69
ace_time::ZoneRegistrar::registrySize
uint16_t registrySize() const
Return the number of zones.
Definition: ZoneRegistrar.h:52