Merge pull request #195 from apache/allocation_tests

test that allocator default constructor is not called
diff --git a/common/test/test_allocator.hpp b/common/test/test_allocator.hpp
index b383af6..d658e8f 100644
--- a/common/test/test_allocator.hpp
+++ b/common/test/test_allocator.hpp
@@ -22,6 +22,7 @@
 
 #include <new>
 #include <utility>
+#include <stdexcept>
 
 // this allocator keeps the total allocated size in a global variable for testing
 
@@ -43,7 +44,14 @@
   template <class U>
   struct rebind { typedef test_allocator<U> other; };
 
-  test_allocator() {}
+  // this is to test that a given instance of an allocator is used instead of instantiating
+  static const bool DISALLOW_DEFAULT_CONSTRUCTOR = true;
+  test_allocator() {
+    if (DISALLOW_DEFAULT_CONSTRUCTOR) throw std::runtime_error("test_allocator: default constructor");
+  }
+  // call this constructor in tests and pass an allocator instance
+  test_allocator(int) {}
+
   test_allocator(const test_allocator&) {}
   template <class U>
   test_allocator(const test_allocator<U>&) {}
diff --git a/cpc/test/CMakeLists.txt b/cpc/test/CMakeLists.txt
index 00bb4c5..9ffce32 100644
--- a/cpc/test/CMakeLists.txt
+++ b/cpc/test/CMakeLists.txt
@@ -41,4 +41,5 @@
     cpc_sketch_test.cpp
     cpc_union_test.cpp
     compression_test.cpp
+    cpc_sketch_allocation_test.cpp
 )
diff --git a/cpc/test/cpc_sketch_allocation_test.cpp b/cpc/test/cpc_sketch_allocation_test.cpp
new file mode 100644
index 0000000..e52b09c
--- /dev/null
+++ b/cpc/test/cpc_sketch_allocation_test.cpp
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+#include <cstring>
+#include <sstream>
+#include <fstream>
+
+#include <catch.hpp>
+
+#include "cpc_sketch.hpp"
+#include "test_allocator.hpp"
+
+namespace datasketches {
+
+using cpc_sketch_test_alloc = cpc_sketch_alloc<test_allocator<uint8_t>>;
+
+TEST_CASE("cpc sketch allocation: serialize deserialize empty", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
+    sketch.serialize(s);
+    auto deserialized = cpc_sketch_test_alloc::deserialize(s, DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize sparse", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(100);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
+    sketch.serialize(s);
+    auto deserialized = cpc_sketch_test_alloc::deserialize(s, DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize hybrid", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(200);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
+    sketch.serialize(s);
+    auto deserialized = cpc_sketch_test_alloc::deserialize(s, DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize pinned", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(2000);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
+    sketch.serialize(s);
+    auto deserialized = cpc_sketch_test_alloc::deserialize(s, DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize sliding", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(20000);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
+    sketch.serialize(s);
+    auto deserialized = cpc_sketch_test_alloc::deserialize(s, DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serializing deserialize sliding large", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(3000000);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
+    sketch.serialize(s);
+    auto deserialized = cpc_sketch_test_alloc::deserialize(s, DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize empty, bytes", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    auto bytes = sketch.serialize();
+    auto deserialized = cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size(), DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1, DEFAULT_SEED, 0), std::out_of_range);
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize sparse, bytes", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(100);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    auto bytes = sketch.serialize();
+    auto deserialized = cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size(), DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), 7, DEFAULT_SEED, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), 15, DEFAULT_SEED, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1, DEFAULT_SEED, 0), std::out_of_range);
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize hybrid, bytes", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(200);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    auto bytes = sketch.serialize();
+    auto deserialized = cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size(), DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), 7, DEFAULT_SEED, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), 15, DEFAULT_SEED, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1, DEFAULT_SEED, 0), std::out_of_range);
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize pinned, bytes", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(2000);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    auto bytes = sketch.serialize();
+    auto deserialized = cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size(), DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), 7, DEFAULT_SEED, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), 15, DEFAULT_SEED, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1, DEFAULT_SEED, 0), std::out_of_range);
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE("cpc sketch allocation: serialize deserialize sliding, bytes", "[cpc_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    cpc_sketch_test_alloc sketch(11, DEFAULT_SEED, 0);
+    const int n(20000);
+    for (int i = 0; i < n; i++) sketch.update(i);
+    auto bytes = sketch.serialize();
+    auto deserialized = cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size(), DEFAULT_SEED, 0);
+    REQUIRE(deserialized.is_empty() == sketch.is_empty());
+    REQUIRE(deserialized.get_estimate() == sketch.get_estimate());
+    REQUIRE(deserialized.validate());
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), 7, DEFAULT_SEED, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), 15, DEFAULT_SEED, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(cpc_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1, DEFAULT_SEED, 0), std::out_of_range);
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+} /* namespace datasketches */
diff --git a/fi/test/frequent_items_sketch_custom_type_test.cpp b/fi/test/frequent_items_sketch_custom_type_test.cpp
index ec89a76..06d4467 100644
--- a/fi/test/frequent_items_sketch_custom_type_test.cpp
+++ b/fi/test/frequent_items_sketch_custom_type_test.cpp
@@ -22,13 +22,14 @@
 
 #include "frequent_items_sketch.hpp"
 #include "test_type.hpp"
