From 41869d8cb08d444f7d9b0fe2c50b20cf574299de Mon Sep 17 00:00:00 2001 From: Joshua Moerman Date: Sun, 1 Dec 2013 17:37:54 +0100 Subject: [PATCH] Added a second way to save an image --- include/utilities.hpp | 28 ++++++++++++++ wavelet/compressed_image.hpp | 21 ++++++++++- wavelet/compressed_image_test.cpp | 62 ++++++++++++++++++++++++++----- wavelet/file_test.cpp | 0 wavelet/wavelet2.hpp | 0 wavelet/wavelet_constants.hpp | 0 6 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 wavelet/file_test.cpp create mode 100644 wavelet/wavelet2.hpp create mode 100644 wavelet/wavelet_constants.hpp diff --git a/include/utilities.hpp b/include/utilities.hpp index 2156fcc..1fd6cd1 100644 --- a/include/utilities.hpp +++ b/include/utilities.hpp @@ -1,11 +1,19 @@ #pragma once #include +#include inline bool is_pow_of_two(int n){ return (n & (n - 1)) == 0; } +// calculates integer 2-log such that: +// 2^(two_log(x)) >= x > 2^(two_log(x) - 1) +unsigned int two_log(unsigned int x){ + if(x <= 1) return 0; + return 8*sizeof(unsigned int) - __builtin_clz(x-1); +} + inline std::string human_string(int n){ static const std::string names [] = {"", "K", "M", "G"}; int i = 0; @@ -22,3 +30,23 @@ inline std::string field(std::string const & str){ auto add = length - str.size(); return str + ":" + std::string(add, ' ') + "\t"; } + +struct timer{ + typedef std::chrono::high_resolution_clock clock; + typedef std::chrono::time_point time; + typedef std::chrono::duration seconds; + + std::string name; + time begin; + + timer(std::string name) + : name(name) + , begin(clock::now()) + {} + + ~timer(){ + time end = clock::now(); + seconds elapsed = end - begin; + std::cout << name << "\t" << elapsed.count() << std::endl; + } +}; diff --git a/wavelet/compressed_image.hpp b/wavelet/compressed_image.hpp index 3bbc4d4..4cfa171 100644 --- a/wavelet/compressed_image.hpp +++ b/wavelet/compressed_image.hpp @@ -43,6 +43,9 @@ namespace jcmp { } }; + // Way of writing does not matter for performance + // timings: http://i.imgur.com/cskC43O.png (300 points per method) + // It's not surprising as filebuf is already a buffer inline void write_to_file(image const & image, std::string filename){ std::filebuf file; file.open(filename, std::ios_base::out|std::ios_base::trunc); @@ -50,6 +53,23 @@ namespace jcmp { file.sputn(reinterpret_cast(image.data.data()), image.data.size() * sizeof(coefficient)); } + // Assumes Iterator points to a coefficient] + // length in header is not used + template + inline void write_to_file(header h, Iterator begin, Iterator end, std::string filename){ + h.length = 0; + std::filebuf file; + file.open(filename, std::ios_base::out|std::ios_base::trunc); + file.sputn(reinterpret_cast(&h), sizeof(header)); + while(begin != end){ + file.sputn(reinterpret_cast(&*begin++), sizeof(coefficient)); + h.length++; + } + // http://stackoverflow.com/questions/2530274/how-to-overwrite-only-part-of-a-file-in-c + file.pubseekpos(0); + file.sputn(reinterpret_cast(&h), sizeof(header)); + } + inline image read_from_file(std::string const& filename){ std::filebuf file; file.open(filename, std::ios_base::in); @@ -60,5 +80,4 @@ namespace jcmp { file.sgetn(reinterpret_cast(image.data.data()), image.data.size() * sizeof(coefficient)); return image; } - } diff --git a/wavelet/compressed_image_test.cpp b/wavelet/compressed_image_test.cpp index fad089d..0b511d3 100644 --- a/wavelet/compressed_image_test.cpp +++ b/wavelet/compressed_image_test.cpp @@ -1,4 +1,5 @@ #include +#include #include "compressed_image.hpp" namespace jcmp{ @@ -21,22 +22,63 @@ struct gen{ } }; -int main(){ +void test_correctness(){ const int w = 1024, h = 512; - srand(time(0)); - std::vector v(w*h / 100); std::generate(v.begin(), v.end(), gen{w, 0, 0}); - jcmp::image i(w, h, std::move(v)); + { // iterator method + jcmp::write_to_file({w, h}, v.begin(), v.end(), "test.jcmp"); + auto j = jcmp::read_from_file("test.jcmp"); + + assert(w == j.header.width); + assert(h == j.header.height); + assert(v == j.data); + } + + { // copy method + jcmp::image i(w, h, std::move(v)); + + jcmp::write_to_file(i, "test.jcmp"); + auto j = jcmp::read_from_file("test.jcmp"); + + assert(w == j.header.width); + assert(h == j.header.height); + assert(i.data == j.data); + } +} + +void test_speed(){ + const int w = 4000, h = 8000; + std::vector input(w*h / 20); + std::generate(input.begin(), input.end(), gen{w, 0, 0}); - jcmp::write_to_file(i, "test.jcmp"); - auto j = jcmp::read_from_file("test.jcmp"); + for(int i = 0; i < 10; ++i){ + { timer t("stream"); + jcmp::write_to_file({w, h}, input.begin(), input.end(), "stream.jcmp"); + } + + std::vector copy(w*h / 20); + std::copy(input.begin(), input.end(), copy.begin()); - assert(w == j.header.width); - assert(h == j.header.height); - assert(i.data.size() == j.data.size()); - assert(i.data == j.data); + { timer t("move"); + jcmp::image i(w, h, std::move(copy)); + jcmp::write_to_file(i, "move.jcmp"); + } + { timer t("copy"); + jcmp::image i(w, h, input); + jcmp::write_to_file(i, "copy.jcmp"); + } + } +} + +int main(){ + srand(time(0)); + + test_correctness(); std::cout << "Test succeeded" << std::endl; + + test_speed(); + std::cout << "Test completed" << std::endl; } diff --git a/wavelet/file_test.cpp b/wavelet/file_test.cpp new file mode 100644 index 0000000..e69de29 diff --git a/wavelet/wavelet2.hpp b/wavelet/wavelet2.hpp new file mode 100644 index 0000000..e69de29 diff --git a/wavelet/wavelet_constants.hpp b/wavelet/wavelet_constants.hpp new file mode 100644 index 0000000..e69de29