6 #ifndef ACE_TIME_EXTENDED_TRANSITION_H
7 #define ACE_TIME_EXTENDED_TRANSITION_H
10 #include "common/logging.h"
11 #include "local_date_mutation.h"
13 class TransitionStorageTest_getFreeAgent;
14 class TransitionStorageTest_getFreeAgent2;
15 class TransitionStorageTest_addFreeAgentToActivePool;
16 class TransitionStorageTest_reservePrior;
17 class TransitionStorageTest_addPriorToCandidatePool;
18 class TransitionStorageTest_addFreeAgentToCandidatePool;
19 class TransitionStorageTest_setFreeAgentAsPriorIfValid;
20 class TransitionStorageTest_addActiveCandidatesToActivePool;
21 class TransitionStorageTest_findTransitionForDateTime;
22 class TransitionStorageTest_resetCandidatePool;
26 #ifndef ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG
27 #define ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG 0
39 enum class MatchStatus : uint8_t {
47 inline bool isMatchStatusActive(MatchStatus status) {
48 return status == MatchStatus::kExactMatch
49 || status == MatchStatus::kWithinMatch
50 || status == MatchStatus::kPrior;
62 DateTuple(int16_t y, uint8_t mon, uint8_t d, int16_t min, uint8_t mod):
63 year(y), month(mon), day(d), suffix(mod), minutes(min) {}
73 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
74 int hour = minutes / 60;
75 int minute = minutes - hour * 60;
76 char c =
"wsu"[(suffix>>4)];
77 logging::printf(
"%04d-%02u-%02uT%02d:%02d%c",
78 year, month, day, hour, minute, c);
84 inline bool operator<(
const DateTuple& a,
const DateTuple& b) {
85 if (a.year < b.year)
return true;
86 if (a.year > b.year)
return false;
87 if (a.month < b.month)
return true;
88 if (a.month > b.month)
return false;
89 if (a.day < b.day)
return true;
90 if (a.day > b.day)
return false;
91 if (a.minutes < b.minutes)
return true;
92 if (a.minutes > b.minutes)
return false;
96 inline bool operator>=(
const DateTuple& a,
const DateTuple& b) {
100 inline bool operator<=(
const DateTuple& a,
const DateTuple& b) {
104 inline bool operator>(
const DateTuple& a,
const DateTuple& b) {
109 inline bool operator==(
const DateTuple& a,
const DateTuple& b) {
110 return a.year == b.year
111 && a.month == b.month
113 && a.minutes == b.minutes
114 && a.suffix == b.suffix;
118 inline void normalizeDateTuple(DateTuple* dt) {
119 const int16_t kOneDayAsMinutes = 60 * 24;
120 if (dt->minutes <= -kOneDayAsMinutes) {
122 local_date_mutation::decrementOneDay(ld);
123 dt->year = ld.year();
124 dt->month = ld.month();
126 dt->minutes += kOneDayAsMinutes;
127 }
else if (kOneDayAsMinutes <= dt->minutes) {
129 local_date_mutation::incrementOneDay(ld);
130 dt->year = ld.year();
131 dt->month = ld.month();
133 dt->minutes -= kOneDayAsMinutes;
145 inline acetime_t subtractDateTuple(
const DateTuple& a,
const DateTuple& b) {
155 return (epochDaysA - epochDaysB) * 86400 + (a.minutes - b.minutes) * 60;
170 inline MatchStatus compareDateTupleFuzzy(
172 const DateTuple& start,
173 const DateTuple& until) {
176 int32_t tMonths = t.year * (int32_t) 12 + t.month;
177 int32_t startMonths = start.year * (int32_t) 12 + start.month;
178 if (tMonths < startMonths - 1)
return MatchStatus::kPrior;
179 int32_t untilMonths = until.year * 12 + until.month;
180 if (untilMonths + 1 < tMonths)
return MatchStatus::kFarFuture;
181 return MatchStatus::kWithinMatch;
192 template<
typename ZEB>
216 logging::printf(
"MatchingEra(");
219 logging::printf(
"; era=%c", (
era.isNull()) ?
'-' :
'*');
220 logging::printf(
"; prevMatch=%c", (
prevMatch) ?
'*' :
'-');
221 logging::printf(
")");
259 template <
typename ZEB,
typename ZPB,
typename ZRB>
310 #if ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG
357 const char* format()
const {
358 return match->era.format();
383 const ZPB policy =
match->era.zonePolicy();
384 uint8_t numLetters = policy.numLetters();
385 if (
letter >= numLetters) {
393 return policy.letter(
letter);
398 logging::printf(
"Transition(");
405 logging::printf(
"; UTC");
412 logging::printf(
"; rule=-");
414 logging::printf(
"; rule=");
415 logging::printf(
"[%d,%d]",
rule.fromYear(),
rule.toYear());
428 uint8_t hour = minutes / 60;
429 uint8_t minute = minutes - hour * 60;
430 logging::printf(
"%c%02u:%02u", sign, (
unsigned) hour, (
unsigned) minute);
433 #ifdef ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG
440 logging::printf(prefix);
442 logging::printf(
"\n");
455 template <
typename ZEB,
typename ZPB,
typename ZRB>
485 template <
typename ZEB,
typename ZPB,
typename ZRB>
529 template<u
int8_t SIZE,
typename ZEB,
typename ZPB,
typename ZRB>
562 for (uint8_t i = 0; i < SIZE; i++) {
563 mTransitions[i] = &mPool[i];
566 mIndexCandidates = 0;
572 return mTransitions[mIndexPrior];
584 mIndexCandidates = mIndexPrior;
585 mIndexFree = mIndexPrior;
589 return &mTransitions[mIndexCandidates];
592 return &mTransitions[mIndexFree];
596 return &mTransitions[0];
599 return &mTransitions[mIndexFree];
608 if (mIndexFree < SIZE) {
610 if (mIndexFree >= mAllocSize) {
611 mAllocSize = mIndexFree + 1;
613 return mTransitions[mIndexFree];
619 return mTransitions[SIZE - 1];
631 if (mIndexFree >= SIZE)
return;
633 mIndexPrior = mIndexFree;
634 mIndexCandidates = mIndexFree;
650 return &mTransitions[mIndexPrior];
656 Transition* prior = mTransitions[mIndexPrior];
661 internal::swap(mTransitions[mIndexPrior], mTransitions[mIndexFree]);
681 if (mIndexFree >= SIZE)
return;
690 for (uint8_t i = mIndexFree; i > mIndexCandidates; i--) {
694 mTransitions[i] = prev;
695 mTransitions[i - 1] = curr;
707 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
708 logging::printf(
"addActiveCandidatesToActivePool()\n");
712 uint8_t iActive = mIndexPrior;
713 uint8_t iCandidate = mIndexCandidates;
714 for (; iCandidate < mIndexFree; iCandidate++) {
715 if (isMatchStatusActive(mTransitions[iCandidate]->matchStatus)) {
716 if (iActive != iCandidate) {
719 internal::swap(mTransitions[iActive], mTransitions[iCandidate]);
725 mIndexPrior = iActive;
726 mIndexCandidates = iActive;
727 mIndexFree = iActive;
729 return mTransitions[iActive - 1];
742 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
744 "findTransitionForSeconds(): mIndexFree: %d\n", mIndexFree);
750 for (uint8_t i = 0; i < mIndexFree; i++) {
751 next = mTransitions[i];
775 if (curr ==
nullptr) {
783 if (prev ==
nullptr) {
789 acetime_t shiftSeconds = subtractDateTuple(
791 if (shiftSeconds >= 0) {
806 if (next ==
nullptr) {
812 acetime_t shiftSeconds = subtractDateTuple(
814 if (shiftSeconds >= 0) {
854 for (uint8_t i = 0; i < mIndexFree; i++) {
855 curr = mTransitions[i];
859 bool isExactMatch = (startDateTime <= localDate)
860 && (localDate < untilDateTime);
871 }
else if (startDateTime > localDate) {
895 logging::printf(
"TransitionStorage: ");
896 logging::printf(
"SIZE=%d, mAllocSize=%d\n", SIZE, mAllocSize);
897 int nActives = mIndexPrior;
898 int nPrior = mIndexCandidates - mIndexPrior;
899 int nCandidates = mIndexFree - mIndexCandidates;
900 int nAllocFree = mAllocSize - mIndexFree;
901 int nVirginFree = SIZE - mAllocSize;
903 logging::printf(
" Actives: %d\n", nActives);
905 " ", &mTransitions[0], &mTransitions[mIndexPrior]);
907 logging::printf(
" Prior: %d\n", nPrior);
909 " ", &mTransitions[mIndexPrior], &mTransitions[mIndexCandidates]);
911 logging::printf(
" Candidates: %d\n", nCandidates);
913 " ", &mTransitions[mIndexCandidates], &mTransitions[mIndexFree]);
915 logging::printf(
" Allocated Free: %d\n", nAllocFree);
916 logging::printf(
" Virgin Free: %d\n", nVirginFree);
930 friend class ::TransitionStorageTest_getFreeAgent;
931 friend class ::TransitionStorageTest_getFreeAgent2;
932 friend class ::TransitionStorageTest_addFreeAgentToActivePool;
933 friend class ::TransitionStorageTest_reservePrior;
934 friend class ::TransitionStorageTest_addPriorToCandidatePool;
935 friend class ::TransitionStorageTest_addFreeAgentToCandidatePool;
936 friend class ::TransitionStorageTest_setFreeAgentAsPriorIfValid;
937 friend class ::TransitionStorageTest_addActiveCandidatesToActivePool;
938 friend class ::TransitionStorageTest_findTransitionForDateTime;
939 friend class ::TransitionStorageTest_resetCandidatePool;
943 return mTransitions[i];
949 uint8_t mIndexCandidates;
953 uint8_t mAllocSize = 0;
Class that holds the date-time as the components (year, month, day, hour, minute, second) without reg...
uint8_t day() const
Return the day of the month.
uint8_t month() const
Return the month with January=1, December=12.
uint8_t minute() const
Return the minute.
uint8_t hour() const
Return the hour.
int16_t year() const
Return the year.
static LocalDate forComponents(int16_t year, uint8_t month, uint8_t day)
Factory method using separated year, month and day fields.
int32_t toEpochDays() const
Return number of days since the current epoch year sCurrentEpochYear.
A heap manager which is specialized and tuned to manage a collection of Transitions,...
void resetAllocSize()
Reset the current allocation size.
void addFreeAgentToActivePool()
Immediately add the free agent Transition at index mIndexFree to the Active pool.
TransitionForSecondsTemplate< ZEB, ZPB, ZRB > TransitionForSeconds
Template instantiation of TransitionForSecondsTemplate used by this class.
TransitionForDateTimeTemplate< ZEB, ZPB, ZRB > TransitionForDateTime
Template instantiation of TransitionForDateTimeTemplate used by this class.
void init()
Initialize all pools to 0 size, usually when a new year is initialized.
void setFreeAgentAsPriorIfValid()
Set the free agent transition as the most recent prior.
Transition * getFreeAgent()
Return a pointer to the first Transition in the free pool.
TransitionTemplate< ZEB, ZPB, ZRB > Transition
Template instantiation of TransitionTemplate used by this class.
void resetCandidatePool()
Empty the Candidate pool by resetting the various indexes.
static void calcFoldAndOverlap(uint8_t *fold, uint8_t *num, const Transition *prev, const Transition *curr, const Transition *next, acetime_t epochSeconds)
Calculate the fold and num parameters of TransitionForSecond.
uint8_t getAllocSize() const
Return the maximum number of transitions which was allocated.
void addFreeAgentToCandidatePool()
Add the free agent Transition at index mIndexFree to the Candidate pool, sorted by transitionTime.
Transition * getPrior()
Return the current prior transition.
TransitionForDateTime findTransitionForDateTime(const LocalDateTime &ldt) const
Return the candidate Transitions matching the given dateTime.
TransitionStorageTemplate()
Constructor.
Transition * addActiveCandidatesToActivePool()
Add active candidates into the Active pool, and collapse the Candidate pool.
void addPriorToCandidatePool()
Add the current prior into the Candidates pool.
TransitionForSeconds findTransitionForSeconds(acetime_t epochSeconds) const
Return the Transition matching the given epochSeconds.
Transition ** reservePrior()
Allocate a free Transition then add it to the Prior pool.
void log() const
Verify that the indexes are valid.
int32_t acetime_t
Type for the number of seconds from epoch.
A tuple that represents a date and time.
void log() const
Used only for debugging.
Data structure that captures the matching ZoneEra and its ZoneRule transitions for a given year.
MatchingEraTemplate * prevMatch
The previous MatchingEra, needed to interpret startDateTime.
int16_t lastDeltaMinutes
The DST offset of the last Transition in this MatchingEra.
ZEB era
The ZoneEra that matched the given year.
DateTuple untilDateTime
The effective until time of the matching ZoneEra.
DateTuple startDateTime
The effective start time of the matching ZoneEra, which uses the UTC offsets of the previous matching...
int16_t lastOffsetMinutes
The STD offset of the last Transition in this MatchingEra.
The result of the findTransitionForDateTime(const LocalDatetime& ldt) method which can return 0,...
uint8_t num
Number of matches: 0, 1, 2.
const TransitionTemplate< ZEB, ZPB, ZRB > * prev
The previous transition.
const TransitionTemplate< ZEB, ZPB, ZRB > * curr
The matching transition, or null if not found or in gap.
Tuple of a matching Transition and its 'fold'.
uint8_t fold
1 if corresponding datetime occurred the second time
const TransitionTemplate< ZEB, ZPB, ZRB > * curr
The matching transition, or null if not found.
uint8_t num
Number of occurrences of the resulting LocalDateTime: 0, 1, or 2.
Represents an interval of time where the time zone obeyed a certain UTC offset and DST delta.
static void printTransitions(const char *prefix, const TransitionTemplate *const *begin, const TransitionTemplate *const *end)
Print an iterable of Transitions from 'begin' to 'end'.
ZRB rule
The Zone transition rule that matched for the the given year.
bool isValidPrior
During findCandidateTransitions(), this flag indicates whether the current transition is a valid "pri...
DateTuple transitionTime
The original transition time, usually 'w' but sometimes 's' or 'u'.
acetime_t startEpochSeconds
The calculated transition time of the given rule.
DateTuple transitionTimeS
Version of transitionTime in 's' mode, using the UTC offset of the previous Transition.
DateTuple untilDateTime
Until time expressed using the UTC offset of the current Transition.
const char * letter() const
Return the letter string.
int16_t offsetMinutes
The base offset minutes, not the total effective UTC offset.
void log() const
Used only for debugging.
char letterBuf[2]
Storage for the single letter 'letter' field if 'rule' is not null.
DateTuple transitionTimeU
Version of transitionTime in 'u' mode, using the UTC offset of the previous transition.
static void logHourMinute(int16_t minutes)
Print minutes as [+/-]hh:mm.
MatchStatus matchStatus
During processTransitionMatchStatus(), this flag indicates how the transition falls within the time i...
DateTuple startDateTime
Start time expressed using the UTC offset of the current Transition.
char abbrev[internal::kAbbrevSize]
The calculated effective time zone abbreviation, e.g.
int16_t deltaMinutes
The DST delta minutes.
const MatchingEraTemplate< ZEB > * match
The match which generated this Transition.
static const uint8_t kSuffixW
Represents 'w' or wall time.