+#include "test_allocator.hpp"
 
 namespace datasketches {
 
-typedef frequent_items_sketch<test_type, float, test_type_hash, test_type_equal, test_type_serde> frequent_test_type_sketch;
+using frequent_test_type_sketch = frequent_items_sketch<test_type, float, test_type_hash, test_type_equal, test_type_serde, test_allocator<test_type>>;
 
 TEST_CASE("frequent items: custom type", "[frequent_items_sketch]") {
-  frequent_test_type_sketch sketch(3);
+  frequent_test_type_sketch sketch(3, frequent_test_type_sketch::LG_MIN_MAP_SIZE, 0);
   sketch.update(1, 10); // should survive the purge
   sketch.update(2);
   sketch.update(3);
@@ -41,35 +42,36 @@
   REQUIRE_FALSE(sketch.is_empty());
   REQUIRE(sketch.get_total_weight() == 17);
   REQUIRE(sketch.get_estimate(1) == 10);
-  //std::cerr << "num active: " << sketch.get_num_active_items() << std::endl;
 
-  //std::cerr << "get frequent items" << std::endl;
   auto items = sketch.get_frequent_items(frequent_items_error_type::NO_FALSE_POSITIVES);
   REQUIRE(items.size() == 1); // only 1 item should be above threshold
   REQUIRE(items[0].get_item().get_value() == 1);
   REQUIRE(items[0].get_estimate() == 10);
 
   std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
-  //std::cerr << "serialize" << std::endl;
   sketch.serialize(s);
-  //std::cerr << "deserialize" << std::endl;
-  auto sketch2 = frequent_test_type_sketch::deserialize(s);
+  auto sketch2 = frequent_test_type_sketch::deserialize(s, 0);
   REQUIRE_FALSE(sketch2.is_empty());
   REQUIRE(sketch2.get_total_weight() == 17);
   REQUIRE(sketch2.get_estimate(1) == 10);
   REQUIRE(sketch.get_num_active_items() == sketch2.get_num_active_items());
   REQUIRE(sketch.get_maximum_error() == sketch2.get_maximum_error());
-  //std::cerr << "end" << std::endl;
 
-  std::cout << sketch2.to_string(true);
+  auto bytes = sketch.serialize();
+  auto sketch3 = frequent_test_type_sketch::deserialize(bytes.data(), bytes.size(), 0);
+  REQUIRE_FALSE(sketch3.is_empty());
+  REQUIRE(sketch3.get_total_weight() == 17);
+  REQUIRE(sketch3.get_estimate(1) == 10);
+  REQUIRE(sketch.get_num_active_items() == sketch3.get_num_active_items());
+  REQUIRE(sketch.get_maximum_error() == sketch3.get_maximum_error());
 }
 
 // this is to see the debug print from test_type if enabled there to make sure items are moved
 TEST_CASE("frequent items: moving merge", "[frequent_items_sketch]") {
-  frequent_test_type_sketch sketch1(3);
+  frequent_test_type_sketch sketch1(3, frequent_test_type_sketch::LG_MIN_MAP_SIZE, 0);
   sketch1.update(1);
 
-  frequent_test_type_sketch sketch2(3);
+  frequent_test_type_sketch sketch2(3, frequent_test_type_sketch::LG_MIN_MAP_SIZE, 0);
   sketch2.update(2);
 
   sketch2.merge(std::move(sketch1));
@@ -77,7 +79,7 @@
 }
 
 TEST_CASE("frequent items: negative weight", "[frequent_items_sketch]") {
-  frequent_test_type_sketch sketch(3);
+  frequent_test_type_sketch sketch(3, frequent_test_type_sketch::LG_MIN_MAP_SIZE, 0);
   REQUIRE_THROWS_AS(sketch.update(1, -1), std::invalid_argument);
 }
 
diff --git a/hll/test/HllSketchTest.cpp b/hll/test/HllSketchTest.cpp
index dae2cab..be86321 100644
--- a/hll/test/HllSketchTest.cpp
+++ b/hll/test/HllSketchTest.cpp
@@ -24,10 +24,10 @@
 
 namespace datasketches {
 
-typedef hll_sketch_alloc<test_allocator<uint8_t>> hll_sketch_test_alloc;
+using hll_sketch_test_alloc = hll_sketch_alloc<test_allocator<uint8_t>>;
 
 static void runCheckCopy(int lgConfigK, target_hll_type tgtHllType) {
-  hll_sketch_test_alloc sk(lgConfigK, tgtHllType);
+  hll_sketch_test_alloc sk(lgConfigK, tgtHllType, false, 0);
 
   for (int i = 0; i < 7; ++i) {
     sk.update(i);
@@ -71,7 +71,7 @@
   int n3 = 1000;
   int base = 0;
 
-  hll_sketch_test_alloc src(lgK, srcType);
+  hll_sketch_test_alloc src(lgK, srcType, false, 0);
   for (int i = 0; i < n1; ++i) {
     src.update(i + base);
   }
@@ -110,7 +110,7 @@
   {
     int lgConfigK = 8;
     target_hll_type srcType = target_hll_type::HLL_8;
-    hll_sketch_test_alloc sk(lgConfigK, srcType);
+    hll_sketch_test_alloc sk(lgConfigK, srcType, false, 0);
 
     for (int i = 0; i < 7; ++i) { sk.update(i); } // LIST
     REQUIRE(sk.get_compact_serialization_bytes() == 36);
@@ -135,7 +135,7 @@
 }
 
 void checkSerializationSizes(const int lgConfigK, target_hll_type tgtHllType) {
-  hll_sketch_test_alloc sk(lgConfigK, tgtHllType);
+  hll_sketch_test_alloc sk(lgConfigK, tgtHllType, false, 0);
   int i;
 
   // LIST
@@ -162,27 +162,23 @@
 }
 
 TEST_CASE("hll sketch: exercise to string", "[hll_sketch]") {
-  test_allocator_total_bytes = 0;
-  {
-    hll_sketch_test_alloc sk(15, HLL_4);
-    for (int i = 0; i < 25; ++i) { sk.update(i); }
-    std::ostringstream oss(std::ios::binary);
-    oss << sk.to_string(false, true, true, true);
-    for (int i = 25; i < (1 << 20); ++i) { sk.update(i); }
-    oss << sk.to_string(false, true, true, true);
-    oss << sk.to_string(false, true, true, false);
+  hll_sketch sk(15, HLL_4);
+  for (int i = 0; i < 25; ++i) { sk.update(i); }
+  std::ostringstream oss(std::ios::binary);
+  oss << sk.to_string(false, true, true, true);
+  for (int i = 25; i < (1 << 20); ++i) { sk.update(i); }
+  oss << sk.to_string(false, true, true, true);
+  oss << sk.to_string(false, true, true, false);
 
-    sk = hll_sketch_test_alloc(8, HLL_8);
-    for (int i = 0; i < 25; ++i) { sk.update(i); }
-    oss << sk.to_string(false, true, true, true);
-  }
-  REQUIRE(test_allocator_total_bytes == 0);
+  sk = hll_sketch(8, HLL_8);
+  for (int i = 0; i < 25; ++i) { sk.update(i); }
+  oss << sk.to_string(false, true, true, true);
 }
 
 // Creates and serializes then deserializes sketch.
 // Returns true if deserialized sketch is compact.
 static bool checkCompact(const int lgK, const int n, const target_hll_type type, bool compact) {
-  hll_sketch_test_alloc sk(lgK, type);
+  hll_sketch_test_alloc sk(lgK, type, false, 0);
   for (int i = 0; i < n; ++i) { sk.update(i); }
   
   std::stringstream ss(std::ios::in | std::ios::out | std::ios::binary);
@@ -194,7 +190,7 @@
     REQUIRE(ss.tellp() == sk.get_updatable_serialization_bytes());
   }
   
-  hll_sketch_test_alloc sk2 = hll_sketch_test_alloc::deserialize(ss);
+  hll_sketch_test_alloc sk2 = hll_sketch_test_alloc::deserialize(ss, 0);
   REQUIRE(sk2.get_estimate() == Approx(n).margin(0.01));
   bool isCompact = sk2.is_compact();
 
@@ -233,11 +229,10 @@
 TEST_CASE("hll sketch: check k limits", "[hll_sketch]") {
   test_allocator_total_bytes = 0;
   {
-    hll_sketch_test_alloc sketch1(HllUtil<>::MIN_LOG_K, target_hll_type::HLL_8);
-    hll_sketch_test_alloc sketch2(HllUtil<>::MAX_LOG_K, target_hll_type::HLL_4);
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc(HllUtil<>::MIN_LOG_K - 1), std::invalid_argument);
-
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc(HllUtil<>::MAX_LOG_K + 1), std::invalid_argument);
+    hll_sketch_test_alloc sketch1(HllUtil<>::MIN_LOG_K, target_hll_type::HLL_8, false, 0);
+    hll_sketch_test_alloc sketch2(HllUtil<>::MAX_LOG_K, target_hll_type::HLL_4, false, 0);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc(HllUtil<>::MIN_LOG_K - 1, target_hll_type::HLL_4, false, 0), std::invalid_argument);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc(HllUtil<>::MAX_LOG_K + 1, target_hll_type::HLL_4, false, 0), std::invalid_argument);
   }
   REQUIRE(test_allocator_total_bytes == 0);
 }
