#ifndef Compression_h
#define Compression_h
#include <memory>
#include <wtf/Vector.h>
namespace WTF {
class GenericCompressedData {
WTF_MAKE_NONCOPYABLE(GenericCompressedData)
WTF_MAKE_FAST_ALLOCATED;
public:
WTF_EXPORT_PRIVATE static std::unique_ptr<GenericCompressedData> create(const uint8_t*, size_t);
uint32_t compressedSize() const { return m_compressedSize; }
uint32_t originalSize() const { return m_originalSize; }
WTF_EXPORT_PRIVATE bool decompress(uint8_t* destination, size_t bufferSize, size_t* decompressedByteCount = 0);
private:
GenericCompressedData(size_t originalSize, size_t compressedSize)
{
UNUSED_PARAM(m_data);
ASSERT(!m_originalSize);
ASSERT(!m_compressedSize);
m_originalSize = originalSize;
m_compressedSize = compressedSize;
}
uint32_t m_originalSize;
uint32_t m_compressedSize;
uint8_t m_data[1];
};
template <typename T> class CompressedVector : public GenericCompressedData {
public:
static std::unique_ptr<CompressedVector> create(const Vector<T>& source)
{
std::unique_ptr<GenericCompressedData> result = GenericCompressedData::create(reinterpret_cast<const uint8_t*>(source.data()), sizeof(T) * source.size());
return std::unique_ptr<CompressedVector<T>>(static_cast<CompressedVector<T>*>(result.release()));
}
void decompress(Vector<T>& destination)
{
Vector<T> output(originalSize() / sizeof(T));
ASSERT(output.size() * sizeof(T) == originalSize());
size_t decompressedByteCount = 0;
GenericCompressedData::decompress(reinterpret_cast<uint8_t*>(output.data()), originalSize(), &decompressedByteCount);
ASSERT(decompressedByteCount == originalSize());
ASSERT(output.size() * sizeof(T) == decompressedByteCount);
destination.swap(output);
}
size_t size() const { return originalSize() / sizeof(T); }
};
template <typename T> class CompressibleVector {
WTF_MAKE_NONCOPYABLE(CompressibleVector)
public:
CompressibleVector(size_t size = 0)
: m_decompressedData(size)
{
}
typedef typename Vector<T>::iterator iterator;
typedef typename Vector<T>::const_iterator const_iterator;
void shrinkToFit()
{
ASSERT(!m_compressedData);
m_compressedData = CompressedVector<T>::create(m_decompressedData);
if (m_compressedData)
m_decompressedData.clear();
else
m_decompressedData.shrinkToFit();
}
size_t size()
{
if (m_compressedData)
return m_compressedData->size();
return m_decompressedData.size();
}
template <typename U> T& operator[](Checked<U> index) { return data().at(index); }
template <typename U> const T& operator[](Checked<U> index) const { return data().at(index); }
template <typename U> T& at(Checked<U> index) { return data().at(index); }
template <typename U> const T& at(Checked<U> index) const { return data().at(index); }
iterator begin() { return data().begin(); }
iterator end() { return data().end(); }
const_iterator begin() const { return data().begin(); }
const_iterator end() const { return data().end(); }
const Vector<T>& data() const
{
decompressIfNecessary();
return m_decompressedData;
}
Vector<T>& data()
{
decompressIfNecessary();
return m_decompressedData;
}
private:
void decompressIfNecessary() const
{
if (!m_compressedData)
return;
m_compressedData->decompress(m_decompressedData);
m_compressedData = nullptr;
}
mutable Vector<T> m_decompressedData;
mutable std::unique_ptr<CompressedVector<T>> m_compressedData;
};
}
using WTF::GenericCompressedData;
using WTF::CompressedVector;
using WTF::CompressibleVector;
#endif