MINIFICPP-1383 intdiv_ceil: disable negative numbers

MINIFICPP-1383 check that constexpr division by zero doesn't compile

Signed-off-by: Arpad Boda <aboda@apache.org>

This closes #918
diff --git a/libminifi/include/utils/GeneralUtils.h b/libminifi/include/utils/GeneralUtils.h
index 224f455..c132650 100644
--- a/libminifi/include/utils/GeneralUtils.h
+++ b/libminifi/include/utils/GeneralUtils.h
@@ -42,10 +42,11 @@
 #endif /* < C++14 */
 
 template<typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
-T intdiv_ceil(T numerator, T denominator) {
-  gsl_Expects(denominator != 0);
+constexpr T intdiv_ceil(T numerator, T denominator) {
   // note: division and remainder is 1 instruction on x86
-  return numerator / denominator + (numerator % denominator > 0);
+  return gsl_Expects(denominator != 0), ((numerator >= 0) != (denominator > 0)
+      ? numerator / denominator  // negative result rounds towards zero, i.e. up
+      : numerator / denominator + (numerator % denominator != 0));
 }
 
 using gsl::owner;
diff --git a/libminifi/test/unit/GeneralUtilsTest.cpp b/libminifi/test/unit/GeneralUtilsTest.cpp
index f7d12b7..f24b88c 100644
--- a/libminifi/test/unit/GeneralUtilsTest.cpp
+++ b/libminifi/test/unit/GeneralUtilsTest.cpp
@@ -32,18 +32,38 @@
   REQUIRE("test string" == *pstr);
 }
 
-TEST_CASE("GeneralUtils::intdiv_ceil", "[intdiv_ceil]") {
-  REQUIRE(0 == utils::intdiv_ceil(0, 1));
-  REQUIRE(0 == utils::intdiv_ceil(0, 2));
-  REQUIRE(1 == utils::intdiv_ceil(1, 2));
-  REQUIRE(1 == utils::intdiv_ceil(1, 3));
-  REQUIRE(1 == utils::intdiv_ceil(3, 3));
-  REQUIRE(2 == utils::intdiv_ceil(4, 3));
-  REQUIRE(2 == utils::intdiv_ceil(4, 3));
-  REQUIRE(0 == utils::intdiv_ceil(-1, 3));
-  REQUIRE(-1 == utils::intdiv_ceil(-3, 3));
-  REQUIRE(-1 == utils::intdiv_ceil(-4, 3));
-}
+// intdiv_ceil
+static_assert(0 == utils::intdiv_ceil(0, 1), "");
+static_assert(0 == utils::intdiv_ceil(0, 2), "");
+static_assert(1 == utils::intdiv_ceil(1, 2), "");
+static_assert(1 == utils::intdiv_ceil(1, 3), "");
+static_assert(1 == utils::intdiv_ceil(3, 3), "");
+static_assert(2 == utils::intdiv_ceil(4, 3), "");
+static_assert(2 == utils::intdiv_ceil(5, 3), "");
+static_assert(0 == utils::intdiv_ceil(-1, 3), "");
+static_assert(-1 == utils::intdiv_ceil(-3, 3), "");
+static_assert(-1 == utils::intdiv_ceil(-4, 3), "");
+static_assert(2 == utils::intdiv_ceil(-4, -3), "");
+static_assert(2 == utils::intdiv_ceil(-5, -3), "");
+static_assert(0 == utils::intdiv_ceil(1, -3), "");
+static_assert(-1 == utils::intdiv_ceil(5, -3), "");
+static_assert(3 == utils::intdiv_ceil(6, 2), "");
+static_assert(-3 == utils::intdiv_ceil(-6, 2), "");
+static_assert(-3 == utils::intdiv_ceil(6, -2), "");
+static_assert(3 == utils::intdiv_ceil(-6, -2), "");
+static_assert(0 == utils::intdiv_ceil(0, -10), "");
+
+template<int N, int D, typename = void>
+struct does_compile : std::false_type {};
+
+template<int N, int D>
+struct does_compile<N, D,
+    // we must force evaluation so decltype won't do
+    typename std::enable_if<(utils::intdiv_ceil(N, D), true)>::type> : std::true_type {};
+
+static_assert(does_compile<2, 3>::value, "does_compile should work");
+static_assert(!does_compile<1, 0>::value, "constexpr division by zero shouldn't compile");
+
 
 TEST_CASE("GeneralUtils::exchange", "[exchange]") {
   int a = 1;