@@ -245,7 +240,7 @@
 TEST_CASE("hll sketch: check input types", "[hll_sketch]") {
   test_allocator_total_bytes = 0;
   {
-    hll_sketch_test_alloc sk(8, target_hll_type::HLL_8);
+    hll_sketch_test_alloc sk(8, target_hll_type::HLL_8, false, 0);
 
     // inserting the same value as a variety of input types
     sk.update((uint8_t) 102);
@@ -271,19 +266,19 @@
     sk.update(str.c_str(), str.length());
     REQUIRE(sk.get_estimate() == Approx(4.0).margin(0.01));
 
-    sk = hll_sketch_test_alloc(8, target_hll_type::HLL_6);
+    sk = hll_sketch_test_alloc(8, target_hll_type::HLL_6, false, 0);
     sk.update((float) 0.0);
     sk.update((float) -0.0);
     sk.update((double) 0.0);
     sk.update((double) -0.0);
     REQUIRE(sk.get_estimate() == Approx(1.0).margin(0.01));
 
-    sk = hll_sketch_test_alloc(8, target_hll_type::HLL_4);
+    sk = hll_sketch_test_alloc(8, target_hll_type::HLL_4, false, 0);
     sk.update(std::nanf("3"));
     sk.update(std::nan("9"));
     REQUIRE(sk.get_estimate() == Approx(1.0).margin(0.01));
 
-    sk = hll_sketch_test_alloc(8, target_hll_type::HLL_4);
+    sk = hll_sketch_test_alloc(8, target_hll_type::HLL_4, false, 0);
     sk.update(nullptr, 0);
     sk.update("");
     REQUIRE(sk.is_empty());
@@ -294,24 +289,24 @@
 TEST_CASE("hll sketch: deserialize list mode buffer overrun", "[hll_sketch]") {
   test_allocator_total_bytes = 0;
   {
-    hll_sketch_test_alloc sketch(10);
+    hll_sketch_test_alloc sketch(10, target_hll_type::HLL_4, false, 0);
     sketch.update(1);
     auto bytes = sketch.serialize_compact();
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 7), std::out_of_range);
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1), std::out_of_range);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 7, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1, 0), std::out_of_range);
 
     // ckeck for leaks on stream exceptions
     {
       std::stringstream ss;
       ss.exceptions(std::ios::failbit | std::ios::badbit);
       ss.str(std::string((char*)bytes.data(), 7));
-      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss), std::ios_base::failure);
+      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss, 0), std::ios_base::failure);
     }
     {
       std::stringstream ss;
       ss.exceptions(std::ios::failbit | std::ios::badbit);
       ss.str(std::string((char*)bytes.data(), bytes.size() - 1));
-      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss), std::ios_base::failure);
+      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss, 0), std::ios_base::failure);
     }
   }
   REQUIRE(test_allocator_total_bytes == 0);
