tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Era.h (8262B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef builtin_temporal_Era_h
      8 #define builtin_temporal_Era_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/MathAlgorithms.h"
     12 
     13 #include <initializer_list>
     14 #include <stdint.h>
     15 #include <string_view>
     16 
     17 #include "jstypes.h"
     18 
     19 #include "builtin/temporal/Calendar.h"
     20 
     21 namespace js::temporal {
     22 
     23 enum class EraCode {
     24  // The standard era of a calendar.
     25  Standard,
     26 
     27  // The era before the standard era of a calendar.
     28  Inverse,
     29 
     30  // Named Japanese eras.
     31  Meiji,
     32  Taisho,
     33  Showa,
     34  Heisei,
     35  Reiwa,
     36 };
     37 
     38 // static variables in constexpr functions requires C++23 support, so we can't
     39 // declare the eras directly in CalendarEras.
     40 namespace eras {
     41 inline constexpr auto Standard = {EraCode::Standard};
     42 
     43 inline constexpr auto StandardInverse = {EraCode::Standard, EraCode::Inverse};
     44 
     45 inline constexpr auto Japanese = {
     46    EraCode::Standard, EraCode::Inverse,
     47 
     48    EraCode::Meiji,    EraCode::Taisho,  EraCode::Showa,
     49    EraCode::Heisei,   EraCode::Reiwa,
     50 };
     51 
     52 // https://tc39.es/proposal-intl-era-monthcode/#table-eras
     53 //
     54 // Calendars which don't use eras were omitted.
     55 namespace names {
     56 using namespace std::literals;
     57 
     58 // Empty placeholder.
     59 inline constexpr auto Empty = {
     60    ""sv,
     61 };
     62 
     63 inline constexpr auto Buddhist = {
     64    "be"sv,
     65 };
     66 
     67 inline constexpr auto Coptic = {
     68    "am"sv,
     69 };
     70 
     71 inline constexpr auto EthiopianAmeteAlem = {
     72    "aa"sv,
     73 };
     74 
     75 // "Intl era and monthCode" proposal follows CDLR which defines that Amete Alem
     76 // era is used for years before the incarnation. This may not match modern
     77 // usage, though. For the time being use a single era to check if we get any
     78 // user reports to clarify the situation.
     79 //
     80 // CLDR bug report: https://unicode-org.atlassian.net/browse/CLDR-18739
     81 inline constexpr auto Ethiopian = {
     82    "am"sv,
     83 };
     84 
     85 inline constexpr auto Gregorian = {
     86    "ce"sv,
     87    "ad"sv,
     88 };
     89 
     90 inline constexpr auto GregorianInverse = {
     91    "bce"sv,
     92    "bc"sv,
     93 };
     94 
     95 inline constexpr auto Hebrew = {
     96    "am"sv,
     97 };
     98 
     99 inline constexpr auto Indian = {
    100    "shaka"sv,
    101 };
    102 
    103 inline constexpr auto Islamic = {
    104    "ah"sv,
    105 };
    106 
    107 inline constexpr auto IslamicInverse = {
    108    "bh"sv,
    109 };
    110 
    111 inline constexpr auto JapaneseMeiji = {
    112    "meiji"sv,
    113 };
    114 
    115 inline constexpr auto JapaneseTaisho = {
    116    "taisho"sv,
    117 };
    118 
    119 inline constexpr auto JapaneseShowa = {
    120    "showa"sv,
    121 };
    122 
    123 inline constexpr auto JapaneseHeisei = {
    124    "heisei"sv,
    125 };
    126 
    127 inline constexpr auto JapaneseReiwa = {
    128    "reiwa"sv,
    129 };
    130 
    131 inline constexpr auto Persian = {
    132    "ap"sv,
    133 };
    134 
    135 inline constexpr auto ROC = {
    136    "roc"sv,
    137 };
    138 
    139 inline constexpr auto ROCInverse = {
    140    "broc"sv,
    141 };
    142 }  // namespace names
    143 }  // namespace eras
    144 
    145 constexpr auto& CalendarEras(CalendarId calendar) {
    146  switch (calendar) {
    147    case CalendarId::ISO8601:
    148    case CalendarId::Buddhist:
    149    case CalendarId::Chinese:
    150    case CalendarId::Coptic:
    151    case CalendarId::Dangi:
    152    case CalendarId::Ethiopian:
    153    case CalendarId::EthiopianAmeteAlem:
    154    case CalendarId::Hebrew:
    155    case CalendarId::Indian:
    156    case CalendarId::Persian:
    157      return eras::Standard;
    158 
    159    case CalendarId::Gregorian:
    160    case CalendarId::IslamicCivil:
    161    case CalendarId::IslamicTabular:
    162    case CalendarId::IslamicUmmAlQura:
    163    case CalendarId::ROC:
    164      return eras::StandardInverse;
    165 
    166    case CalendarId::Japanese:
    167      return eras::Japanese;
    168  }
    169  MOZ_CRASH("invalid calendar id");
    170 }
    171 
    172 /**
    173 * Return `true` iff the calendar has an inverse era.
    174 */
    175 constexpr bool CalendarEraHasInverse(CalendarId calendar) {
    176  // More than one era implies an inverse era is used.
    177  return CalendarEras(calendar).size() > 1;
    178 }
    179 
    180 /**
    181 * CalendarSupportsEra ( calendar )
    182 */
    183 constexpr bool CalendarSupportsEra(CalendarId calendar) {
    184  switch (calendar) {
    185    case CalendarId::ISO8601:
    186    case CalendarId::Chinese:
    187    case CalendarId::Dangi:
    188      return false;
    189 
    190    case CalendarId::Buddhist:
    191    case CalendarId::Coptic:
    192    case CalendarId::Ethiopian:
    193    case CalendarId::EthiopianAmeteAlem:
    194    case CalendarId::Hebrew:
    195    case CalendarId::Indian:
    196    case CalendarId::Persian:
    197    case CalendarId::Gregorian:
    198    case CalendarId::IslamicCivil:
    199    case CalendarId::IslamicTabular:
    200    case CalendarId::IslamicUmmAlQura:
    201    case CalendarId::ROC:
    202    case CalendarId::Japanese:
    203      return true;
    204  }
    205  MOZ_CRASH("invalid calendar id");
    206 }
    207 
    208 constexpr auto& CalendarEraNames(CalendarId calendar, EraCode era) {
    209  switch (calendar) {
    210    case CalendarId::ISO8601:
    211    case CalendarId::Chinese:
    212    case CalendarId::Dangi:
    213      MOZ_ASSERT(era == EraCode::Standard);
    214      return eras::names::Empty;
    215 
    216    case CalendarId::Buddhist:
    217      MOZ_ASSERT(era == EraCode::Standard);
    218      return eras::names::Buddhist;
    219 
    220    case CalendarId::Coptic:
    221      MOZ_ASSERT(era == EraCode::Standard);
    222      return eras::names::Coptic;
    223 
    224    case CalendarId::Ethiopian:
    225      MOZ_ASSERT(era == EraCode::Standard);
    226      return eras::names::Ethiopian;
    227 
    228    case CalendarId::EthiopianAmeteAlem:
    229      MOZ_ASSERT(era == EraCode::Standard);
    230      return eras::names::EthiopianAmeteAlem;
    231 
    232    case CalendarId::Hebrew:
    233      MOZ_ASSERT(era == EraCode::Standard);
    234      return eras::names::Hebrew;
    235 
    236    case CalendarId::Indian:
    237      MOZ_ASSERT(era == EraCode::Standard);
    238      return eras::names::Indian;
    239 
    240    case CalendarId::Persian:
    241      MOZ_ASSERT(era == EraCode::Standard);
    242      return eras::names::Persian;
    243 
    244    case CalendarId::Gregorian: {
    245      MOZ_ASSERT(era == EraCode::Standard || era == EraCode::Inverse);
    246      return era == EraCode::Standard ? eras::names::Gregorian
    247                                      : eras::names::GregorianInverse;
    248    }
    249 
    250    case CalendarId::IslamicCivil:
    251    case CalendarId::IslamicTabular:
    252    case CalendarId::IslamicUmmAlQura: {
    253      MOZ_ASSERT(era == EraCode::Standard || era == EraCode::Inverse);
    254      return era == EraCode::Standard ? eras::names::Islamic
    255                                      : eras::names::IslamicInverse;
    256    }
    257 
    258    case CalendarId::Japanese: {
    259      switch (era) {
    260        case EraCode::Standard:
    261          return eras::names::Gregorian;
    262        case EraCode::Inverse:
    263          return eras::names::GregorianInverse;
    264        case EraCode::Meiji:
    265          return eras::names::JapaneseMeiji;
    266        case EraCode::Taisho:
    267          return eras::names::JapaneseTaisho;
    268        case EraCode::Showa:
    269          return eras::names::JapaneseShowa;
    270        case EraCode::Heisei:
    271          return eras::names::JapaneseHeisei;
    272        case EraCode::Reiwa:
    273          return eras::names::JapaneseReiwa;
    274      }
    275      break;
    276    }
    277 
    278    case CalendarId::ROC: {
    279      MOZ_ASSERT(era == EraCode::Standard || era == EraCode::Inverse);
    280      return era == EraCode::Standard ? eras::names::ROC
    281                                      : eras::names::ROCInverse;
    282    }
    283  }
    284  MOZ_CRASH("invalid era");
    285 }
    286 
    287 constexpr auto CalendarEraName(CalendarId calendar, EraCode era) {
    288  auto& names = CalendarEraNames(calendar, era);
    289  MOZ_ASSERT(names.size() > 0);
    290  return *names.begin();
    291 }
    292 
    293 /**
    294 * CalendarHasMidYearEras ( calendar )
    295 */
    296 constexpr bool CalendarHasMidYearEras(CalendarId calendar) {
    297  // Steps 1-2.
    298  //
    299  // Japanese eras can start in the middle of the year. All other calendars
    300  // start their eras at year boundaries. (Or don't have eras at all.)
    301  return calendar == CalendarId::Japanese;
    302 }
    303 
    304 constexpr bool IsJapaneseEraName(EraCode era) {
    305  switch (era) {
    306    case EraCode::Standard:
    307    case EraCode::Inverse:
    308      return false;
    309    case EraCode::Meiji:
    310    case EraCode::Taisho:
    311    case EraCode::Showa:
    312    case EraCode::Heisei:
    313    case EraCode::Reiwa:
    314      return true;
    315  }
    316  MOZ_CRASH("invalid era");
    317 }
    318 
    319 struct EraYear {
    320  EraCode era = EraCode::Standard;
    321  int32_t year = 0;
    322 };
    323 
    324 constexpr EraYear CalendarEraYear(CalendarId calendar, int32_t year) {
    325  if (year > 0 || !CalendarEraHasInverse(calendar)) {
    326    return EraYear{EraCode::Standard, year};
    327  }
    328  return EraYear{EraCode::Inverse, int32_t(mozilla::Abs(year) + 1)};
    329 }
    330 
    331 }  // namespace js::temporal
    332 
    333 #endif /* builtin_temporal_Era_h */