tor-browser

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

fields.h (13948B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #ifndef LIB_JXL_FIELDS_H_
      7 #define LIB_JXL_FIELDS_H_
      8 
      9 // Forward/backward-compatible 'bundles' with auto-serialized 'fields'.
     10 
     11 #include <cstddef>
     12 #include <cstdint>
     13 #include <cstdlib>
     14 #include <cstring>
     15 
     16 #include "lib/jxl/base/compiler_specific.h"
     17 #include "lib/jxl/base/status.h"
     18 #include "lib/jxl/dec_bit_reader.h"
     19 #include "lib/jxl/field_encodings.h"
     20 
     21 namespace jxl {
     22 
     23 struct AuxOut;
     24 enum class LayerType : uint8_t;
     25 struct BitWriter;
     26 
     27 // Integer coders: BitsCoder (raw), U32Coder (table), U64Coder (varint).
     28 
     29 // Reads/writes a given (fixed) number of bits <= 32.
     30 namespace BitsCoder {
     31 size_t MaxEncodedBits(size_t bits);
     32 
     33 Status CanEncode(size_t bits, uint32_t value,
     34                 size_t* JXL_RESTRICT encoded_bits);
     35 
     36 uint32_t Read(size_t bits, BitReader* JXL_RESTRICT reader);
     37 
     38 // Returns false if the value is too large to encode.
     39 Status Write(size_t bits, uint32_t value, BitWriter* JXL_RESTRICT writer);
     40 }  // namespace BitsCoder
     41 
     42 // Encodes u32 using a lookup table and/or extra bits, governed by a per-field
     43 // encoding `enc` which consists of four distributions `d` chosen via a 2-bit
     44 // selector (least significant = 0). Each d may have two modes:
     45 // - direct: if d.IsDirect(), the value is d.Direct();
     46 // - offset: the value is derived from d.ExtraBits() extra bits plus d.Offset();
     47 // This encoding is denser than Exp-Golomb or Gamma codes when both small and
     48 // large values occur.
     49 //
     50 // Examples:
     51 // Direct: U32Enc(Val(8), Val(16), Val(32), Bits(6)), value 32 => 10b.
     52 // Offset: U32Enc(Val(0), BitsOffset(1, 1), BitsOffset(2, 3), BitsOffset(8, 8))
     53 //   defines the following prefix code:
     54 //   00 -> 0
     55 //   01x -> 1..2
     56 //   10xx -> 3..7
     57 //   11xxxxxxxx -> 8..263
     58 namespace U32Coder {
     59 size_t MaxEncodedBits(U32Enc enc);
     60 Status CanEncode(U32Enc enc, uint32_t value, size_t* JXL_RESTRICT encoded_bits);
     61 uint32_t Read(U32Enc enc, BitReader* JXL_RESTRICT reader);
     62 
     63 // Returns false if the value is too large to encode.
     64 Status Write(U32Enc enc, uint32_t value, BitWriter* JXL_RESTRICT writer);
     65 
     66 // "private"
     67 Status ChooseSelector(U32Enc enc, uint32_t value,
     68                      uint32_t* JXL_RESTRICT selector,
     69                      size_t* JXL_RESTRICT total_bits);
     70 }  // namespace U32Coder
     71 
     72 // Encodes 64-bit unsigned integers with a fixed distribution, taking 2 bits
     73 // to encode 0, 6 bits to encode 1 to 16, 10 bits to encode 17 to 272, 15 bits
     74 // to encode up to 4095, and on the order of log2(value) * 1.125 bits for
     75 // larger values.
     76 namespace U64Coder {
     77 constexpr size_t MaxEncodedBits() { return 2 + 12 + 6 * (8 + 1) + (4 + 1); }
     78 
     79 uint64_t Read(BitReader* JXL_RESTRICT reader);
     80 
     81 // Returns false if the value is too large to encode.
     82 Status Write(uint64_t value, BitWriter* JXL_RESTRICT writer);
     83 
     84 // Can always encode, but useful because it also returns bit size.
     85 Status CanEncode(uint64_t value, size_t* JXL_RESTRICT encoded_bits);
     86 }  // namespace U64Coder
     87 
     88 // IEEE 754 half-precision (binary16). Refuses to read/write NaN/Inf.
     89 namespace F16Coder {
     90 constexpr size_t MaxEncodedBits() { return 16; }
     91 
     92 // Returns false if the bit representation is NaN or infinity
     93 Status Read(BitReader* JXL_RESTRICT reader, float* JXL_RESTRICT value);
     94 
     95 // Returns false if the value is too large to encode.
     96 Status Write(float value, BitWriter* JXL_RESTRICT writer);
     97 Status CanEncode(float value, size_t* JXL_RESTRICT encoded_bits);
     98 }  // namespace F16Coder
     99 
    100 // A "bundle" is a forward- and backward compatible collection of fields.
    101 // They are used for SizeHeader/FrameHeader/GroupHeader. Bundles can be
    102 // extended by appending(!) fields. Optional fields may be omitted from the
    103 // bitstream by conditionally visiting them. When reading new bitstreams with
    104 // old code, we skip unknown fields at the end of the bundle. This requires
    105 // storing the amount of extra appended bits, and that fields are visited in
    106 // chronological order of being added to the format, because old decoders
    107 // cannot skip some future fields and resume reading old fields. Similarly,
    108 // new readers query bits in an "extensions" field to skip (groups of) fields
    109 // not present in old bitstreams. Note that each bundle must include an
    110 // "extensions" field prior to freezing the format, otherwise it cannot be
    111 // extended.
    112 //
    113 // To ensure interoperability, there will be no opaque fields.
    114 //
    115 // HOWTO:
    116 // - basic usage: define a struct with member variables ("fields") and a
    117 //   VisitFields(v) member function that calls v->U32/Bool etc. for each
    118 //   field, specifying their default values. The ctor must call
    119 //   Bundle::Init(this).
    120 //
    121 // - print a trace of visitors: ensure each bundle has a static Name() member
    122 //   function, and change Bundle::Print* to return true.
    123 //
    124 // - optional fields: in VisitFields, add if (v->Conditional(your_condition))
    125 //   { v->Bool(default, &field); }. This prevents reading/writing field
    126 //   if !your_condition, which is typically computed from a prior field.
    127 //   WARNING: to ensure all fields are initialized, do not add an else branch;
    128 //   instead add another if (v->Conditional(!your_condition)).
    129 //
    130 // - repeated fields: for dynamic sizes, use e.g. std::vector and in
    131 //   VisitFields, if (v->IsReading()) field.resize(size) before accessing field.
    132 //   For static or bounded sizes, use an array or std::array. In all cases,
    133 //   simply visit each array element as if it were a normal field.
    134 //
    135 // - nested bundles: add a bundle as a normal field and in VisitFields call
    136 //   JXL_RETURN_IF_ERROR(v->VisitNested(&nested));
    137 //
    138 // - allow future extensions: define a "uint64_t extensions" field and call
    139 //   v->BeginExtensions(&extensions) after visiting all non-extension fields,
    140 //   and `return v->EndExtensions();` after the last extension field.
    141 //
    142 // - encode an entire bundle in one bit if ALL its fields equal their default
    143 //   values: add a "mutable bool all_default" field and as the first visitor:
    144 //   if (v->AllDefault(*this, &all_default)) {
    145 //     // Overwrite all serialized fields, but not any nonserialized_*.
    146 //     v->SetDefault(this);
    147 //     return true;
    148 //   }
    149 //   Note: if extensions are present, AllDefault() == false.
    150 
    151 namespace Bundle {
    152 constexpr size_t kMaxExtensions = 64;  // bits in u64
    153 
    154 // Initializes fields to the default values. It is not recursive to nested
    155 // fields, this function is intended to be called in the constructors so
    156 // each nested field will already Init itself.
    157 void Init(Fields* JXL_RESTRICT fields);
    158 
    159 // Similar to Init, but recursive to nested fields.
    160 void SetDefault(Fields* JXL_RESTRICT fields);
    161 
    162 // Returns whether ALL fields (including `extensions`, if present) are equal
    163 // to their default value.
    164 bool AllDefault(const Fields& fields);
    165 
    166 // Returns max number of bits required to encode a T.
    167 size_t MaxBits(const Fields& fields);
    168 
    169 // Returns whether a header's fields can all be encoded, i.e. they have a
    170 // valid representation. If so, "*total_bits" is the exact number of bits
    171 // required. Called by Write.
    172 Status CanEncode(const Fields& fields, size_t* JXL_RESTRICT extension_bits,
    173                 size_t* JXL_RESTRICT total_bits);
    174 
    175 Status Read(BitReader* reader, Fields* JXL_RESTRICT fields);
    176 
    177 // Returns whether enough bits are available to fully read this bundle using
    178 // Read. Also returns true in case of a codestream error (other than not being
    179 // large enough): that means enough bits are available to determine there's an
    180 // error, use Read to get such error status.
    181 // NOTE: this advances the BitReader, a different one pointing back at the
    182 // original bit position in the codestream must be created to use Read after
    183 // this.
    184 bool CanRead(BitReader* reader, Fields* JXL_RESTRICT fields);
    185 
    186 Status Write(const Fields& fields, BitWriter* JXL_RESTRICT writer,
    187             LayerType layer, AuxOut* aux_out);
    188 }  // namespace Bundle
    189 
    190 // Different subclasses of Visitor are passed to implementations of Fields
    191 // throughout their lifetime. Templates used to be used for this but dynamic
    192 // polymorphism produces more compact executables than template reification did.
    193 class Visitor {
    194 public:
    195  virtual ~Visitor() = default;
    196  virtual Status Visit(Fields* fields) = 0;
    197 
    198  virtual Status Bool(bool default_value, bool* JXL_RESTRICT value) = 0;
    199  virtual Status U32(U32Enc, uint32_t, uint32_t*) = 0;
    200 
    201  // Helper to construct U32Enc from U32Distr.
    202  Status U32(const U32Distr d0, const U32Distr d1, const U32Distr d2,
    203             const U32Distr d3, const uint32_t default_value,
    204             uint32_t* JXL_RESTRICT value) {
    205    return U32(U32Enc(d0, d1, d2, d3), default_value, value);
    206  }
    207 
    208  template <typename EnumT>
    209  Status Enum(const EnumT default_value, EnumT* JXL_RESTRICT value) {
    210    uint32_t u32 = static_cast<uint32_t>(*value);
    211    // 00 -> 0
    212    // 01 -> 1
    213    // 10xxxx -> 2..17
    214    // 11yyyyyy -> 18..81
    215    JXL_RETURN_IF_ERROR(U32(Val(0), Val(1), BitsOffset(4, 2), BitsOffset(6, 18),
    216                            static_cast<uint32_t>(default_value), &u32));
    217    *value = static_cast<EnumT>(u32);
    218    return EnumValid(*value);
    219  }
    220 
    221  virtual Status Bits(size_t bits, uint32_t default_value,
    222                      uint32_t* JXL_RESTRICT value) = 0;
    223  virtual Status U64(uint64_t default_value, uint64_t* JXL_RESTRICT value) = 0;
    224  virtual Status F16(float default_value, float* JXL_RESTRICT value) = 0;
    225 
    226  // Returns whether VisitFields should visit some subsequent fields.
    227  // "condition" is typically from prior fields, e.g. flags.
    228  // Overridden by InitVisitor and MaxBitsVisitor.
    229  virtual Status Conditional(bool condition) { return condition; }
    230 
    231  // Overridden by InitVisitor, AllDefaultVisitor and CanEncodeVisitor.
    232  virtual Status AllDefault(const Fields& /*fields*/,
    233                            bool* JXL_RESTRICT all_default) {
    234    JXL_RETURN_IF_ERROR(Bool(true, all_default));
    235    return *all_default;
    236  }
    237 
    238  virtual void SetDefault(Fields* /*fields*/) {
    239    // Do nothing by default, this is overridden by ReadVisitor.
    240  }
    241 
    242  // Returns the result of visiting a nested Bundle.
    243  // Overridden by InitVisitor.
    244  virtual Status VisitNested(Fields* fields) { return Visit(fields); }
    245 
    246  // Overridden by ReadVisitor. Enables dynamically-sized fields.
    247  virtual bool IsReading() const { return false; }
    248 
    249  virtual Status BeginExtensions(uint64_t* JXL_RESTRICT extensions) = 0;
    250  virtual Status EndExtensions() = 0;
    251 };
    252 
    253 namespace fields_internal {
    254 // A bundle can be in one of three states concerning extensions: not-begun,
    255 // active, ended. Bundles may be nested, so we need a stack of states.
    256 class ExtensionStates {
    257 public:
    258  void Push() {
    259    // Initial state = not-begun.
    260    begun_ <<= 1;
    261    ended_ <<= 1;
    262  }
    263 
    264  // Clears current state; caller must check IsEnded beforehand.
    265  void Pop() {
    266    begun_ >>= 1;
    267    ended_ >>= 1;
    268  }
    269 
    270  // Returns true if state == active || state == ended.
    271  Status IsBegun() const { return (begun_ & 1) != 0; }
    272  // Returns true if state != not-begun && state != active.
    273  Status IsEnded() const { return (ended_ & 1) != 0; }
    274 
    275  void Begin() {
    276    JXL_DASSERT(!IsBegun());
    277    JXL_DASSERT(!IsEnded());
    278    begun_ += 1;
    279  }
    280 
    281  void End() {
    282    JXL_DASSERT(IsBegun());
    283    JXL_DASSERT(!IsEnded());
    284    ended_ += 1;
    285  }
    286 
    287 private:
    288  // Current state := least-significant bit of begun_ and ended_.
    289  uint64_t begun_ = 0;
    290  uint64_t ended_ = 0;
    291 };
    292 
    293 // Visitors generate Init/AllDefault/Read/Write logic for all fields. Each
    294 // bundle's VisitFields member function calls visitor->U32 etc. We do not
    295 // overload operator() because a function name is easier to search for.
    296 
    297 class VisitorBase : public Visitor {
    298 public:
    299  explicit VisitorBase() = default;
    300  ~VisitorBase() override { JXL_DASSERT(depth_ == 0); }
    301 
    302  // This is the only call site of Fields::VisitFields.
    303  // Ensures EndExtensions was called.
    304  Status Visit(Fields* fields) override {
    305    JXL_ENSURE(depth_ < Bundle::kMaxExtensions);
    306    depth_ += 1;
    307    extension_states_.Push();
    308 
    309    const Status ok = fields->VisitFields(this);
    310 
    311    if (ok) {
    312      // If VisitFields called BeginExtensions, must also call
    313      // EndExtensions.
    314      JXL_DASSERT(!extension_states_.IsBegun() || extension_states_.IsEnded());
    315    } else {
    316      // Failed, undefined state: don't care whether EndExtensions was
    317      // called.
    318    }
    319 
    320    extension_states_.Pop();
    321    JXL_DASSERT(depth_ != 0);
    322    depth_ -= 1;
    323 
    324    return ok;
    325  }
    326 
    327  // For visitors accepting a const Visitor, need to const-cast so we can call
    328  // the non-const Visitor::VisitFields. NOTE: C is not modified except the
    329  // `all_default` field by CanEncodeVisitor.
    330  Status VisitConst(const Fields& t) { return Visit(const_cast<Fields*>(&t)); }
    331 
    332  // Derived types (overridden by InitVisitor because it is unsafe to read
    333  // from *value there)
    334 
    335  Status Bool(bool default_value, bool* JXL_RESTRICT value) override {
    336    uint32_t bits = *value ? 1 : 0;
    337    JXL_RETURN_IF_ERROR(Bits(1, static_cast<uint32_t>(default_value), &bits));
    338    JXL_DASSERT(bits <= 1);
    339    *value = bits == 1;
    340    return true;
    341  }
    342 
    343  // Overridden by ReadVisitor and WriteVisitor.
    344  // Called before any conditional visit based on "extensions".
    345  // Overridden by ReadVisitor, CanEncodeVisitor and WriteVisitor.
    346  Status BeginExtensions(uint64_t* JXL_RESTRICT extensions) override {
    347    JXL_RETURN_IF_ERROR(U64(0, extensions));
    348 
    349    extension_states_.Begin();
    350    return true;
    351  }
    352 
    353  // Called after all extension fields (if any). Although non-extension
    354  // fields could be visited afterward, we prefer the convention that
    355  // extension fields are always the last to be visited. Overridden by
    356  // ReadVisitor.
    357  Status EndExtensions() override {
    358    extension_states_.End();
    359    return true;
    360  }
    361 
    362 private:
    363  size_t depth_ = 0;  // to check nesting
    364  ExtensionStates extension_states_;
    365 };
    366 }  // namespace fields_internal
    367 
    368 Status CheckHasEnoughBits(Visitor* visitor, size_t bits);
    369 
    370 }  // namespace jxl
    371 
    372 #endif  // LIB_JXL_FIELDS_H_