@@ -320,25 +315,25 @@
 TEST_CASE("hll sketch: deserialize set mode buffer overrun", "[hll_sketch]") {
   test_allocator_total_bytes = 0;
   {
-    hll_sketch_test_alloc sketch(10);
+    hll_sketch_test_alloc sketch(10, target_hll_type::HLL_4, false, 0);
     for (int i = 0; i < 10; ++i) sketch.update(i);
     //std::cout << sketch.to_string();
     auto bytes = sketch.serialize_updatable();
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 7), std::out_of_range);
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1), std::out_of_range);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 7, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1, 0), std::out_of_range);
 
     // ckeck for leaks on stream exceptions
     {
       std::stringstream ss;
       ss.exceptions(std::ios::failbit | std::ios::badbit);
       ss.str(std::string((char*)bytes.data(), 7));
-      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss), std::ios_base::failure);
+      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss, 0), std::ios_base::failure);
     }
     {
       std::stringstream ss;
       ss.exceptions(std::ios::failbit | std::ios::badbit);
       ss.str(std::string((char*)bytes.data(), bytes.size() - 1));
-      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss), std::ios_base::failure);
+      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss, 0), std::ios_base::failure);
     }
   }
   REQUIRE(test_allocator_total_bytes == 0);
@@ -348,39 +343,39 @@
   test_allocator_total_bytes = 0;
   {
     // this sketch should have aux table
-    hll_sketch_test_alloc sketch(15);
+    hll_sketch_test_alloc sketch(15, target_hll_type::HLL_4, false, 0);
     for (int i = 0; i < 14444; ++i) sketch.update(i);
     //std::cout << sketch.to_string();
     auto bytes = sketch.serialize_compact();
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 7), std::out_of_range);
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 15), std::out_of_range);
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 16420), std::out_of_range); // before aux table
-    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1), std::out_of_range);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 7, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 15, 0), std::out_of_range);
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), 16420, 0), std::out_of_range); // before aux table
+    REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(bytes.data(), bytes.size() - 1, 0), std::out_of_range);
 
     // ckeck for leaks on stream exceptions
     {
       std::stringstream ss;
       ss.exceptions(std::ios::failbit | std::ios::badbit);
       ss.str(std::string((char*)bytes.data(), 7));
-      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss), std::ios_base::failure);
+      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss, 0), std::ios_base::failure);
     }
     {
       std::stringstream ss;
       ss.exceptions(std::ios::failbit | std::ios::badbit);
       ss.str(std::string((char*)bytes.data(), 15));
-      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss), std::ios_base::failure);
+      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss, 0), std::ios_base::failure);
     }
     {
       std::stringstream ss;
       ss.exceptions(std::ios::failbit | std::ios::badbit);
       ss.str(std::string((char*)bytes.data(), 16420)); // before aux table
-      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss), std::ios_base::failure);
+      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss, 0), std::ios_base::failure);
     }
     {
       std::stringstream ss;
       ss.exceptions(std::ios::failbit | std::ios::badbit);
       ss.str(std::string((char*)bytes.data(), bytes.size() - 1));
-      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss), std::ios_base::failure);
+      REQUIRE_THROWS_AS(hll_sketch_test_alloc::deserialize(ss, 0), std::ios_base::failure);
     }
   }
   REQUIRE(test_allocator_total_bytes == 0);
