Exemplo n.º 1
0
    def _generate_validation_data_cpp_test_items(
        self,
        zone_name: str,
        test_items: List[TestItem],
    ) -> str:
        """Generate the C++ code snippet related to the List[TestItem].
        """
        s = ''
        for test_item in test_items:
            epoch_seconds = test_item['epoch']
            total_offset_minutes = div_to_zero(test_item['total_offset'], 60)
            delta_offset_minutes = div_to_zero(test_item['dst_offset'], 60)
            year = test_item['y']
            month = test_item['M']
            day = test_item['d']
            hour = test_item['h']
            minute = test_item['m']
            second = test_item['s']
            abbrev_value = test_item['abbrev']
            abbrev = f'"{abbrev_value}"' if abbrev_value else 'nullptr'
            tag = test_item['type']

            test_item_code = f"""\
  {{ {epoch_seconds:10}, {total_offset_minutes:4}, {delta_offset_minutes:4}, \
{year:4}, {month:2}, {day:2}, {hour:2}, {minute:2}, {second:2}, {abbrev} }}, \
// type={tag}
"""
            s += test_item_code
        return s
Exemplo n.º 2
0
 def test_div_to_zero(self) -> None:
     self.assertEqual(1, div_to_zero(3, 3))
     self.assertEqual(0, div_to_zero(2, 3))
     self.assertEqual(0, div_to_zero(1, 3))
     self.assertEqual(0, div_to_zero(0, 3))
     self.assertEqual(0, div_to_zero(-1, 3))
     self.assertEqual(0, div_to_zero(-2, 3))
     self.assertEqual(-1, div_to_zero(-3, 3))
     self.assertEqual(-1, div_to_zero(-4, 3))
     self.assertEqual(-1, div_to_zero(-5, 3))
     self.assertEqual(-2, div_to_zero(-6, 3))
Exemplo n.º 3
0
    def _generate_era_item(
        self, zone_name: str, era: ZoneEraRaw
    ) -> Tuple[str, int]:
        policy_name = era['rules']
        if policy_name == '-' or policy_name == ':':
            zone_policy = 'nullptr'
            delta_seconds = era['rulesDeltaSecondsTruncated']
        else:
            zone_policy = '&kPolicy%s' % normalize_name(policy_name)
            delta_seconds = 0

        if self.scope == 'extended':
            offset_code, delta_code = _to_extended_offset_and_delta(
                era['offsetSecondsTruncated'], delta_seconds)
        else:
            offset_code = div_to_zero(era['offsetSecondsTruncated'], 900)
            delta_code = str(div_to_zero(delta_seconds, 900))

        until_year = era['untilYear']
        if until_year == MAX_UNTIL_YEAR:
            until_year_tiny = MAX_UNTIL_YEAR_TINY
        else:
            until_year_tiny = until_year - EPOCH_YEAR

        until_month = era['untilMonth']
        if not until_month:
            until_month = 1

        until_day = era['untilDay']
        if not until_day:
            until_day = 1

        until_time_code, until_time_modifier = _to_code_and_modifier(
            era['untilSecondsTruncated'], era['untilTimeSuffix'], self.scope)

        # Replace %s with just a % for C++
        format = era['format'].replace('%s', '%')
        string_length = len(format) + 1

        era_item = self.ZONE_INFOS_CPP_ERA_ITEM.format(
            rawLine=normalize_raw(era['rawLine']),
            offsetCode=offset_code,
            deltaCode=delta_code,
            zonePolicy=zone_policy,
            format=format,
            untilYearTiny=until_year_tiny,
            untilMonth=until_month,
            untilDay=until_day,
            untilTimeCode=until_time_code,
            untilTimeModifier=until_time_modifier)

        return (era_item, string_length)
Exemplo n.º 4
0
 def _generate_validation_data_cpp_test_items(
         self, zone_name: str, test_items: List[TestItem]) -> str:
     """Generate the {testItems} value.
     """
     s = ''
     for test_item in test_items:
         total_offset_minutes = div_to_zero(test_item.total_offset, 60)
         delta_offset_minutes = div_to_zero(test_item.dst_offset, 60)
         s += self.TEST_ITEM.format(epochSeconds=test_item.epoch,
                                    totalOffsetMinutes=total_offset_minutes,
                                    deltaOffsetMinutes=delta_offset_minutes,
                                    year=test_item.y,
                                    month=test_item.M,
                                    day=test_item.d,
                                    hour=test_item.h,
                                    minute=test_item.m,
                                    second=test_item.s,
                                    type=test_item.type)
     return s
