| /* |
| * Copyright (C) 2012 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #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 |