tor-browser

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

CalendarFields.h (12045B)


      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_CalendarFields_h
      8 #define builtin_temporal_CalendarFields_h
      9 
     10 #include "mozilla/Assertions.h"
     11 #include "mozilla/Attributes.h"
     12 #include "mozilla/EnumSet.h"
     13 #include "mozilla/EnumTypeTraits.h"
     14 #include "mozilla/FloatingPoint.h"
     15 
     16 #include <cmath>
     17 #include <stdint.h>
     18 
     19 #include "jstypes.h"
     20 
     21 #include "builtin/temporal/MonthCode.h"
     22 #include "builtin/temporal/TemporalUnit.h"
     23 #include "builtin/temporal/TimeZone.h"
     24 #include "js/RootingAPI.h"
     25 #include "js/TypeDecls.h"
     26 
     27 class JS_PUBLIC_API JSTracer;
     28 
     29 namespace js::temporal {
     30 
     31 // NB: The fields must be sorted alphabetically!
     32 enum class CalendarField {
     33  Day,
     34  Era,
     35  EraYear,
     36  Hour,
     37  Microsecond,
     38  Millisecond,
     39  Minute,
     40  Month,
     41  MonthCode,
     42  Nanosecond,
     43  Offset,
     44  Second,
     45  TimeZone,
     46  Year,
     47 };
     48 
     49 class MonthCodeField final {
     50  // Packed representation for ordinal month (31 bits) and leap month (1 bit).
     51  uint32_t code_ = 0;
     52 
     53 public:
     54  MonthCodeField() = default;
     55 
     56  MonthCodeField(int32_t ordinal, bool isLeapMonth)
     57      : code_((ordinal << 1) | isLeapMonth) {
     58    MOZ_ASSERT(ordinal >= 0);
     59    MOZ_ASSERT_IF(ordinal == 0, isLeapMonth);
     60  }
     61 
     62  MOZ_IMPLICIT MonthCodeField(MonthCode monthCode)
     63      : MonthCodeField(monthCode.ordinal(), monthCode.isLeapMonth()) {}
     64 
     65  int32_t ordinal() const { return (code_ >> 1); }
     66 
     67  bool isLeapMonth() const { return bool(code_ & 1); }
     68 };
     69 
     70 class OffsetField final {
     71  int64_t offset_ = INT64_MIN;
     72 
     73 public:
     74  OffsetField() = default;
     75 
     76  explicit OffsetField(int64_t offset) : offset_(offset) {
     77    MOZ_ASSERT(std::abs(offset) < ToNanoseconds(TemporalUnit::Day));
     78  }
     79 
     80  explicit operator int64_t() const {
     81    MOZ_ASSERT(offset_ != INT64_MIN);
     82    return offset_;
     83  }
     84 };
     85 
     86 // Default values are specified in [1]. `UNSET` is replaced with an appropriate
     87 // value based on the type, for example `double` fields use NaN whereas pointer
     88 // fields use nullptr.
     89 //
     90 // [1]
     91 // <https://tc39.es/proposal-temporal/#table-temporal-calendar-fields-record-fields>
     92 class MOZ_STACK_CLASS CalendarFields final {
     93  mozilla::EnumSet<CalendarField> fields_ = {};
     94 
     95  JSString* era_ = nullptr;
     96  double eraYear_ = mozilla::UnspecifiedNaN<double>();
     97  double year_ = mozilla::UnspecifiedNaN<double>();
     98  double month_ = mozilla::UnspecifiedNaN<double>();
     99  MonthCodeField monthCode_ = {};
    100  double day_ = mozilla::UnspecifiedNaN<double>();
    101  double hour_ = 0;
    102  double minute_ = 0;
    103  double second_ = 0;
    104  double millisecond_ = 0;
    105  double microsecond_ = 0;
    106  double nanosecond_ = 0;
    107  OffsetField offset_ = {};
    108  TimeZoneValue timeZone_ = {};
    109 
    110 public:
    111  CalendarFields() = default;
    112  CalendarFields(const CalendarFields&) = default;
    113 
    114  auto* era() const { return era_; }
    115  auto eraYear() const { return eraYear_; }
    116  auto year() const { return year_; }
    117  auto month() const { return month_; }
    118  auto monthCode() const { return monthCode_; }
    119  auto day() const { return day_; }
    120  auto hour() const { return hour_; }
    121  auto minute() const { return minute_; }
    122  auto second() const { return second_; }
    123  auto millisecond() const { return millisecond_; }
    124  auto microsecond() const { return microsecond_; }
    125  auto nanosecond() const { return nanosecond_; }
    126  auto offset() const { return offset_; }
    127  auto& timeZone() const { return timeZone_; }
    128 
    129  void setEra(JSString* era) {
    130    fields_ += CalendarField::Era;
    131    era_ = era;
    132  }
    133  void setEraYear(double eraYear) {
    134    fields_ += CalendarField::EraYear;
    135    eraYear_ = eraYear;
    136  }
    137  void setYear(double year) {
    138    fields_ += CalendarField::Year;
    139    year_ = year;
    140  }
    141  void setMonth(double month) {
    142    fields_ += CalendarField::Month;
    143    month_ = month;
    144  }
    145  void setMonthCode(MonthCodeField monthCode) {
    146    fields_ += CalendarField::MonthCode;
    147    monthCode_ = monthCode;
    148  }
    149  void setDay(double day) {
    150    fields_ += CalendarField::Day;
    151    day_ = day;
    152  }
    153  void setHour(double hour) {
    154    fields_ += CalendarField::Hour;
    155    hour_ = hour;
    156  }
    157  void setMinute(double minute) {
    158    fields_ += CalendarField::Minute;
    159    minute_ = minute;
    160  }
    161  void setSecond(double second) {
    162    fields_ += CalendarField::Second;
    163    second_ = second;
    164  }
    165  void setMillisecond(double millisecond) {
    166    fields_ += CalendarField::Millisecond;
    167    millisecond_ = millisecond;
    168  }
    169  void setMicrosecond(double microsecond) {
    170    fields_ += CalendarField::Microsecond;
    171    microsecond_ = microsecond;
    172  }
    173  void setNanosecond(double nanosecond) {
    174    fields_ += CalendarField::Nanosecond;
    175    nanosecond_ = nanosecond;
    176  }
    177  void setOffset(OffsetField offset) {
    178    fields_ += CalendarField::Offset;
    179    offset_ = offset;
    180  }
    181  void setTimeZone(const TimeZoneValue& timeZone) {
    182    fields_ += CalendarField::TimeZone;
    183    timeZone_ = timeZone;
    184  }
    185 
    186  /**
    187   * Return `true` if the field is present.
    188   */
    189  bool has(CalendarField field) const { return fields_.contains(field); }
    190 
    191  /**
    192   * Return the set of all present fields.
    193   */
    194  mozilla::EnumSet<CalendarField> keys() const { return fields_; }
    195 
    196  /**
    197   * Mark that `field` is present, but uses its default value. The field must
    198   * not already be present in `this`.
    199   */
    200  void setDefault(CalendarField field) {
    201    MOZ_ASSERT(!fields_.contains(field));
    202 
    203    // Field whose default value is not UNSET.
    204    static constexpr mozilla::EnumSet<CalendarField> notUnsetDefault = {
    205        CalendarField::Hour,        CalendarField::Minute,
    206        CalendarField::Second,      CalendarField::Millisecond,
    207        CalendarField::Microsecond, CalendarField::Nanosecond,
    208    };
    209 
    210    // Fields whose default value is UNSET are ignored.
    211    if (notUnsetDefault.contains(field)) {
    212      fields_ += field;
    213    }
    214  }
    215 
    216  /**
    217   * Set `field` from `source`. The field must be present in `source`.
    218   */
    219  void setFrom(CalendarField field, const CalendarFields& source);
    220 
    221  // Helper methods for WrappedPtrOperations.
    222  auto eraDoNotUse() const { return &era_; }
    223  auto timeZoneDoNotUse() const { return &timeZone_; }
    224 
    225  // Trace implementation.
    226  void trace(JSTracer* trc);
    227 };
    228 }  // namespace js::temporal
    229 
    230 namespace js {
    231 
    232 template <typename Wrapper>
    233 class WrappedPtrOperations<temporal::CalendarFields, Wrapper> {
    234  const temporal::CalendarFields& container() const {
    235    return static_cast<const Wrapper*>(this)->get();
    236  }
    237 
    238 public:
    239  JS::Handle<JSString*> era() const {
    240    return JS::Handle<JSString*>::fromMarkedLocation(container().eraDoNotUse());
    241  }
    242  double eraYear() const { return container().eraYear(); }
    243  double year() const { return container().year(); }
    244  double month() const { return container().month(); }
    245  temporal::MonthCodeField monthCode() const { return container().monthCode(); }
    246  double day() const { return container().day(); }
    247  double hour() const { return container().hour(); }
    248  double minute() const { return container().minute(); }
    249  double second() const { return container().second(); }
    250  double millisecond() const { return container().millisecond(); }
    251  double microsecond() const { return container().microsecond(); }
    252  double nanosecond() const { return container().nanosecond(); }
    253  temporal::OffsetField offset() const { return container().offset(); }
    254  JS::Handle<temporal::TimeZoneValue> timeZone() const {
    255    return JS::Handle<temporal::TimeZoneValue>::fromMarkedLocation(
    256        container().timeZoneDoNotUse());
    257  }
    258 
    259  bool has(temporal::CalendarField field) const {
    260    return container().has(field);
    261  }
    262  auto keys() const { return container().keys(); }
    263 };
    264 
    265 template <typename Wrapper>
    266 class MutableWrappedPtrOperations<temporal::CalendarFields, Wrapper>
    267    : public WrappedPtrOperations<temporal::CalendarFields, Wrapper> {
    268  temporal::CalendarFields& container() {
    269    return static_cast<Wrapper*>(this)->get();
    270  }
    271 
    272 public:
    273  void setEra(JSString* era) { container().setEra(era); }
    274  void setEraYear(double eraYear) { container().setEraYear(eraYear); }
    275  void setYear(double year) { container().setYear(year); }
    276  void setMonth(double month) { container().setMonth(month); }
    277  void setMonthCode(temporal::MonthCodeField monthCode) {
    278    container().setMonthCode(monthCode);
    279  }
    280  void setDay(double day) { container().setDay(day); }
    281  void setHour(double hour) { container().setHour(hour); }
    282  void setMinute(double minute) { container().setMinute(minute); }
    283  void setSecond(double second) { container().setSecond(second); }
    284  void setMillisecond(double millisecond) {
    285    container().setMillisecond(millisecond);
    286  }
    287  void setMicrosecond(double microsecond) {
    288    container().setMicrosecond(microsecond);
    289  }
    290  void setNanosecond(double nanosecond) {
    291    container().setNanosecond(nanosecond);
    292  }
    293  void setOffset(temporal::OffsetField offset) {
    294    container().setOffset(offset);
    295  }
    296  void setTimeZone(const temporal::TimeZoneValue& timeZone) {
    297    container().setTimeZone(timeZone);
    298  }
    299 
    300  void setDefault(temporal::CalendarField field) {
    301    container().setDefault(field);
    302  }
    303 };
    304 
    305 }  // namespace js
    306 
    307 namespace js::temporal {
    308 
    309 class CalendarValue;
    310 class PlainDate;
    311 class PlainDateTime;
    312 class PlainMonthDay;
    313 class PlainYearMonth;
    314 
    315 /**
    316 * PrepareCalendarFields ( calendar, fields, calendarFieldNames,
    317 * nonCalendarFieldNames, requiredFieldNames )
    318 */
    319 bool PrepareCalendarFields(JSContext* cx, JS::Handle<CalendarValue> calendar,
    320                           JS::Handle<JSObject*> fields,
    321                           mozilla::EnumSet<CalendarField> fieldNames,
    322                           mozilla::EnumSet<CalendarField> requiredFields,
    323                           JS::MutableHandle<CalendarFields> result);
    324 
    325 /**
    326 * PrepareCalendarFields ( calendar, fields, calendarFieldNames,
    327 * nonCalendarFieldNames, requiredFieldNames )
    328 */
    329 inline bool PrepareCalendarFields(JSContext* cx,
    330                                  JS::Handle<CalendarValue> calendar,
    331                                  JS::Handle<JSObject*> fields,
    332                                  mozilla::EnumSet<CalendarField> fieldNames,
    333                                  JS::MutableHandle<CalendarFields> result) {
    334  return PrepareCalendarFields(cx, calendar, fields, fieldNames, {}, result);
    335 }
    336 
    337 /**
    338 * PrepareCalendarFields ( calendar, fields, calendarFieldNames,
    339 * nonCalendarFieldNames, requiredFieldNames )
    340 */
    341 bool PreparePartialCalendarFields(JSContext* cx,
    342                                  JS::Handle<CalendarValue> calendar,
    343                                  JS::Handle<JSObject*> fields,
    344                                  mozilla::EnumSet<CalendarField> fieldNames,
    345                                  JS::MutableHandle<CalendarFields> result);
    346 
    347 /**
    348 * CalendarMergeFields ( calendar, fields, additionalFields )
    349 */
    350 CalendarFields CalendarMergeFields(const CalendarValue& calendar,
    351                                   const CalendarFields& fields,
    352                                   const CalendarFields& additionalFields);
    353 
    354 /**
    355 * ISODateToFields ( calendar, isoDate, type )
    356 */
    357 bool ISODateToFields(JSContext* cx, Handle<PlainDate> date,
    358                     MutableHandle<CalendarFields> result);
    359 
    360 /**
    361 * ISODateToFields ( calendar, isoDate, type )
    362 */
    363 bool ISODateToFields(JSContext* cx, Handle<PlainDateTime> dateTime,
    364                     MutableHandle<CalendarFields> result);
    365 
    366 /**
    367 * ISODateToFields ( calendar, isoDate, type )
    368 */
    369 bool ISODateToFields(JSContext* cx, Handle<PlainMonthDay> monthDay,
    370                     MutableHandle<CalendarFields> result);
    371 
    372 /**
    373 * ISODateToFields ( calendar, isoDate, type )
    374 */
    375 bool ISODateToFields(JSContext* cx, Handle<PlainYearMonth> yearMonth,
    376                     MutableHandle<CalendarFields> result);
    377 
    378 } /* namespace js::temporal */
    379 
    380 namespace mozilla {
    381 template <>
    382 struct MaxContiguousEnumValue<js::temporal::CalendarField> {
    383  static constexpr auto value = js::temporal::CalendarField::Year;
    384 };
    385 }  // namespace mozilla
    386 
    387 #endif /* builtin_temporal_CalendarFields_h */