diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e936aea..bb11427 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(core) +add_subdirectory(compression) add_subdirectory(database) add_subdirectory(network) add_subdirectory(geometry) diff --git a/src/compression/CMakeLists.txt b/src/compression/CMakeLists.txt new file mode 100644 index 0000000..a635f45 --- /dev/null +++ b/src/compression/CMakeLists.txt @@ -0,0 +1,15 @@ + +list(APPEND compression_LIB_INCLUDES + StreamCompressor.cpp + HuffmanEncoder.cpp + ) + +add_library(compression SHARED ${compression_LIB_INCLUDES}) + +target_include_directories(compression PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}" + ) + +target_link_libraries(compression PUBLIC core) +set_property(TARGET compression PROPERTY FOLDER src) +set_target_properties( compression PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON ) \ No newline at end of file diff --git a/src/compression/HuffmanEncoder.cpp b/src/compression/HuffmanEncoder.cpp new file mode 100644 index 0000000..1b2901f --- /dev/null +++ b/src/compression/HuffmanEncoder.cpp @@ -0,0 +1,77 @@ +#include "HuffmanEncoder.h" + +#include "Tree.h" + +#include +#include +#include +#include + +void HuffmanEncoder::encode(const HuffmanEncoder::DataStream& stream) +{ + std::unordered_map counts; + for (auto c : stream) + { + counts[c]++; + } + + using CountPair = std::pair; + auto cmp = [](CountPair left, CountPair right) + { + return left.second > right.second; + }; + std::priority_queue, decltype(cmp)> q(cmp); + for (const auto& entry : counts) + { + q.push({entry.first, entry.second}); + } + + NodePtr lastNode; + while(!q.empty()) + { + const auto charData = q.top(); + auto characterNode = std::make_unique >(charData); + q.pop(); + + if (!lastNode) + { + const auto rightCharData = q.top(); + auto rightCharacterNode = std::make_unique >(rightCharData); + q.pop(); + + const auto sum = charData.second + rightCharData.second; + CountPair data{0, sum}; + auto midNode = std::make_unique >(data); + + midNode->addChild(std::move(characterNode)); + midNode->addChild(std::move(rightCharacterNode)); + lastNode = std::move(midNode); + } + else + { + const auto sum = lastNode->getData().second; + CountPair data{0, sum}; + auto midNode = std::make_unique >(data); + + if (charData.second < lastNode->getData().second) + { + midNode->addChild(std::move(lastNode)); + midNode->addChild(std::move(characterNode)); + } + else + { + midNode->addChild(std::move(characterNode)); + midNode->addChild(std::move(lastNode)); + } + lastNode = std::move(midNode); + } + } + + Tree tree; + tree.addRootNode(std::move(lastNode)); + + //using TableEntry = std::tuple<> + + + std::cout << "********" << std::endl; +} diff --git a/src/compression/HuffmanEncoder.h b/src/compression/HuffmanEncoder.h new file mode 100644 index 0000000..857c988 --- /dev/null +++ b/src/compression/HuffmanEncoder.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +class HuffmanEncoder +{ +using DataStream = std::vector; + +public: + void encode(const DataStream& stream); +}; diff --git a/src/compression/StreamCompressor.cpp b/src/compression/StreamCompressor.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/compression/StreamCompressor.h b/src/compression/StreamCompressor.h new file mode 100644 index 0000000..6d03767 --- /dev/null +++ b/src/compression/StreamCompressor.h @@ -0,0 +1,6 @@ +#pragma once + +class StreamCompressor +{ + +}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 130e9de..94e0d6a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -15,6 +15,7 @@ list(APPEND core_LIB_INCLUDES Dictionary.cpp Color.cpp CommandLineArgs.cpp + data_structures/Tree.cpp loggers/FileLogger.cpp file_utilities/File.cpp file_utilities/FileFormats.cpp @@ -35,6 +36,7 @@ target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/loggers" "${CMAKE_CURRENT_SOURCE_DIR}/memory" "${CMAKE_CURRENT_SOURCE_DIR}/streams" + "${CMAKE_CURRENT_SOURCE_DIR}/data_structures" ) set_target_properties( core PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON ) set_property(TARGET core PROPERTY FOLDER src) \ No newline at end of file diff --git a/src/core/data_structures/Tree.cpp b/src/core/data_structures/Tree.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/core/data_structures/Tree.h b/src/core/data_structures/Tree.h new file mode 100644 index 0000000..57166ac --- /dev/null +++ b/src/core/data_structures/Tree.h @@ -0,0 +1,66 @@ +#pragma once + +#include + +template +class Node +{ +public: + Node(T data) + : mData(data) + {} + + void addChild(std::unique_ptr child) + { + if(!mLeftChild) + { + mLeftChild = std::move(child); + } + else + { + mRightChild = std::move(child); + } + } + + bool isLeaf() const + { + return !mLeftChild && !mRightChild; + } + + T getData() const + { + return mData; + } + +private: + T mData; + unsigned char mTag{0}; + std::unique_ptr mLeftChild; + std::unique_ptr mRightChild; +}; + +template +using NodePtr = std::unique_ptr >; + +template +class Tree +{ +public: + Tree() + { + + } + + void addRootNode(NodePtr root) + { + mRootNode = std::move(root); + } + + Node* getRootNode() const + { + return mRootNode.get(); + } + +private: + NodePtr mRootNode; +}; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bdc6fb5..26143b9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,6 +11,7 @@ list(APPEND TestFiles audio/TestAudioWriter.cpp audio/TestMidiReader.cpp core/TestBinaryStream.cpp + compression/TestStreamCompressor.cpp database/TestDatabase.cpp fonts/TestFontReader.cpp graphics/TestOpenGlRendering.cpp @@ -30,6 +31,7 @@ list(APPEND TestNames TestAudioWriter TestMidiReader TestBinaryStream + TestStreamCompressor TestDatabase TestFontReader TestOpenGlRendering @@ -52,7 +54,7 @@ link_directories(${DBUS_LIBRARY_DIRS}) foreach(TestFile TestName IN ZIP_LISTS TestFiles TestNames) add_executable(${TestName} ${TestFile}) - target_link_libraries(${TestName} PUBLIC core fonts network image publishing video database geometry audio graphics web client test_utils ${DBUS_LIBRARIES}) + target_link_libraries(${TestName} PUBLIC core compression fonts network image publishing video database geometry audio graphics web client test_utils ${DBUS_LIBRARIES}) endforeach() diff --git a/test/compression/TestStreamCompressor.cpp b/test/compression/TestStreamCompressor.cpp new file mode 100644 index 0000000..37cb691 --- /dev/null +++ b/test/compression/TestStreamCompressor.cpp @@ -0,0 +1,14 @@ +#include + +#include "HuffmanEncoder.h" + +int main() +{ + std::string testData = "BCAADDDCCACACAC"; + std::vector stream(testData.begin(), testData.end()); + + HuffmanEncoder encoder; + encoder.encode(stream); + + return 0; +}