Exemplo n.º 5
0
def _to_code_and_modifier(
    seconds: int, suffix: str, scope: str,
) -> Tuple[int, str]:
    """Return the packed (code, modifier) uint8_t integers that hold
    the AT or UNTIL timeCode, timeMinute and the suffix.
    """
    timeCode = div_to_zero(seconds, 15 * 60)
    timeMinute = seconds % 900 // 60
    modifier = _to_modifier(suffix, scope)
    if timeMinute > 0:
        modifier += f' + {timeMinute}'
    return timeCode, modifier
Exemplo n.º 6
0
    def _generate_policy_item(
        self,
        name: str,
        rules: List[ZoneRuleRaw],
        indexed_letters: Optional[IndexedLetters],
    ) -> Tuple[str, int, int]:

        # Generate kZoneRules*[]
        rule_items = ''
        for rule in rules:
            at_time_code, at_time_modifier = _to_code_and_modifier(
                rule['atSecondsTruncated'], rule['atTimeSuffix'], self.scope)

            if self.scope == 'extended':
                delta_code = _to_extended_delta_code(
                    rule['deltaSecondsTruncated'])
            else:
                delta_code = str(div_to_zero(
                    rule['deltaSecondsTruncated'], 900
                ))

            from_year = rule['fromYear']
            from_year_tiny = to_tiny_year(from_year)
            to_year = rule['toYear']
            to_year_tiny = to_tiny_year(to_year)

            # Single-character 'letter' values are represented as themselves
            # using the C++ 'char' type ('A'-'Z'). But some 'letter' fields hold
            # a multi-character string. We can encode these multi-character
            # strings as an index into an array of NUL-terminated strings.
            # ASCII codes less than 32 (space) are non-printable control
            # characters so they will not collide with the printable characters
            # 'A' - 'Z'. Therefore we can hold to up to 31 multi-character
            # strings per-zone. In practice, for a single zone, the maximum
            # number of multi-character strings that I've seen is 2.
            if len(rule['letter']) == 1:
                letter = "'%s'" % rule['letter']
                letterComment = ''
            elif len(rule['letter']) > 1:
                letters = cast(IndexedLetters, indexed_letters)
                index = letters[rule['letter']]
                if index >= 32:
                    raise Exception('Number of indexed letters >= 32')
                letter = str(index)
                letterComment = ('; "%s"' % rule['letter'])
            else:
                raise Exception(
                    'len(%s) == 0; should not happen'
                    % rule['letter'])

            rule_items += self.ZONE_POLICIES_CPP_RULE_ITEM.format(
                rawLine=normalize_raw(rule['rawLine']),
                fromYearTiny=from_year_tiny,
                toYearTiny=to_year_tiny,
                inMonth=rule['inMonth'],
                onDayOfWeek=rule['onDayOfWeek'],
                onDayOfMonth=rule['onDayOfMonth'],
                atTimeCode=at_time_code,
                atTimeModifier=at_time_modifier,
                deltaCode=delta_code,
                letter=letter,
                letterComment=letterComment)

        # Generate kLetters*[]
        policyName = normalize_name(name)
        numLetters = len(indexed_letters) if indexed_letters else 0
        memoryLetters8 = 0
        memoryLetters32 = 0
        if numLetters:
            letters = cast(IndexedLetters, indexed_letters)
            letterArrayRef = 'kLetters%s' % policyName
            letterItems = ''
            for name, index in letters.items():
                letterItems += ('  /*%d*/ "%s",\n' % (index, name))
                memoryLetters8 += len(name) + 1 + 2  # NUL terminated
                memoryLetters32 += len(name) + 1 + 4  # NUL terminated
            letterArray = self.ZONE_POLICIES_LETTER_ARRAY.format(
                policyName=policyName,
                letterItems=letterItems,
                progmem='ACE_TIME_PROGMEM')
        else:
            letterArrayRef = 'nullptr'
            letterArray = ''

        # Calculate the memory consumed by structs and arrays
        num_rules = len(rules)
        memory8 = (
            1 * self.SIZEOF_ZONE_POLICY_8
            + num_rules * self.SIZEOF_ZONE_RULE_8
            + memoryLetters8)
        memory32 = (
            1 * self.SIZEOF_ZONE_POLICY_32
            + num_rules * self.SIZEOF_ZONE_RULE_32
            + memoryLetters32)

        policy_item = self.ZONE_POLICIES_CPP_POLICY_ITEM.format(
            scope=self.scope,
            policyName=policyName,
            numRules=num_rules,
            memory8=memory8,
            memory32=memory32,
            ruleItems=rule_items,
            numLetters=numLetters,
            letterArrayRef=letterArrayRef,
            letterArray=letterArray,
            progmem='ACE_TIME_PROGMEM')

        return (policy_item, memory8, memory32)