simple arrayo of doubles instead of std::vector
diff --git a/tuple/include/array_of_doubles_intersection.hpp b/tuple/include/array_of_doubles_intersection.hpp
index 008d9d6..89459c3 100644
--- a/tuple/include/array_of_doubles_intersection.hpp
+++ b/tuple/include/array_of_doubles_intersection.hpp
@@ -32,10 +32,10 @@
   typename Policy,
   typename Allocator = std::allocator<double>
 >
-class array_of_doubles_intersection: public tuple_intersection<std::vector<double, Allocator>, Policy, AllocVectorDouble<Allocator>> {
+class array_of_doubles_intersection: public tuple_intersection<aod<Allocator>, Policy, AllocAOD<Allocator>> {
 public:
-  using Summary = std::vector<double, Allocator>;
-  using AllocSummary = AllocVectorDouble<Allocator>;
+  using Summary = aod<Allocator>;
+  using AllocSummary = AllocAOD<Allocator>;
   using Base = tuple_intersection<Summary, Policy, AllocSummary>;
   using CompactSketch = compact_array_of_doubles_sketch_alloc<Allocator>;
   using resize_factor = theta_constants::resize_factor;
diff --git a/tuple/include/array_of_doubles_sketch.hpp b/tuple/include/array_of_doubles_sketch.hpp
index a3c26d1..af9e87a 100644
--- a/tuple/include/array_of_doubles_sketch.hpp
+++ b/tuple/include/array_of_doubles_sketch.hpp
@@ -28,18 +28,71 @@
 
 namespace datasketches {
 
-// equivalent of ArrayOfDoublesSketch in Java
+// This sketch is equivalent of ArrayOfDoublesSketch in Java
+
+// This simple array of double is faster than std::vector and should be sufficient for this application
+template<typename Allocator = std::allocator<double>>
+class aod {
+public:
+  explicit aod(uint8_t size, const Allocator& allocator = Allocator()):
+  allocator_(allocator), size_(size), array_(allocator_.allocate(size_)) {
+    std::fill(array_, array_ + size_, 0);
+  }
+  aod(const aod& other):
+    allocator_(other.allocator_),
+    size_(other.size_),
+    array_(allocator_.allocate(size_))
+  {
+    std::copy(other.array_, other.array_ + size_, array_);
+  }
+  aod(aod&& other) noexcept:
+    allocator_(std::move(other.allocator_)),
+    size_(other.size_),
+    array_(other.array_)
+  {
+    other.array_ = nullptr;
+  }
+  ~aod() {
+    if (array_ != nullptr) allocator_.deallocate(array_, size_);
+  }
+  aod& operator=(const aod& other) {
+    aod copy(other);
+    std::swap(allocator_, copy.allocator_);
+    std::swap(size_, copy.size_);
+    std::swap(array_, copy.array_);
+    return *this;
+  }
+  aod& operator=(aod&& other) {
+    std::swap(allocator_, other.allocator_);
+    std::swap(size_, other.size_);
+    std::swap(array_, other.array_);
+    return *this;
+  }
+  double& operator[](size_t index) { return array_[index]; }
+  double operator[](size_t index) const { return array_[index]; }
+  uint8_t size() const { return size_; }
+  double* data() { return array_; }
+  const double* data() const { return array_; }
+  bool operator==(const aod& other) const {
+    for (uint8_t i = 0; i < size_; ++i) if (array_[i] != other.array_[i]) return false;
+    return true;
+  }
+private:
+  Allocator allocator_;
+  uint8_t size_;
+  double* array_;
+};
 
 template<typename A = std::allocator<double>>
 class array_of_doubles_update_policy {
 public:
   array_of_doubles_update_policy(uint8_t num_values = 1, const A& allocator = A()):
     allocator_(allocator), num_values_(num_values) {}
-  std::vector<double, A> create() const {
-    return std::vector<double, A>(num_values_, 0, allocator_);
+  aod<A> create() const {
+    return aod<A>(num_values_, allocator_);
   }
   template<typename InputVector> // to allow any type with indexed access (such as double*)
-  void update(std::vector<double, A>& summary, const InputVector& update) const {
+  void update(aod<A>& summary, const InputVector& update) const {
     for (uint8_t i = 0; i < num_values_; ++i) summary[i] += update[i];
   }
   uint8_t get_num_values() const {
@@ -54,13 +107,12 @@
 // forward declaration
 template<typename A> class compact_array_of_doubles_sketch_alloc;
 
-template<typename A> using AllocVectorDouble = typename std::allocator_traits<A>::template rebind_alloc<std::vector<double, A>>;
+template<typename A> using AllocAOD = typename std::allocator_traits<A>::template rebind_alloc<aod<A>>;
 
 template<typename A = std::allocator<double>>
-class update_array_of_doubles_sketch_alloc: public update_tuple_sketch<std::vector<double, A>, std::vector<double, A>,
-array_of_doubles_update_policy<A>, AllocVectorDouble<A>> {
+class update_array_of_doubles_sketch_alloc: public update_tuple_sketch<aod<A>, aod<A>, array_of_doubles_update_policy<A>, AllocAOD<A>> {
 public:
-  using Base = update_tuple_sketch<std::vector<double, A>, std::vector<double, A>, array_of_doubles_update_policy<A>, AllocVectorDouble<A>>;
+  using Base = update_tuple_sketch<aod<A>, aod<A>, array_of_doubles_update_policy<A>, AllocAOD<A>>;
   using resize_factor = typename Base::resize_factor;
 
   class builder;
@@ -85,9 +137,9 @@
 };
 
 template<typename A = std::allocator<double>>
-class compact_array_of_doubles_sketch_alloc: public compact_tuple_sketch<std::vector<double, A>, AllocVectorDouble<A>> {
+class compact_array_of_doubles_sketch_alloc: public compact_tuple_sketch<aod<A>, AllocAOD<A>> {
 public:
-  using Base = compact_tuple_sketch<std::vector<double, A>, AllocVectorDouble<A>>;
+  using Base = compact_tuple_sketch<aod<A>, AllocAOD<A>>;
   using Entry = typename Base::Entry;
   using AllocEntry = typename Base::AllocEntry;
   using AllocU64 = typename Base::AllocU64;
diff --git a/tuple/include/array_of_doubles_sketch_impl.hpp b/tuple/include/array_of_doubles_sketch_impl.hpp
index 16fa925..6457072 100644
--- a/tuple/include/array_of_doubles_sketch_impl.hpp
+++ b/tuple/include/array_of_doubles_sketch_impl.hpp
@@ -176,7 +176,7 @@
     std::vector<uint64_t, AllocU64> keys(num_entries, 0, allocator);
     is.read(reinterpret_cast<char*>(keys.data()), num_entries * sizeof(uint64_t));
     for (size_t i = 0; i < num_entries; ++i) {
-      std::vector<double, A> summary(num_values, 0, allocator);
+      aod<A> summary(num_values, allocator);
       is.read(reinterpret_cast<char*>(summary.data()), num_values * sizeof(double));
       entries.push_back(Entry(keys[i], std::move(summary)));
     }
@@ -225,7 +225,7 @@
     std::vector<uint64_t, AllocU64> keys(num_entries, 0, allocator);
     ptr += copy_from_mem(ptr, keys.data(), sizeof(uint64_t) * num_entries);
     for (size_t i = 0; i < num_entries; ++i) {
-      std::vector<double, A> summary(num_values, 0, allocator);
+      aod<A> summary(num_values, allocator);
       ptr += copy_from_mem(ptr, summary.data(), num_values * sizeof(double));
       entries.push_back(Entry(keys[i], std::move(summary)));
     }
diff --git a/tuple/include/array_of_doubles_union.hpp b/tuple/include/array_of_doubles_union.hpp
index a70a015..592c1f9 100644
--- a/tuple/include/array_of_doubles_union.hpp
+++ b/tuple/include/array_of_doubles_union.hpp
@@ -32,7 +32,7 @@
 struct array_of_doubles_union_policy_alloc {
   array_of_doubles_union_policy_alloc(uint8_t num_values = 1): num_values_(num_values) {}
 
-  void operator()(std::vector<double, A>& summary, const std::vector<double, A>& other) const {
+  void operator()(aod<A>& summary, const aod<A>& other) const {
     for (size_t i = 0; i < summary.size(); ++i) {
       summary[i] += other[i];
     }
@@ -48,10 +48,10 @@
 using array_of_doubles_union_policy = array_of_doubles_union_policy_alloc<>;
 
 template<typename Allocator = std::allocator<double>>
-class array_of_doubles_union_alloc: public tuple_union<std::vector<double, Allocator>, array_of_doubles_union_policy_alloc<Allocator>, AllocVectorDouble<Allocator>> {
+class array_of_doubles_union_alloc: public tuple_union<aod<Allocator>, array_of_doubles_union_policy_alloc<Allocator>, AllocAOD<Allocator>> {
 public:
   using Policy = array_of_doubles_union_policy_alloc<Allocator>;
-  using Base = tuple_union<std::vector<double, Allocator>, Policy, AllocVectorDouble<Allocator>>;
+  using Base = tuple_union<aod<Allocator>, Policy, AllocAOD<Allocator>>;
   using CompactSketch = compact_array_of_doubles_sketch_alloc<Allocator>;
   using resize_factor = theta_constants::resize_factor;