#include <iostream>
#include <chrono>
#include <string>
#include <map>
#include <cstdint>
#include <ctime>
#include <random>
#include <algorithm>
#include <utility>

class Elapsed {
  std::chrono::high_resolution_clock::time_point firstTime;
  std::string mes;
public:
  Elapsed(const std::string& s) : mes(s) {
    firstTime = std::chrono::high_resolution_clock::now();
  }
  ~Elapsed() {
    std::cout << mes << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - firstTime).count() << "ms" << std::endl;
  }
};

class Heavy {
  static const int N = 100000;
  double* d;
public:
  Heavy() : d(new double[N]) {}
  Heavy(const Heavy& h) { // copy constructor
    d = new double[N];
    std::copy(h.d, h.d + N, d);
  }
//  Heavy(Heavy&& h) { // move constructor
//    d = h.d;
//    h.d = nullptr;
//  }
  ~Heavy() { delete[] d; }
};

const int ITER = 100;
const int NSEEDS = 10;

int main()
{
  typedef std::map<double, Heavy> MDH;
  MDH m;

  std::uint32_t seeds[NSEEDS];
  auto t = std::time(nullptr);

  for (std::size_t i = 0; i < NSEEDS; i++)
    if (seeds[i] == 0)
      seeds[i] = t * (i + 3) ;

  std::seed_seq seed_seq(seeds, seeds + NSEEDS);
  std::mt19937 twister(seed_seq);
  std::uniform_real_distribution<> dist(0.0, 10000.0);

  {
    Elapsed ep("value_type = ");

    for (int i = 0; i < ITER; i++)
      m.insert(MDH::value_type(dist(twister), Heavy()));
  }
  m.clear();
  {
    Elapsed ep("std::pair = ");

    for (int i = 0; i < ITER; i++)
      m.insert(std::pair<double, Heavy>(dist(twister), Heavy()));
  }
  m.clear();
  {
    Elapsed ep("std::make_pair = ");

    for (int i = 0; i < ITER; i++)
      m.insert(std::make_pair(dist(twister), Heavy()));
  }
  m.clear();
  {
    Elapsed ep("std::emplace = ");

    for (int i = 0; i < ITER; i++)
      m.emplace(dist(twister), Heavy());
  }
}