diff --git a/kll/test/kll_sketch_custom_type_test.cpp b/kll/test/kll_sketch_custom_type_test.cpp
index 3844902..12c491a 100644
--- a/kll/test/kll_sketch_custom_type_test.cpp
+++ b/kll/test/kll_sketch_custom_type_test.cpp
@@ -34,7 +34,7 @@
   test_allocator_total_bytes = 0;
 
   SECTION("compact level zero") {
-    kll_test_type_sketch sketch(8);
+    kll_test_type_sketch sketch(8, 0);
     REQUIRE_THROWS_AS(sketch.get_quantile(0), std::runtime_error);
     REQUIRE_THROWS_AS(sketch.get_min_value(), std::runtime_error);
     REQUIRE_THROWS_AS(sketch.get_max_value(), std::runtime_error);
@@ -59,10 +59,10 @@
   }
 
   SECTION("merge small") {
-    kll_test_type_sketch sketch1(8);
+    kll_test_type_sketch sketch1(8, 0);
     sketch1.update(1);
 
-    kll_test_type_sketch sketch2(8);
+    kll_test_type_sketch sketch2(8, 0);
     sketch2.update(2);
 
     sketch2.merge(sketch1);
@@ -76,7 +76,7 @@
   }
 
   SECTION("merge higher levels") {
-    kll_test_type_sketch sketch1(8);
+    kll_test_type_sketch sketch1(8, 0);
     sketch1.update(1);
     sketch1.update(2);
     sketch1.update(3);
@@ -87,7 +87,7 @@
     sketch1.update(8);
     sketch1.update(9);
 
-    kll_test_type_sketch sketch2(8);
+    kll_test_type_sketch sketch2(8, 0);
     sketch2.update(10);
     sketch2.update(11);
     sketch2.update(12);
@@ -109,7 +109,7 @@
   }
 
   SECTION("serialize deserialize") {
-    kll_test_type_sketch sketch1;
+    kll_test_type_sketch sketch1(200, 0);
 
     const int n = 1000;
     for (int i = 0; i < n; i++) sketch1.update(i);
@@ -117,7 +117,7 @@
     std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
     sketch1.serialize(s);
     REQUIRE((size_t) s.tellp() == sketch1.get_serialized_size_bytes());
-    auto sketch2 = kll_test_type_sketch::deserialize(s);
+    auto sketch2 = kll_test_type_sketch::deserialize(s, 0);
     REQUIRE((size_t) s.tellg() == sketch2.get_serialized_size_bytes());
     REQUIRE(s.tellg() == s.tellp());
     REQUIRE(sketch2.is_empty() == sketch1.is_empty());
@@ -135,9 +135,9 @@
   }
 
   SECTION("moving merge") {
-    kll_test_type_sketch sketch1(8);
+    kll_test_type_sketch sketch1(8, 0);
     for (int i = 0; i < 10; i++) sketch1.update(i);
-    kll_test_type_sketch sketch2(8);
+    kll_test_type_sketch sketch2(8, 0);
     sketch2.update(10);
     sketch2.merge(std::move(sketch1));
     REQUIRE(sketch2.get_min_value().get_value() == 0);
diff --git a/kll/test/kll_sketch_test.cpp b/kll/test/kll_sketch_test.cpp
index 08e9abe..13f7673 100644
--- a/kll/test/kll_sketch_test.cpp
+++ b/kll/test/kll_sketch_test.cpp
@@ -48,14 +48,14 @@
   test_allocator_total_bytes = 0;
 
   SECTION("k limits") {
-    kll_float_sketch sketch1(kll_float_sketch::MIN_K); // this should work
-    kll_float_sketch sketch2(kll_float_sketch::MAX_K); // this should work
-    REQUIRE_THROWS_AS(new kll_float_sketch(kll_float_sketch::MIN_K - 1), std::invalid_argument);
+    kll_float_sketch sketch1(kll_float_sketch::MIN_K, 0); // this should work
+    kll_float_sketch sketch2(kll_float_sketch::MAX_K, 0); // this should work
+    REQUIRE_THROWS_AS(new kll_float_sketch(kll_float_sketch::MIN_K - 1, 0), std::invalid_argument);
     // MAX_K + 1 makes no sense because k is uint16_t
   }
 
   SECTION("empty") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     REQUIRE(sketch.is_empty());
     REQUIRE_FALSE(sketch.is_estimation_mode());
     REQUIRE(sketch.get_n() == 0);
@@ -79,13 +79,13 @@
 }
 
   SECTION("get bad quantile") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     sketch.update(0); // has to be non-empty to reach the check
     REQUIRE_THROWS_AS(sketch.get_quantile(-1), std::invalid_argument);
   }
 
   SECTION("one item") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     sketch.update(1);
     REQUIRE_FALSE(sketch.is_empty());
     REQUIRE_FALSE(sketch.is_estimation_mode());
@@ -112,7 +112,7 @@
   }
 
   SECTION("NaN") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     sketch.update(std::numeric_limits<float>::quiet_NaN());
     REQUIRE(sketch.is_empty());
 
@@ -122,7 +122,7 @@
   }
 
   SECTION("many items, exact mode") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     const uint32_t n(200);
     for (uint32_t i = 0; i < n; i++) {
       sketch.update(i);
@@ -157,7 +157,7 @@
   }
 
   SECTION("10 items") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     sketch.update(1);
     sketch.update(2);
     sketch.update(3);
@@ -175,7 +175,7 @@
   }
 
   SECTION("100 items") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     for (int i = 0; i < 100; ++i) sketch.update(i);
     REQUIRE(sketch.get_quantile(0) == 0);
     REQUIRE(sketch.get_quantile(0.01) == 1);
@@ -185,7 +185,7 @@
   }
 
   SECTION("many items, estimation mode") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     const int n(1000000);
     for (int i = 0; i < n; i++) {
       sketch.update(i);
@@ -227,7 +227,7 @@
   }
 
   SECTION("consistency between get_rank adn get_PMF/CDF") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     const int n = 1000;
     float values[n];
     for (int i = 0; i < n; i++) {
@@ -256,7 +256,7 @@
     std::ifstream is;
     is.exceptions(std::ios::failbit | std::ios::badbit);
     is.open(testBinaryInputPath + "kll_sketch_from_java.sk", std::ios::binary);
-    auto sketch = kll_float_sketch::deserialize(is);
+    auto sketch = kll_float_sketch::deserialize(is, 0);
     REQUIRE_FALSE(sketch.is_empty());
     REQUIRE(sketch.is_estimation_mode());
     REQUIRE(sketch.get_n() == 1000000);
@@ -266,11 +266,11 @@
   }
 
   SECTION("stream serialize deserialize empty") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
     sketch.serialize(s);
     REQUIRE(static_cast<size_t>(s.tellp()) == sketch.get_serialized_size_bytes());
-    auto sketch2 = kll_float_sketch::deserialize(s);
+    auto sketch2 = kll_float_sketch::deserialize(s, 0);
     REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
     REQUIRE(sketch2.is_empty() == sketch.is_empty());
     REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
