Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/circular_buffer_bound_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This example shows how the `circular_buffer` can be utilized
as an underlying container of the bounded buffer.
*/

#include <iostream>
#include <boost/circular_buffer.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
Expand Down
172 changes: 172 additions & 0 deletions example/circular_buffer_serialization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Distributed under the Boost Software License, Version 1.0.
// (See the accompanying file LICENSE_1_0.txt
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)

#include <boost/circular_buffer.hpp>
#include <sstream>
#include <iostream>
#include <cstdlib>
#include <random>
#include <chrono>
#include <fstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

int main(int argc, char** argv)
{
int buffer_size = 100000;

if (argc == 2) {
buffer_size = std::atoi(argv[1]);
if (buffer_size <= 0) {
std::cout << "invalid buffer size" << std::endl;
return 1;
}
}

// Seed with a real random value, if available
std::random_device r;

// Choose a randomly whether to push or pop
std::default_random_engine e(r());
std::uniform_int_distribution<int> uniform_dist(1, 10);

{
boost::circular_buffer<double> cb1(buffer_size);
for (auto i = 0; i < buffer_size; ++i) {
auto draw = uniform_dist(e);
if (draw < 8 || cb1.empty())
cb1.push_back(i);
else
cb1.pop_front();
}

{
// in-memory storage text
std::stringstream ss;

boost::archive::text_oarchive oa(ss);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
boost::serialization::serialize(oa, cb1, 0);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "in-memory serialization for buffer: " << buffer_size << " took: " <<
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl;

boost::circular_buffer<double> cb2(0);
boost::archive::text_iarchive ia(ss);
begin = std::chrono::steady_clock::now();
boost::serialization::serialize(ia, cb2, 0);
end = std::chrono::steady_clock::now();
std::cout << "in-memory deserialization for buffer: " << buffer_size << " took: " <<
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl;

if (cb1 != cb2) {
std::cout << "circular buffer did not recover correctly" << std::endl;
}
}

{
// in-memory storage binary
std::stringstream ss;

boost::archive::binary_oarchive oa(ss);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
boost::serialization::serialize(oa, cb1, 0);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "in-memory binary serialization for buffer: " << buffer_size << " took: " <<
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl;

boost::circular_buffer<double> cb2(0);
boost::archive::binary_iarchive ia(ss);
begin = std::chrono::steady_clock::now();
boost::serialization::serialize(ia, cb2, 0);
end = std::chrono::steady_clock::now();
std::cout << "in-memory binary deserialization for buffer: " << buffer_size << " took: " <<
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl;

if (cb1 != cb2) {
std::cout << "circular buffer did not recover correctly" << std::endl;
}
}

{
const std::string filename = "cb.tmp";
// file storage text
{
std::ofstream ofs(filename);

boost::archive::text_oarchive oa(ofs);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
boost::serialization::serialize(oa, cb1, 0);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "file serialization for buffer: " << buffer_size << " took: " <<
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl;
}
{
std::ifstream ifs(filename);

boost::circular_buffer<double> cb2(0);
boost::archive::text_iarchive ia(ifs);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
boost::serialization::serialize(ia, cb2, 0);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "file deserialization for buffer: " << buffer_size << " took: " <<
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl;

if (cb1 != cb2) {
std::cout << "circular buffer did not recover correctly" << std::endl;
}
}
std::remove(filename.c_str());
}
}

{
// space optimized
boost::circular_buffer_space_optimized<double> cb1(buffer_size);
for (auto i = 0; i < buffer_size; ++i) {
auto draw = uniform_dist(e);
if (draw < 8 || cb1.empty()) {
cb1.push_back(i);
} else {
cb1.pop_front();
}
}

{
const std::string filename = "space_opt_cb.tmp";
{
std::ofstream ofs(filename);

boost::archive::text_oarchive oa(ofs);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
boost::serialization::serialize(oa, cb1, 0);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "in-memory serialization for space optimized buffer: " << buffer_size << " took: " <<
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl;
}

{
std::ifstream ifs(filename);

boost::circular_buffer_space_optimized<double> cb2(0);
boost::archive::text_iarchive ia(ifs);
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
boost::serialization::serialize(ia, cb2, 0);
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
std::cout << "in-memory deserialization for space optimized buffer: " << buffer_size << " took: " <<
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl;

if (cb1 != cb2) {
std::cout << "space optimized circular buffer did not recover correctly" << std::endl;
}
}
std::remove(filename.c_str());
}
}

return 0;
}

2 changes: 2 additions & 0 deletions example/jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ project
: requirements
<library>/boost/system//boost_system
<library>/boost/thread//boost_thread
<library>/boost//serialization
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't match the others - is it correct?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean the library location? i don't know why it is different, but this is the correct one for serialization

#<define>BOOST_ALL_NO_LIB=1
<threading>multi

Expand Down Expand Up @@ -39,4 +40,5 @@ run bounded_buffer_comparison.cpp ;
run circular_buffer_iter_example.cpp ;
run circular_buffer_sum_example.cpp ;
run circular_buffer_bound_example.cpp ../../thread/build//boost_thread ../../timer/build//boost_timer ;
run circular_buffer_serialization.cpp ;

3 changes: 3 additions & 0 deletions include/boost/circular_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
#include <boost/circular_buffer/details.hpp>
#include <boost/circular_buffer/base.hpp>
#include <boost/circular_buffer/space_optimized.hpp>
#if !defined(BOOST_CIRCULAR_BUFFER_DISABLE_SERIALIZATION)
#include <boost/circular_buffer/serialization.hpp>
#endif

#undef BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS
#undef BOOST_CB_IS_CONVERTIBLE
Expand Down
167 changes: 167 additions & 0 deletions include/boost/circular_buffer/serialization.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// Implementation of circular_buffer serialization

// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <boost/circular_buffer.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/smart_ptr/scoped_array.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

namespace boost { namespace serialization {
template <class Archive, class T>
void save(Archive& ar, const circular_buffer<T>& b, const unsigned int /* version */)
{
ar << b.capacity();
ar << b.size();
const typename circular_buffer<T>::const_iterator it_end = b.end();
typename circular_buffer<T>::const_iterator it = b.begin();
for (; it != it_end; ++it) {
ar << *it;
}
}

template <class T>
void save(archive::binary_oarchive& ar, const circular_buffer<T>& b, const unsigned int /* version */)
{
ar << b.capacity();
const typename circular_buffer<T>::const_array_range& one = b.array_one();
const typename circular_buffer<T>::const_array_range& two = b.array_two();
ar << one.second;
ar << two.second;
if (one.second) {
ar.save_binary(one.first, one.second*sizeof(T));
}
if (two.second) {
ar.save_binary(two.first, two.second*sizeof(T));
}
}

template <class Archive, class T>
void load(Archive& ar, circular_buffer<T>& b, const unsigned int /* version */)
{
b.clear();
typename circular_buffer<T>::capacity_type capacity;
ar >> capacity;
b.set_capacity(capacity);
typename circular_buffer<T>::size_type size;
ar >> size;
while (size > 0) {
T e;
ar >> e;
b.push_back(e);
--size;
}
}

template <class T>
void load(archive::binary_iarchive& ar, circular_buffer<T>& b, const unsigned int /* version */)
{
b.clear();
typename circular_buffer<T>::capacity_type capacity;
ar >> capacity;
b.set_capacity(capacity);
typename circular_buffer<T>::size_type size1;
typename circular_buffer<T>::size_type size2;
ar >> size1;
ar >> size2;
const scoped_array<typename circular_buffer<T>::value_type> buff(new T[size1+size2]);
if (size1) {
ar.load_binary(buff.get(), size1*sizeof(T));
}
if (size2) {
ar.load_binary(&buff[size1], size2*sizeof(T));
}
b.insert(b.begin(), buff.get(), buff.get()+size1+size2);
}

template<class Archive, class T>
inline void serialize(Archive & ar, circular_buffer<T>& b, const unsigned int version)
{
split_free(ar, b, version);
}

template <class Archive, class T>
void save(Archive& ar, const circular_buffer_space_optimized<T>& b, const unsigned int /* version */)
{
ar << b.capacity().capacity();
ar << b.capacity().min_capacity();
ar << b.size();
const typename circular_buffer_space_optimized<T>::const_iterator it_end = b.end();
typename circular_buffer_space_optimized<T>::const_iterator it = b.begin();
for (; it != it_end; ++it) {
ar << *it;
}
}

template <class T>
void save(archive::binary_oarchive& ar, const circular_buffer_space_optimized<T>& b, const unsigned int /* version */)
{
ar << b.capacity().capacity();
ar << b.capacity().min_capacity();
const typename circular_buffer_space_optimized<T>::const_array_range one = b.array_one();
const typename circular_buffer_space_optimized<T>::const_array_range two = b.array_two();
ar << one.second;
ar << two.second;
if (one.second) {
ar.save_binary(one.first, one.second*sizeof(T));
}
if (two.second) {
ar.save_binary(two.first, two.second*sizeof(T));
}
}

template <class Archive, class T>
void load(Archive& ar, circular_buffer_space_optimized<T>& b, const unsigned int /* version */)
{
b.clear();
typename circular_buffer_space_optimized<T>::size_type capacity;
typename circular_buffer_space_optimized<T>::size_type min_capacity;
ar >> capacity;
ar >> min_capacity;
const typename circular_buffer_space_optimized<T>::capacity_type capacity_control(capacity, min_capacity);
b.set_capacity(capacity_control);
typename circular_buffer<T>::size_type size;
ar >> size;
while (size > 0) {
T e;
ar >> e;
b.push_back(e);
--size;
}
}

template <class T>
void load(archive::binary_iarchive& ar, circular_buffer_space_optimized<T>& b, const unsigned int /* version */)
{
b.clear();
typename circular_buffer_space_optimized<T>::size_type capacity;
typename circular_buffer_space_optimized<T>::size_type min_capacity;
ar >> capacity;
ar >> min_capacity;
const typename circular_buffer_space_optimized<T>::capacity_type capacity_control(capacity, min_capacity);
b.set_capacity(capacity_control);
typename circular_buffer<T>::size_type size1;
typename circular_buffer<T>::size_type size2;
ar >> size1;
ar >> size2;
const scoped_array<typename circular_buffer<T>::value_type> buff(new T[size1+size2]);
if (size1) {
ar.load_binary(buff.get(), size1*sizeof(T));
}
if (size2) {
ar.load_binary(&buff[size1], size2*sizeof(T));
}
b.insert(b.begin(), buff.get(), buff.get()+size1+size2);
}

template<class Archive, class T>
inline void serialize(Archive & ar, circular_buffer_space_optimized<T>& b, const unsigned int version)
{
split_free(ar, b, version);
}

} } // end namespace boost::serialization

4 changes: 4 additions & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import testing ;

project
: requirements
<library>/boost/test//boost_unit_test_framework
<library>/boost/serialization
<link>static
<toolset>msvc:<warnings>all
<toolset>msvc:<asynch-exceptions>on
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
Expand All @@ -29,4 +32,5 @@ test-suite "circular_buffer"
[ run soft_iterator_invalidation.cpp : : : <threading>single : ]
[ run constant_erase_test.cpp : : : <threading>single : ]
[ compile bounded_buffer_comparison.cpp : <threading>multi : ]
[ run serialization_test.cpp : : : <threading>single : ]
;
Loading