Merge "trace_processor: properly handle how to bound filter int and float types"
diff --git a/src/trace_processor/sqlite_utils.h b/src/trace_processor/sqlite_utils.h
index 53d1e19..6ac7325 100644
--- a/src/trace_processor/sqlite_utils.h
+++ b/src/trace_processor/sqlite_utils.h
@@ -17,6 +17,7 @@
 #ifndef SRC_TRACE_PROCESSOR_SQLITE_UTILS_H_
 #define SRC_TRACE_PROCESSOR_SQLITE_UTILS_H_
 
+#include <math.h>
 #include <sqlite3.h>
 
 #include <functional>
@@ -137,6 +138,99 @@
 #endif  // PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
 
 template <typename T>
+using is_float =
+    typename std::enable_if<std::is_floating_point<T>::value, T>::type;
+
+template <typename T>
+using is_int = typename std::enable_if<std::is_integral<T>::value, T>::type;
+
+// Greater bound for floating point numbers.
+template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
+T FindGtBound(bool is_eq, sqlite3_value* sqlite_val) {
+  constexpr auto kMax = static_cast<long double>(std::numeric_limits<T>::max());
+  auto type = sqlite3_value_type(sqlite_val);
+  if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
+    return kMax;
+  }
+
+  // If this is a strict gt bound then just get the next highest float
+  // after value.
+  auto value = ExtractSqliteValue<T>(sqlite_val);
+  return is_eq ? value : nexttoward(value, kMax);
+}
+
+template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
+T FindGtBound(bool is_eq, sqlite3_value* sqlite_val) {
+  auto type = sqlite3_value_type(sqlite_val);
+  if (type == SQLITE_INTEGER) {
+    auto value = ExtractSqliteValue<T>(sqlite_val);
+    return is_eq ? value : value + 1;
+  } else if (type == SQLITE_FLOAT) {
+    auto value = ExtractSqliteValue<double>(sqlite_val);
+    auto above = ceil(value);
+    auto cast = static_cast<T>(above);
+    return value < above ? cast : (is_eq ? cast : cast + 1);
+  } else {
+    return std::numeric_limits<T>::max();
+  }
+}
+
+template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
+T FindLtBound(bool is_eq, sqlite3_value* sqlite_val) {
+  constexpr auto kMin =
+      static_cast<long double>(std::numeric_limits<T>::lowest());
+  auto type = sqlite3_value_type(sqlite_val);
+  if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
+    return kMin;
+  }
+
+  // If this is a strict lt bound then just get the next lowest float
+  // before value.
+  auto value = ExtractSqliteValue<T>(sqlite_val);
+  return is_eq ? value : nexttoward(value, kMin);
+}
+
+template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
+T FindLtBound(bool is_eq, sqlite3_value* sqlite_val) {
+  auto type = sqlite3_value_type(sqlite_val);
+  if (type == SQLITE_INTEGER) {
+    auto value = ExtractSqliteValue<T>(sqlite_val);
+    return is_eq ? value : value - 1;
+  } else if (type == SQLITE_FLOAT) {
+    auto value = ExtractSqliteValue<double>(sqlite_val);
+    auto below = floor(value);
+    auto cast = static_cast<T>(below);
+    return value > below ? cast : (is_eq ? cast : cast - 1);
+  } else {
+    return std::numeric_limits<T>::max();
+  }
+}
+
+template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
+T FindEqBound(sqlite3_value* sqlite_val) {
+  auto type = sqlite3_value_type(sqlite_val);
+  if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
+    return std::numeric_limits<T>::max();
+  }
+  return ExtractSqliteValue<T>(sqlite_val);
+}
+
+template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
+T FindEqBound(sqlite3_value* sqlite_val) {
+  auto type = sqlite3_value_type(sqlite_val);
+  if (type == SQLITE_INTEGER) {
+    return ExtractSqliteValue<T>(sqlite_val);
+  } else if (type == SQLITE_FLOAT) {
+    auto value = ExtractSqliteValue<double>(sqlite_val);
+    auto below = floor(value);
+    auto cast = static_cast<T>(below);
+    return value > below ? std::numeric_limits<T>::max() : cast;
+  } else {
+    return std::numeric_limits<T>::max();
+  }
+}
+
+template <typename T>
 void ReportSqliteResult(sqlite3_context*, T value);
 
 template <>
diff --git a/src/trace_processor/storage_schema.h b/src/trace_processor/storage_schema.h
index ebca90f..739ff92 100644
--- a/src/trace_processor/storage_schema.h
+++ b/src/trace_processor/storage_schema.h
@@ -98,26 +98,24 @@
       if (!is_naturally_ordered_)
         return bounds;
 
-      auto min = std::numeric_limits<T>::min();
-      auto max = std::numeric_limits<T>::max();
-
       // Makes the below code much more readable.
       using namespace sqlite_utils;
 
-      // Try and bound the min and max value based on the constraints.
-      auto value = sqlite_utils::ExtractSqliteValue<T>(sqlite_val);
+      T min = kTMin;
+      T max = kTMax;
       if (IsOpGe(op) || IsOpGt(op)) {
-        min = IsOpGe(op) ? value : value + 1;
+        min = FindGtBound<T>(IsOpGe(op), sqlite_val);
       } else if (IsOpLe(op) || IsOpLt(op)) {
-        max = IsOpLe(op) ? value : value - 1;
+        max = FindLtBound<T>(IsOpLe(op), sqlite_val);
       } else if (IsOpEq(op)) {
-        min = value;
-        max = value;
-      } else {
-        // We cannot bound on this constraint.
-        return bounds;
+        auto val = FindEqBound<T>(sqlite_val);
+        min = val;
+        max = val;
       }
 
+      if (min <= kTMin && max >= kTMax)
+        return bounds;
+
       // Convert the values into indices into the deque.
       auto min_it = std::lower_bound(deque_->begin(), deque_->end(), min);
       bounds.min_idx =
@@ -175,6 +173,9 @@
     }
 
    private:
+    T kTMin = std::numeric_limits<T>::lowest();
+    T kTMax = std::numeric_limits<T>::max();
+
     template <typename C>
     Predicate FilterWithCast(int op, sqlite3_value* value) const {
       auto binary_op = sqlite_utils::GetPredicateForOp<C>(op);