@@ -283,9 +283,9 @@
   }
 
   SECTION("bytes serialize deserialize empty") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     auto bytes = sketch.serialize();
-    auto sketch2 = kll_float_sketch::deserialize(bytes.data(), bytes.size());
+    auto sketch2 = kll_float_sketch::deserialize(bytes.data(), bytes.size(), 0);
     REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
     REQUIRE(sketch2.is_empty() == sketch.is_empty());
     REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
@@ -298,12 +298,12 @@
   }
 
   SECTION("serialize deserialize one item") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     sketch.update(1);
     std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
     sketch.serialize(s);
     REQUIRE(static_cast<size_t>(s.tellp()) == sketch.get_serialized_size_bytes());
-    auto sketch2 = kll_float_sketch::deserialize(s);
+    auto sketch2 = kll_float_sketch::deserialize(s, 0);
     REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
     REQUIRE(s.tellg() == s.tellp());
     REQUIRE_FALSE(sketch2.is_empty());
@@ -321,7 +321,7 @@
     std::ifstream is;
     is.exceptions(std::ios::failbit | std::ios::badbit);
     is.open(testBinaryInputPath + "kll_sketch_float_one_item_v1.sk", std::ios::binary);
-    auto sketch = kll_float_sketch::deserialize(is);
+    auto sketch = kll_float_sketch::deserialize(is, 0);
     REQUIRE_FALSE(sketch.is_empty());
     REQUIRE_FALSE(sketch.is_estimation_mode());
     REQUIRE(sketch.get_n() == 1);
@@ -331,13 +331,13 @@
   }
 
   SECTION("stream serialize deserialize many floats") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     const int n(1000);
     for (int i = 0; i < n; i++) sketch.update(i);
     std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
     sketch.serialize(s);
     REQUIRE(static_cast<size_t>(s.tellp()) == sketch.get_serialized_size_bytes());
-    auto sketch2 = kll_float_sketch::deserialize(s);
+    auto sketch2 = kll_float_sketch::deserialize(s, 0);
     REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
     REQUIRE(s.tellg() == s.tellp());
     REQUIRE(sketch2.is_empty() == sketch.is_empty());
@@ -354,12 +354,12 @@
   }
 
   SECTION("bytes serialize deserialize many floats") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     const int n(1000);
     for (int i = 0; i < n; i++) sketch.update(i);
     auto bytes = sketch.serialize();
     REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
-    auto sketch2 = kll_float_sketch::deserialize(bytes.data(), bytes.size());
+    auto sketch2 = kll_float_sketch::deserialize(bytes.data(), bytes.size(), 0);
     REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
     REQUIRE(sketch2.is_empty() == sketch.is_empty());
     REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
@@ -414,7 +414,7 @@
   }
 
   SECTION("out of order split points, float") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     sketch.update(0); // has too be non-empty to reach the check
     float split_points[2] = {1, 0};
     REQUIRE_THROWS_AS(sketch.get_CDF(split_points, 2), std::invalid_argument);
