mfbt/EnumSet.h
author Andrea Marchesini <amarchesini@mozilla.com>
Wed, 31 Oct 2018 18:30:18 +0100
changeset 500246 544498045a9cfe55968fa6500bffbc3181869fce
parent 494798 8fb46c61e091b2b812ebeee76466abb520cf4f85
child 505383 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1486698 - Update Fetch+Stream implementation to throw when the stream is disturbed or locked, r=bz In this patch, I went through any place in DOM fetch code, where there are ReadableStreams and update the locked, disturbed, readable checks. Because we expose streams more often, we need an extra care in the use of ErrorResult objects. JS streams can now throw exceptions and we need to handle them. This patch also fixes a bug in FileStreamReader::CloseAndRelease() which could be called in case mReader creation fails.

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* A set abstraction for enumeration values. */

#ifndef mozilla_EnumSet_h
#define mozilla_EnumSet_h

#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"

#include <initializer_list>
#include <type_traits>

#include <stdint.h>

namespace mozilla {

/**
 * EnumSet<T, U> is a set of values defined by an enumeration. It is implemented
 * using a bit mask with the size of U for each value. It works both for enum
 * and enum class types.
 */
template<typename T,
         typename Serialized = typename std::make_unsigned<typename std::underlying_type<T>::type>::type>
class EnumSet
{
public:
  typedef T valueType;

  constexpr EnumSet()
    : mBitField(0)
  {
  }

  constexpr MOZ_IMPLICIT EnumSet(T aEnum)
    : mBitField(bitFor(aEnum))
  { }

  constexpr EnumSet(T aEnum1, T aEnum2)
    : mBitField(bitFor(aEnum1) |
                bitFor(aEnum2))
  {
  }

  constexpr EnumSet(T aEnum1, T aEnum2, T aEnum3)
    : mBitField(bitFor(aEnum1) |
                bitFor(aEnum2) |
                bitFor(aEnum3))
  {
  }

  constexpr EnumSet(T aEnum1, T aEnum2, T aEnum3, T aEnum4)
    : mBitField(bitFor(aEnum1) |
                bitFor(aEnum2) |
                bitFor(aEnum3) |
                bitFor(aEnum4))
  {
  }

  MOZ_IMPLICIT EnumSet(std::initializer_list<T> list)
    : mBitField(0)
  {
    for (auto value : list) {
      (*this) += value;
    }
  }

  constexpr EnumSet(const EnumSet& aEnumSet)
    : mBitField(aEnumSet.mBitField)
  {
  }

  /**
   * Add an element
   */
  void operator+=(T aEnum)
  {
    incVersion();
    mBitField |= bitFor(aEnum);
  }

  /**
   * Add an element
   */
  EnumSet operator+(T aEnum) const
  {
    EnumSet result(*this);
    result += aEnum;
    return result;
  }

  /**
   * Union
   */
  void operator+=(const EnumSet& aEnumSet)
  {
    incVersion();
    mBitField |= aEnumSet.mBitField;
  }

  /**
   * Union
   */
  EnumSet operator+(const EnumSet& aEnumSet) const
  {
    EnumSet result(*this);
    result += aEnumSet;
    return result;
  }

  /**
   * Remove an element
   */
  void operator-=(T aEnum)
  {
    incVersion();
    mBitField &= ~(bitFor(aEnum));
  }

  /**
   * Remove an element
   */
  EnumSet operator-(T aEnum) const
  {
    EnumSet result(*this);
    result -= aEnum;
    return result;
  }

  /**
   * Remove a set of elements
   */
  void operator-=(const EnumSet& aEnumSet)
  {
    incVersion();
    mBitField &= ~(aEnumSet.mBitField);
  }

  /**
   * Remove a set of elements
   */
  EnumSet operator-(const EnumSet& aEnumSet) const
  {
    EnumSet result(*this);
    result -= aEnumSet;
    return result;
  }

  /**
   * Clear
   */
  void clear()
  {
    incVersion();
    mBitField = 0;
  }

  /**
   * Intersection
   */
  void operator&=(const EnumSet& aEnumSet)
  {
    incVersion();
    mBitField &= aEnumSet.mBitField;
  }

  /**
   * Intersection
   */
  EnumSet operator&(const EnumSet& aEnumSet) const
  {
    EnumSet result(*this);
    result &= aEnumSet;
    return result;
  }

