Bug 1586971 - Add SingleEntryHuffmanTable. r=Yoric

Differential Revision: https://phabricator.services.mozilla.com/D48473

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Tooru Fujisawa 2019-10-11 03:45:59 +00:00
Родитель be1002620d
Коммит cce326db03
2 изменённых файлов: 114 добавлений и 27 удалений

Просмотреть файл

@ -1620,6 +1620,11 @@ FlatHuffmanKey::FlatHuffmanKey(const HuffmanKey* key)
// ---- Implementation of Huffman Tables
template <typename T>
GenericHuffmanTable<T>::Iterator::Iterator(
typename SingleEntryHuffmanTable<T>::Iterator&& iterator)
: implementation(std::move(iterator)) {}
template <typename T>
GenericHuffmanTable<T>::Iterator::Iterator(
typename SingleLookupHuffmanTable<T>::Iterator&& iterator)
@ -1638,6 +1643,9 @@ GenericHuffmanTable<T>::Iterator::Iterator(
template <typename T>
void GenericHuffmanTable<T>::Iterator::operator++() {
implementation.match(
[](typename SingleEntryHuffmanTable<T>::Iterator& iterator) {
iterator.operator++();
},
[](typename SingleLookupHuffmanTable<T>::Iterator& iterator) {
iterator.operator++();
},
@ -1653,6 +1661,10 @@ template <typename T>
bool GenericHuffmanTable<T>::Iterator::operator==(
const GenericHuffmanTable<T>::Iterator& other) const {
return implementation.match(
[other](const typename SingleEntryHuffmanTable<T>::Iterator& iterator) {
return iterator == other.implementation.template as<
typename SingleEntryHuffmanTable<T>::Iterator>();
},
[other](const typename SingleLookupHuffmanTable<T>::Iterator& iterator) {
return iterator ==
other.implementation.template as<
@ -1674,6 +1686,10 @@ template <typename T>
bool GenericHuffmanTable<T>::Iterator::operator!=(
const GenericHuffmanTable<T>::Iterator& other) const {
return implementation.match(
[other](const typename SingleEntryHuffmanTable<T>::Iterator& iterator) {
return iterator != other.implementation.template as<
typename SingleEntryHuffmanTable<T>::Iterator>();
},
[other](const typename SingleLookupHuffmanTable<T>::Iterator& iterator) {
return iterator !=
other.implementation.template as<
@ -1694,6 +1710,9 @@ bool GenericHuffmanTable<T>::Iterator::operator!=(
template <typename T>
const T* GenericHuffmanTable<T>::Iterator::operator*() const {
return implementation.match(
[](const typename SingleEntryHuffmanTable<T>::Iterator& iterator) {
return iterator.operator*();
},
[](const typename SingleLookupHuffmanTable<T>::Iterator& iterator) {
return iterator.operator*();
},
@ -1712,6 +1731,9 @@ GenericHuffmanTable<T>::GenericHuffmanTable(JSContext*)
template <typename T>
JS::Result<Ok> GenericHuffmanTable<T>::initComplete() {
return this->implementation.match(
[](SingleEntryHuffmanTable<T>& implementation) -> JS::Result<Ok> {
MOZ_CRASH("SingleEntryHuffmanTable shouldn't have multiple entries!");
},
[](SingleLookupHuffmanTable<T>& implementation) -> JS::Result<Ok> {
return implementation.initComplete();
},
@ -1730,6 +1752,10 @@ template <typename T>
typename GenericHuffmanTable<T>::Iterator GenericHuffmanTable<T>::begin()
const {
return this->implementation.match(
[](const SingleEntryHuffmanTable<T>& implementation)
-> GenericHuffmanTable<T>::Iterator {
return Iterator(implementation.begin());
},
[](const SingleLookupHuffmanTable<T>& implementation)
-> GenericHuffmanTable<T>::Iterator {
return Iterator(implementation.begin());
@ -1750,6 +1776,10 @@ typename GenericHuffmanTable<T>::Iterator GenericHuffmanTable<T>::begin()
template <typename T>
typename GenericHuffmanTable<T>::Iterator GenericHuffmanTable<T>::end() const {
return this->implementation.match(
[](const SingleEntryHuffmanTable<T>& implementation)
-> GenericHuffmanTable<T>::Iterator {
return Iterator(implementation.end());
},
[](const SingleLookupHuffmanTable<T>& implementation)
-> GenericHuffmanTable<T>::Iterator {
return Iterator(implementation.end());
@ -1774,11 +1804,8 @@ JS::Result<Ok> GenericHuffmanTable<T>::initWithSingleValue(JSContext* cx,
MOZ_ASSERT(this->implementation.template is<
HuffmanTableUnreachable>()); // Make sure that we're initializing.
this->implementation = {mozilla::VariantType<SingleLookupHuffmanTable<T>>{},
cx};
MOZ_TRY(this->implementation.template as<SingleLookupHuffmanTable<T>>()
.initWithSingleValue(cx, std::move(value)));
this->implementation = {mozilla::VariantType<SingleEntryHuffmanTable<T>>{},
std::move(value)};
return Ok();
}
@ -1823,6 +1850,10 @@ template <typename T>
JS::Result<Ok> GenericHuffmanTable<T>::addSymbol(uint32_t bits,
uint8_t bitLength, T&& value) {
return this->implementation.match(
[](SingleEntryHuffmanTable<T>&) -> JS::Result<Ok> {
MOZ_CRASH("SingleEntryHuffmanTable shouldn't have multiple entries!");
return Ok();
},
[bits, bitLength, value = std::move(value)](
SingleLookupHuffmanTable<T>&
implementation) mutable /* discard implicit const */
@ -1851,6 +1882,8 @@ template <typename T>
HuffmanEntry<const T*> GenericHuffmanTable<T>::lookup(
HuffmanLookup lookup) const {
return this->implementation.match(
[lookup](const SingleEntryHuffmanTable<T>& implementation)
-> HuffmanEntry<const T*> { return implementation.lookup(lookup); },
[lookup](const SingleLookupHuffmanTable<T>& implementation)
-> HuffmanEntry<const T*> { return implementation.lookup(lookup); },
[lookup](const TwoLookupsHuffmanTable<T>& implementation)
@ -1999,6 +2032,39 @@ HuffmanEntry<const T*> MapBasedHuffmanTable<T>::lookup(
return HuffmanEntry<const T*>(0, 0, nullptr);
}
template <typename T>
SingleEntryHuffmanTable<T>::Iterator::Iterator(const T* position)
: position(position) {}
template <typename T>
void SingleEntryHuffmanTable<T>::Iterator::operator++() {
// There's only one entry, and `nullptr` means `end`.
position = nullptr;
}
template <typename T>
const T* SingleEntryHuffmanTable<T>::Iterator::operator*() const {
return position;
}
template <typename T>
bool SingleEntryHuffmanTable<T>::Iterator::operator==(
const Iterator& other) const {
return position == other.position;
}
template <typename T>
bool SingleEntryHuffmanTable<T>::Iterator::operator!=(
const Iterator& other) const {
return position != other.position;
}
template <typename T>
HuffmanEntry<const T*> SingleEntryHuffmanTable<T>::lookup(
HuffmanLookup key) const {
return HuffmanEntry<const T*>(0, 0, &value_);
}
template <typename T>
SingleLookupHuffmanTable<T>::Iterator::Iterator(const HuffmanEntry<T>* position)
: position(position) {}
@ -2025,22 +2091,6 @@ bool SingleLookupHuffmanTable<T>::Iterator::operator!=(
return position != other.position;
}
template <typename T>
JS::Result<Ok> SingleLookupHuffmanTable<T>::initWithSingleValue(JSContext* cx,
T&& value) {
MOZ_ASSERT(values.empty()); // Make sure that we're initializing.
if (MOZ_UNLIKELY(!values.emplaceBack(0, 0, std::move(value)))) {
ReportOutOfMemory(cx);
return cx->alreadyReportedError();
}
if (MOZ_UNLIKELY(!saturated.emplaceBack(0))) {
ReportOutOfMemory(cx);
return cx->alreadyReportedError();
}
this->largestBitLength = 0;
return Ok();
}
template <typename T>
JS::Result<Ok> SingleLookupHuffmanTable<T>::initStart(
JSContext* cx, size_t numberOfSymbols, uint8_t largestBitLength) {

Просмотреть файл

@ -355,6 +355,43 @@ class MapBasedHuffmanTable {
friend class HuffmanPreludeReader;
};
// An implementation of Huffman Tables for single-entry table.
template <typename T>
class SingleEntryHuffmanTable {
public:
explicit SingleEntryHuffmanTable(T&& value) : value_(std::move(value)) {}
SingleEntryHuffmanTable(SingleEntryHuffmanTable&& other) = default;
SingleEntryHuffmanTable() = delete;
SingleEntryHuffmanTable(SingleEntryHuffmanTable&) = delete;
// Lookup a value in the table.
// The key is 0-bit length and this always suceeds.
HuffmanEntry<const T*> lookup(HuffmanLookup key) const;
// The number of values in the table.
size_t length() const { return 1; }
// Iterating in the order of insertion.
struct Iterator {
explicit Iterator(const T* position);
void operator++();
const T* operator*() const;
bool operator==(const Iterator& other) const;
bool operator!=(const Iterator& other) const;
private:
const T* position;
};
Iterator begin() const { return Iterator(&value_); }
Iterator end() const { return Iterator(nullptr); }
private:
T value_;
friend class HuffmanPreludeReader;
};
// An implementation of Huffman Tables as a vector designed to allow
// constant-time lookups at the expense of high space complexity.
//
@ -442,9 +479,6 @@ class SingleLookupHuffmanTable {
: values(cx), saturated(cx), largestBitLength(-1) {}
SingleLookupHuffmanTable(SingleLookupHuffmanTable&& other) = default;
// Initialize a Huffman table containing a single value.
JS::Result<Ok> initWithSingleValue(JSContext* cx, T&& value);
// Initialize a Huffman table containing `numberOfSymbols`.
// Symbols must be added with `addSymbol`.
// If you initialize with `initStart`, you MUST call `initComplete()`
@ -770,6 +804,7 @@ struct GenericHuffmanTable {
size_t length() const;
struct Iterator {
explicit Iterator(typename SingleEntryHuffmanTable<T>::Iterator&&);
explicit Iterator(typename SingleLookupHuffmanTable<T>::Iterator&&);
explicit Iterator(typename TwoLookupsHuffmanTable<T>::Iterator&&);
explicit Iterator(typename ThreeLookupsHuffmanTable<T>::Iterator&&);
@ -781,7 +816,8 @@ struct GenericHuffmanTable {
bool operator!=(const Iterator& other) const;
private:
mozilla::Variant<typename SingleLookupHuffmanTable<T>::Iterator,
mozilla::Variant<typename SingleEntryHuffmanTable<T>::Iterator,
typename SingleLookupHuffmanTable<T>::Iterator,
typename TwoLookupsHuffmanTable<T>::Iterator,
typename ThreeLookupsHuffmanTable<T>::Iterator>
implementation;
@ -805,8 +841,9 @@ struct GenericHuffmanTable {
HuffmanEntry<const T*> lookup(HuffmanLookup key) const;
private:
mozilla::Variant<SingleLookupHuffmanTable<T>, TwoLookupsHuffmanTable<T>,
ThreeLookupsHuffmanTable<T>, HuffmanTableUnreachable>
mozilla::Variant<SingleEntryHuffmanTable<T>, SingleLookupHuffmanTable<T>,
TwoLookupsHuffmanTable<T>, ThreeLookupsHuffmanTable<T>,
HuffmanTableUnreachable>
implementation;
};