@@ -428,15 +428,15 @@
   }
 
   SECTION("NaN split point") {
-    kll_float_sketch sketch;
+    kll_float_sketch sketch(200, 0);
     sketch.update(0); // has too be non-empty to reach the check
     float split_points[1] = {std::numeric_limits<float>::quiet_NaN()};
     REQUIRE_THROWS_AS(sketch.get_CDF(split_points, 1), std::invalid_argument);
   }
 
   SECTION("merge") {
-    kll_float_sketch sketch1;
-    kll_float_sketch sketch2;
+    kll_float_sketch sketch1(200, 0);
+    kll_float_sketch sketch2(200, 0);
     const int n = 10000;
     for (int i = 0; i < n; i++) {
       sketch1.update(i);
@@ -458,8 +458,8 @@
   }
 
   SECTION("merge lower k") {
-    kll_float_sketch sketch1(256);
-    kll_float_sketch sketch2(128);
+    kll_float_sketch sketch1(256, 0);
+    kll_float_sketch sketch2(128, 0);
     const int n = 10000;
     for (int i = 0; i < n; i++) {
       sketch1.update(i);
@@ -488,8 +488,8 @@
   }
 
   SECTION("merge exact mode, lower k") {
-    kll_float_sketch sketch1(256);
-    kll_float_sketch sketch2(128);
+    kll_float_sketch sketch1(256, 0);
+    kll_float_sketch sketch2(128, 0);
     const int n = 10000;
     for (int i = 0; i < n; i++) {
       sketch1.update(i);
@@ -513,8 +513,8 @@
   }
 
   SECTION("merge min value from other") {
-    kll_float_sketch sketch1;
-    kll_float_sketch sketch2;
+    kll_float_sketch sketch1(200, 0);
+    kll_float_sketch sketch2(200, 0);
     sketch1.update(1);
     sketch2.update(2);
     sketch2.merge(sketch1);
@@ -523,9 +523,9 @@
   }
 
   SECTION("merge min and max values from other") {
-    kll_float_sketch sketch1;
+    kll_float_sketch sketch1(200, 0);
     for (int i = 0; i < 1000000; i++) sketch1.update(i);
-    kll_float_sketch sketch2;
+    kll_float_sketch sketch2(200, 0);
     sketch2.merge(sketch1);
     REQUIRE(sketch2.get_min_value() == 0.0f);
     REQUIRE(sketch2.get_max_value() == 999999.0f);
@@ -560,7 +560,7 @@
   }
 
   SECTION("sketch of strings stream") {
-    kll_string_sketch sketch1;
+    kll_string_sketch sketch1(200, 0);
     REQUIRE_THROWS_AS(sketch1.get_quantile(0), std::runtime_error);
     REQUIRE_THROWS_AS(sketch1.get_min_value(), std::runtime_error);
     REQUIRE_THROWS_AS(sketch1.get_max_value(), std::runtime_error);
@@ -575,7 +575,7 @@
     std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
     sketch1.serialize(s);
     REQUIRE(static_cast<size_t>(s.tellp()) == sketch1.get_serialized_size_bytes());
-    auto sketch2 = kll_string_sketch::deserialize(s);
+    auto sketch2 = kll_string_sketch::deserialize(s, 0);
     REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
     REQUIRE(s.tellg() == s.tellp());
     REQUIRE(sketch2.is_empty() == sketch1.is_empty());
@@ -599,7 +599,7 @@
   }
 
   SECTION("sketch of strings bytes") {
-    kll_string_sketch sketch1;
+    kll_string_sketch sketch1(200, 0);
     REQUIRE_THROWS_AS(sketch1.get_quantile(0), std::runtime_error);
     REQUIRE_THROWS_AS(sketch1.get_min_value(), std::runtime_error);
     REQUIRE_THROWS_AS(sketch1.get_max_value(), std::runtime_error);
@@ -613,7 +613,7 @@
 
     auto bytes = sketch1.serialize();
     REQUIRE(bytes.size() == sketch1.get_serialized_size_bytes());
-    auto sketch2 = kll_string_sketch::deserialize(bytes.data(), bytes.size());
+    auto sketch2 = kll_string_sketch::deserialize(bytes.data(), bytes.size(), 0);
     REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
     REQUIRE(sketch2.is_empty() == sketch1.is_empty());
     REQUIRE(sketch2.is_estimation_mode() == sketch1.is_estimation_mode());
@@ -630,11 +630,11 @@
 
 
   SECTION("sketch of strings, single item, bytes") {
-    kll_string_sketch sketch1;
+    kll_string_sketch sketch1(200, 0);
     sketch1.update("a");
     auto bytes = sketch1.serialize();
     REQUIRE(bytes.size() == sketch1.get_serialized_size_bytes());
-    auto sketch2 = kll_string_sketch::deserialize(bytes.data(), bytes.size());
+    auto sketch2 = kll_string_sketch::deserialize(bytes.data(), bytes.size(), 0);
     REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
   }
 
diff --git a/req/test/req_sketch_custom_type_test.cpp b/req/test/req_sketch_custom_type_test.cpp
index 1d76c3c..05acfff 100644
--- a/req/test/req_sketch_custom_type_test.cpp
+++ b/req/test/req_sketch_custom_type_test.cpp
@@ -34,7 +34,7 @@
   test_allocator_total_bytes = 0;
 
   SECTION("compact level zero") {
-    req_test_type_sketch sketch(4);
+    req_test_type_sketch sketch(4, true, 0);
     REQUIRE_THROWS_AS(sketch.get_quantile(0), std::runtime_error);
     REQUIRE_THROWS_AS(sketch.get_min_value(), std::runtime_error);
     REQUIRE_THROWS_AS(sketch.get_max_value(), std::runtime_error);
@@ -50,10 +50,10 @@
   }
 
   SECTION("merge small") {
-    req_test_type_sketch sketch1(4);
+    req_test_type_sketch sketch1(4, true, 0);
     sketch1.update(1);
 
-    req_test_type_sketch sketch2(4);
+    req_test_type_sketch sketch2(4, true, 0);
     sketch2.update(2);
 
     sketch2.merge(sketch1);
@@ -67,10 +67,10 @@
   }
 
   SECTION("merge higher levels") {
-    req_test_type_sketch sketch1(4);
+    req_test_type_sketch sketch1(4, true, 0);
     for (int i = 0; i < 24; ++i) sketch1.update(i);
 
-    req_test_type_sketch sketch2(4);
+    req_test_type_sketch sketch2(4, true, 0);
     for (int i = 0; i < 24; ++i) sketch2.update(i);
 
     sketch2.merge(sketch1);
@@ -84,7 +84,7 @@
   }
 
   SECTION("serialize deserialize") {
-    req_test_type_sketch sketch1(12);
+    req_test_type_sketch sketch1(12, true, 0);
 
     const int n = 1000;
     for (int i = 0; i < n; i++) sketch1.update(i);
@@ -92,7 +92,7 @@
     std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
     sketch1.serialize(s);
     REQUIRE((size_t) s.tellp() == sketch1.get_serialized_size_bytes());
-    auto sketch2 = req_test_type_sketch::deserialize(s);
+    auto sketch2 = req_test_type_sketch::deserialize(s, 0);
     REQUIRE((size_t) s.tellg() == sketch2.get_serialized_size_bytes());
     REQUIRE(s.tellg() == s.tellp());
     REQUIRE(sketch2.is_empty() == sketch1.is_empty());
@@ -108,9 +108,9 @@
   }
 
   SECTION("moving merge") {
-    req_test_type_sketch sketch1(4);
+    req_test_type_sketch sketch1(4, true, 0);
     for (int i = 0; i < 10; i++) sketch1.update(i);
-    req_test_type_sketch sketch2(4);
+    req_test_type_sketch sketch2(4, true, 0);
     sketch2.update(10);
     sketch2.merge(std::move(sketch1));
     REQUIRE(sketch2.get_min_value().get_value() == 0);
diff --git a/sampling/test/CMakeLists.txt b/sampling/test/CMakeLists.txt
index da0939c..c6c7d83 100644
--- a/sampling/test/CMakeLists.txt
+++ b/sampling/test/CMakeLists.txt
@@ -40,4 +40,5 @@
   PRIVATE
   var_opt_sketch_test.cpp
   var_opt_union_test.cpp
+  var_opt_allocation_test.cpp
 )
diff --git a/sampling/test/var_opt_allocation_test.cpp b/sampling/test/var_opt_allocation_test.cpp
new file mode 100644
index 0000000..ca607b5
--- /dev/null
+++ b/sampling/test/var_opt_allocation_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <var_opt_sketch.hpp>
+#include <var_opt_union.hpp>
+#include <test_type.hpp>
+#include <test_allocator.hpp>
+
+#include <catch.hpp>
+
+#include <sstream>
+
+namespace datasketches {
+
+using var_opt_test_sketch = var_opt_sketch<test_type, test_type_serde, test_allocator<test_type>>;
+using var_opt_test_union = var_opt_union<test_type, test_type_serde, test_allocator<test_type>>;
+
+TEST_CASE("varopt allocation test", "[var_opt_sketch]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    var_opt_test_sketch sk1(10, var_opt_test_sketch::DEFAULT_RESIZE_FACTOR, 0);
+    for (int i = 0; i < 100; ++i) sk1.update(i);
+    auto bytes1 = sk1.serialize();
+    auto sk2 = var_opt_test_sketch::deserialize(bytes1.data(), bytes1.size(), 0);
+
+    std::stringstream ss;
+    sk1.serialize(ss);
+    auto sk3 = var_opt_test_sketch::deserialize(ss, 0);
+
+    var_opt_test_union u1(10, 0);
+    u1.update(sk1);
+    u1.update(sk2);
+    u1.update(sk3);
+
+    auto bytes2 = u1.serialize();
+    auto u2 = var_opt_test_union::deserialize(bytes2.data(), bytes2.size(), 0);
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+TEST_CASE( "varopt union: move", "[var_opt_union][test_type]") {
+  test_allocator_total_bytes = 0;
+  test_allocator_net_allocations = 0;
+  {
+    uint32_t n = 20;
+    uint32_t k = 5;
+    var_opt_test_union u(k, 0);
+    var_opt_test_sketch sk1(k, var_opt_test_sketch::DEFAULT_RESIZE_FACTOR, 0);
+    var_opt_test_sketch sk2(k, var_opt_test_sketch::DEFAULT_RESIZE_FACTOR, 0);
+
+    // move udpates
+    for (int i = 0; i < (int) n; ++i) {
+      sk1.update(i);
+      sk2.update(-i);
+    }
+    REQUIRE(sk1.get_n() == n);
+    REQUIRE(sk2.get_n() == n);
+
+    // move unions
+    u.update(std::move(sk2));
+    u.update(std::move(sk1));
+    REQUIRE(u.get_result().get_n() == 2 * n);
+
+    // move constructor
+    var_opt_test_union u2(std::move(u));
+    REQUIRE(u2.get_result().get_n() == 2 * n);
+
+    // move assignment
+    var_opt_test_union u3(k, 0);
+    u3 = std::move(u2);
+    REQUIRE(u3.get_result().get_n() == 2 * n);
+  }
+  REQUIRE(test_allocator_total_bytes == 0);
+  REQUIRE(test_allocator_net_allocations == 0);
+}
+
+}
diff --git a/sampling/test/var_opt_union_test.cpp b/sampling/test/var_opt_union_test.cpp
index 0275901..e3343d9 100644
--- a/sampling/test/var_opt_union_test.cpp
+++ b/sampling/test/var_opt_union_test.cpp
@@ -18,7 +18,6 @@
  */
 
 #include <var_opt_union.hpp>
-#include "test_type.hpp"
 
 #include <catch.hpp>
 
@@ -325,34 +324,4 @@
   REQUIRE(result.get_k() < 128);
 }
 
-TEST_CASE( "varopt union: move", "[var_opt_union][test_type]") {
-  uint32_t n = 20;
-  uint32_t k = 5;
-  var_opt_union<test_type> u(k);
-  var_opt_sketch<test_type> sk1(k);
-  var_opt_sketch<test_type> sk2(k);
-
-  // move udpates
-  for (int i = 0; i < (int) n; ++i) {
-    sk1.update(i);
-    sk2.update(-i);
-  }
-  REQUIRE(sk1.get_n() == n);
-  REQUIRE(sk2.get_n() == n);
-
-  // move unions
-  u.update(std::move(sk2));
-  u.update(std::move(sk1));
-  REQUIRE(u.get_result().get_n() == 2 * n);
-
-  // move constructor
-  var_opt_union<test_type> u2(std::move(u));
-  REQUIRE(u2.get_result().get_n() == 2 * n);
-
-  // move assignment
-  var_opt_union<test_type> u3(k);
-  u3 = std::move(u2);
-  REQUIRE(u3.get_result().get_n() == 2 * n);
-}
-
 }
diff --git a/tuple/test/CMakeLists.txt b/tuple/test/CMakeLists.txt
index 8f04c5b..af01c34 100644
--- a/tuple/test/CMakeLists.txt
+++ b/tuple/test/CMakeLists.txt
@@ -39,7 +39,7 @@
 target_sources(tuple_test
   PRIVATE
     tuple_sketch_test.cpp
-#    tuple_sketch_allocation_test.cpp
+    tuple_sketch_allocation_test.cpp
     tuple_union_test.cpp
     tuple_intersection_test.cpp
     tuple_a_not_b_test.cpp