#include <vector>
#include <deque>
#include <array>
#include <sstream>

#include <boost/double_ended/devector.hpp>
#include <boost/double_ended/batch_deque.hpp>
#include <boost/double_ended/serialize_devector.hpp>
#include <boost/double_ended/serialize_batch_deque.hpp>

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/deque.hpp>

#include <benchmark/benchmark.h>

namespace {

template <typename Container>
void deserialize_container(benchmark::State& state)
{
  std::stringstream stream(
    std::ios_base::binary
  | std::ios_base::in
  | std::ios_base::out
  );
  {
    Container c(state.range(0));
    boost::archive::binary_oarchive out(stream);
    out << c;
  }

  while (state.KeepRunning()) {
    state.PauseTiming();

    stream.seekg(0);
    boost::archive::binary_iarchive in(stream);
    Container c;

    state.ResumeTiming();

    in >> c;
    benchmark::DoNotOptimize(c);
  }
}

BENCHMARK_TEMPLATE(deserialize_container, boost::double_ended::devector<char>)->Range(8, 8 << 12);
BENCHMARK_TEMPLATE(deserialize_container, boost::double_ended::devector<int>)->Range(8, 8 << 12);
BENCHMARK_TEMPLATE(deserialize_container, boost::double_ended::devector<std::array<char, 32>>)->Range(8, 8 << 12);

BENCHMARK_TEMPLATE(deserialize_container, boost::double_ended::batch_deque<char>)->Range(8, 8 << 12);
BENCHMARK_TEMPLATE(deserialize_container, boost::double_ended::batch_deque<int>)->Range(8, 8 << 12);
BENCHMARK_TEMPLATE(deserialize_container, boost::double_ended::batch_deque<std::array<char, 32>>)->Range(8, 8 << 12);

BENCHMARK_TEMPLATE(deserialize_container, std::vector<char>)->Range(8, 8 << 12);
BENCHMARK_TEMPLATE(deserialize_container, std::vector<int>)->Range(8, 8 << 12);
BENCHMARK_TEMPLATE(deserialize_container, std::vector<std::array<char, 32>>)->Range(8, 8 << 12);

BENCHMARK_TEMPLATE(deserialize_container, std::deque<char>)->Range(8, 8 << 12);
BENCHMARK_TEMPLATE(deserialize_container, std::deque<int>)->Range(8, 8 << 12);
BENCHMARK_TEMPLATE(deserialize_container, std::deque<std::array<char, 32>>)->Range(8, 8 << 12);

} // namespace

BENCHMARK_MAIN();