  /**
   * Equality
   */
  bool operator==(const EnumSet& aEnumSet) const
  {
    return mBitField == aEnumSet.mBitField;
  }

  /**
   * Equality
   */
  bool operator==(T aEnum) const
  {
    return mBitField == bitFor(aEnum);
  }

  /**
   * Not equal
   */
  bool operator!=(const EnumSet& aEnumSet) const
  {
    return !operator==(aEnumSet);
  }

  /**
   * Not equal
   */
  bool operator!=(T aEnum) const
  {
    return !operator==(aEnum);
  }

  /**
   * Test is an element is contained in the set.
   */
  bool contains(T aEnum) const
  {
    return mBitField & bitFor(aEnum);
  }

  /**
   * Test if a set is contained in the set.
   */
  bool contains(const EnumSet& aEnumSet) const
  {
    return (mBitField & aEnumSet.mBitField) == aEnumSet.mBitField;
  }

  /**
   * Return the number of elements in the set.
   */
  uint8_t size() const
  {
    uint8_t count = 0;
    for (Serialized bitField = mBitField; bitField; bitField >>= 1) {
      if (bitField & 1) {
        count++;
      }
    }
    return count;
  }

  bool isEmpty() const
  {
    return mBitField == 0;
  }

  Serialized serialize() const
  {
    return mBitField;
  }

  void deserialize(Serialized aValue)
  {
    incVersion();
    mBitField = aValue;
  }

  class ConstIterator
  {
    const EnumSet* mSet;
    uint32_t mPos;
#ifdef DEBUG
    uint64_t mVersion;
#endif

    void checkVersion() const {
      // Check that the set has not been modified while being iterated.
      MOZ_ASSERT_IF(mSet, mSet->mVersion == mVersion);
    }

   public:
    ConstIterator(const EnumSet& aSet, uint32_t aPos)
     : mSet(&aSet), mPos(aPos)
    {
#ifdef DEBUG
      mVersion = mSet->mVersion;
#endif
      MOZ_ASSERT(aPos <= kMaxBits);
      if (aPos != kMaxBits && !mSet->contains(T(mPos)))
        ++*this;
    }

    ConstIterator(const ConstIterator& aOther)
     : mSet(aOther.mSet), mPos(aOther.mPos)
    {
#ifdef DEBUG
      mVersion = aOther.mVersion;
      checkVersion();
#endif
    }

    ConstIterator(ConstIterator&& aOther)
     : mSet(aOther.mSet), mPos(aOther.mPos)
    {
#ifdef DEBUG
      mVersion = aOther.mVersion;
      checkVersion();
#endif
      aOther.mSet = nullptr;
    }

    ~ConstIterator() {
      checkVersion();
    }

    bool operator==(const ConstIterator& other) const {
      MOZ_ASSERT(mSet == other.mSet);
      checkVersion();
      return mPos == other.mPos;
    }

    bool operator!=(const ConstIterator& other) const {
      return !(*this == other);
    }

    T operator*() const {
      MOZ_ASSERT(mSet);
      MOZ_ASSERT(mPos < kMaxBits);
      MOZ_ASSERT(mSet->contains(T(mPos)));
      checkVersion();
      return T(mPos);
    }

    ConstIterator& operator++() {
      MOZ_ASSERT(mSet);
      MOZ_ASSERT(mPos < kMaxBits);
      checkVersion();
      do {
        mPos++;
      } while (mPos < kMaxBits && !mSet->contains(T(mPos)));
      return *this;
    }
  };

  ConstIterator begin() const {
    return ConstIterator(*this, 0);
  }

  ConstIterator end() const {
    return ConstIterator(*this, kMaxBits);
  }

private:
  constexpr static Serialized bitFor(T aEnum)
  {
    auto bitNumber = static_cast<Serialized>(aEnum);
    MOZ_DIAGNOSTIC_ASSERT(bitNumber < kMaxBits);
    return Serialized(1) << bitNumber;
  }

  void incVersion() {
#ifdef DEBUG
    mVersion++;
#endif
  }

  static const size_t kMaxBits = sizeof(Serialized) * 8;

  Serialized mBitField;

#ifdef DEBUG
  uint64_t mVersion = 0;
#endif
};

} // namespace mozilla

#endif /* mozilla_EnumSet_h_*/