AceTime  0.7
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 "common/compat.h"
12 #include "internal/ZoneInfo.h"
13 #include "internal/Brokers.h"
14 
15 class BasicZoneRegistrarTest_Sorted_isSorted;
16 class BasicZoneRegistrarTest_Sorted_linearSearch;
17 class BasicZoneRegistrarTest_Sorted_linearSearch_not_found;
18 class BasicZoneRegistrarTest_Sorted_binarySearch;
19 class BasicZoneRegistrarTest_Sorted_binarySearch_not_found;
20 class BasicZoneRegistrarTest_Unsorted_isSorted;
21 class BasicZoneRegistrarTest_Unsorted_linearSearch;
22 
23 namespace ace_time {
24 
26 typedef int (*strcmp_t)(const char*, const char*);
27 
40 template<typename ZI, typename ZRB, typename ZIB, strcmp_t STRCMP_P,
41  strcmp_t STRCMP_PP>
43  public:
45  ZoneRegistrar(uint16_t registrySize, const ZI* const* zoneRegistry):
46  mRegistrySize(registrySize),
47  mZoneRegistry(zoneRegistry),
48  mIsSorted(isSorted(zoneRegistry, registrySize)) {}
49 
51  uint16_t registrySize() const { return mRegistrySize; }
52 
57  bool isSorted() const { return mIsSorted; }
58 
59  /* Return the ZoneInfo at index i. Return nullptr if i is out of range. */
60  const ZI* getZoneInfoForIndex(uint16_t i) const {
61  return (i < mRegistrySize) ? ZRB(mZoneRegistry).zoneInfo(i) : nullptr;
62  }
63 
68  const ZI* getZoneInfoForName(const char* name) const {
69  if (mIsSorted && mRegistrySize >= kBinarySearchThreshold) {
70  return binarySearch(mZoneRegistry, mRegistrySize, name);
71  } else {
72  return linearSearch(mZoneRegistry, mRegistrySize, name);
73  }
74  }
75 
76  /* Return the ZoneInfo using the zoneId. Return nullptr if not found. */
77  const ZI* getZoneInfoForId(uint32_t zoneId) const {
78  return linearSearchUsingId(mZoneRegistry, mRegistrySize, zoneId);
79  }
80 
81  protected:
82  friend class ::BasicZoneRegistrarTest_Sorted_isSorted;
83  friend class ::BasicZoneRegistrarTest_Sorted_linearSearch;
84  friend class ::BasicZoneRegistrarTest_Sorted_linearSearch_not_found;
85  friend class ::BasicZoneRegistrarTest_Sorted_binarySearch;
86  friend class ::BasicZoneRegistrarTest_Sorted_binarySearch_not_found;
87  friend class ::BasicZoneRegistrarTest_Unsorted_isSorted;
88  friend class ::BasicZoneRegistrarTest_Unsorted_linearSearch;
89 
91  static const uint8_t kBinarySearchThreshold = 6;
92 
93  static bool isSorted(const ZI* const* zr, uint16_t registrySize) {
94  if (registrySize == 0) {
95  return false;
96  }
97 
98  const ZRB zoneRegistry(zr);
99  const char* prevName = ZIB(zoneRegistry.zoneInfo(0)).name();
100  for (uint16_t i = 1; i < registrySize; ++i) {
101  const char* currName = ZIB(zoneRegistry.zoneInfo(i)).name();
102  if (STRCMP_PP(prevName, currName) > 0) {
103  return false;
104  }
105  prevName = currName;
106  }
107  return true;
108  }
109 
110  static const ZI* linearSearch(const ZI* const* zr,
111  uint16_t registrySize, const char* name) {
112  const ZRB zoneRegistry(zr);
113  for (uint16_t i = 0; i < registrySize; ++i) {
114  const ZI* zoneInfo = zoneRegistry.zoneInfo(i);
115  if (STRCMP_P(name, ZIB(zoneInfo).name()) == 0) {
116  return zoneInfo;
117  }
118  }
119  return nullptr;
120  }
121 
122  static const ZI* binarySearch(const ZI* const* zr,
123  uint16_t registrySize, const char* name) {
124  uint16_t a = 0;
125  uint16_t b = registrySize - 1;
126  const ZRB zoneRegistry(zr);
127  while (true) {
128  uint16_t c = (a + b) / 2;
129  const ZI* zoneInfo = zoneRegistry.zoneInfo(c);
130  int8_t compare = STRCMP_P(name, ZIB(zoneInfo).name());
131  if (compare == 0) return zoneInfo;
132  if (a == b) return nullptr;
133  if (compare < 0) {
134  b = c - 1;
135  } else {
136  a = c + 1;
137  }
138  }
139  }
140 
141  static const ZI* linearSearchUsingId(const ZI* const* zr,
142  uint16_t registrySize, uint32_t zoneId) {
143  const ZRB zoneRegistry(zr);
144  for (uint16_t i = 0; i < registrySize; ++i) {
145  const ZI* zoneInfo = zoneRegistry.zoneInfo(i);
146  if (zoneId == ZIB(zoneInfo).zoneId()) {
147  return zoneInfo;
148  }
149  }
150  return nullptr;
151  }
152 
153  uint16_t const mRegistrySize;
154  const ZI* const* const mZoneRegistry;
155  bool const mIsSorted;
156 };
157 
162 #if ACE_TIME_USE_PROGMEM
164  basic::ZoneInfoBroker, acetime_strcmp_P, acetime_strcmp_PP>
166 #else
167 typedef ZoneRegistrar<basic::ZoneInfo, basic::ZoneRegistryBroker,
168  basic::ZoneInfoBroker, strcmp, strcmp> BasicZoneRegistrar;
169 #endif
170 
175 #if ACE_TIME_USE_PROGMEM
177  extended::ZoneInfoBroker, acetime_strcmp_P, acetime_strcmp_PP>
179 #else
180 typedef ZoneRegistrar<extended::ZoneInfo, extended::ZoneRegistryBroker,
181  extended::ZoneInfoBroker, strcmp, strcmp> ExtendedZoneRegistrar;
182 #endif
183 
184 }
185 
186 #endif
Class that allows looking up the ZoneInfo (ZI) from its TZDB identifier (e.g.
Definition: ZoneRegistrar.h:42
const ZI * getZoneInfoForName(const char *name) const
Return the ZoneInfo corresponding to the given zone name.
Definition: ZoneRegistrar.h:68
Representation of a given time zone, implemented as an array of ZoneEra records.
Definition: ZoneInfo.h:86
Representation of a given time zone, implemented as an array of ZoneEra records.
Definition: ZoneInfo.h:86
bool isSorted() const
Return true if zoneRegistry is sorted, and eligible to use a binary search.
Definition: ZoneRegistrar.h:57
int acetime_strcmp_PP(const char *a, const char *b)
Compare 2 strings in flash memory.
Definition: compat.cpp:36
The classes provide a thin layer of indirection for accessing the zoneinfo files stored in the zonedb...
Macros and definitions that provide a consistency layer among the various Arduino boards for compatib...
ZoneRegistrar(uint16_t registrySize, const ZI *const *zoneRegistry)
Constructor.
Definition: ZoneRegistrar.h:45
Data broker for accessing the ZoneRegistry in PROGMEM.
Definition: Brokers.h:477
static const uint8_t kBinarySearchThreshold
Use binarySearch() if registrySize >= threshold.
Definition: ZoneRegistrar.h:91
uint16_t registrySize() const
Return the number of zones.
Definition: ZoneRegistrar.h:51