123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- /*************************************************************************
- *
- * Copyright 2021 Realm Inc.
- *
- * Licensed 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.
- *
- **************************************************************************/
- #ifndef REALM_AGGREGATE_OPS_HPP
- #define REALM_AGGREGATE_OPS_HPP
- #include <realm/column_type_traits.hpp>
- #include <realm/mixed.hpp>
- #include <algorithm>
- namespace realm::aggregate_operations {
- template <class T>
- inline bool valid_for_agg(T)
- {
- return true;
- }
- template <class T>
- inline bool valid_for_agg(util::Optional<T> val)
- {
- return !!val;
- }
- template <>
- inline bool valid_for_agg(Timestamp val)
- {
- return !val.is_null();
- }
- inline bool valid_for_agg(StringData val)
- {
- return !val.is_null();
- }
- inline bool valid_for_agg(BinaryData val)
- {
- return !val.is_null();
- }
- template <>
- inline bool valid_for_agg(float val)
- {
- return !null::is_null_float(val) && !std::isnan(val);
- }
- template <>
- inline bool valid_for_agg(double val)
- {
- return !null::is_null_float(val) && !std::isnan(val);
- }
- template <>
- inline bool valid_for_agg(Decimal128 val)
- {
- return !val.is_null() && !val.is_nan();
- }
- template <>
- inline bool valid_for_agg(Mixed val)
- {
- return !val.is_null() && (val.get_type() != type_Decimal || !val.get_decimal().is_nan());
- }
- template <typename T, typename Compare>
- class MinMaxAggregateOperator {
- public:
- bool accumulate(T value)
- {
- if (valid_for_agg(value) && (!m_result || Compare()(value, *m_result))) {
- m_result = value;
- return true;
- }
- return false;
- }
- bool accumulate(util::Optional<T> value)
- {
- if (value) {
- return accumulate(*value);
- }
- return false;
- }
- template <typename Type = T>
- std::enable_if_t<!std::is_same_v<Type, Mixed>, bool> accumulate(const Mixed& value)
- {
- if (!value.is_null()) {
- return accumulate(value.get<T>());
- }
- return false;
- }
- bool is_null() const
- {
- return !m_result;
- }
- T result() const
- {
- REALM_ASSERT(m_result);
- return *m_result;
- }
- private:
- util::Optional<T> m_result;
- };
- template <typename T>
- class Minimum : public MinMaxAggregateOperator<T, std::less<>> {
- public:
- static const char* description()
- {
- return "@min";
- }
- };
- template <typename T>
- class Maximum : public MinMaxAggregateOperator<T, std::greater<>> {
- public:
- static const char* description()
- {
- return "@max";
- }
- };
- template <typename T>
- class Sum {
- public:
- using ResultType = typename realm::ColumnSumType<T>;
- bool accumulate(T value)
- {
- if constexpr (std::is_same_v<T, Mixed>) {
- if (value.accumulate_numeric_to(m_result)) {
- ++m_count;
- return true;
- }
- }
- else {
- if (valid_for_agg(value)) {
- m_result += value;
- ++m_count;
- return true;
- }
- }
- return false;
- }
- bool accumulate(const util::Optional<T>& value)
- {
- if (value) {
- return accumulate(*value);
- }
- return false;
- }
- template <typename Type = T>
- std::enable_if_t<!std::is_same_v<Type, Mixed>, bool> accumulate(const Mixed& value)
- {
- if (!value.is_null()) {
- return accumulate(value.get<Type>());
- }
- return false;
- }
- bool is_null() const
- {
- return false;
- }
- ResultType result() const
- {
- return m_result;
- }
- size_t items_counted() const
- {
- return m_count;
- }
- static const char* description()
- {
- return "@sum";
- }
- private:
- ResultType m_result = {};
- size_t m_count = 0;
- };
- template <typename T>
- class Average {
- public:
- using ResultType = typename std::conditional<realm::is_any_v<T, Decimal128, Mixed>, Decimal128, double>::type;
- bool accumulate(T value)
- {
- if constexpr (std::is_same_v<T, Mixed>) {
- if (value.accumulate_numeric_to(m_result)) {
- m_count++;
- return true;
- }
- }
- else {
- if (valid_for_agg(value)) {
- m_count++;
- m_result += value;
- return true;
- }
- }
- return false;
- }
- bool accumulate(const util::Optional<T>& value)
- {
- if (value) {
- return accumulate(*value);
- }
- return false;
- }
- template <typename Type = T>
- std::enable_if_t<!std::is_same_v<Type, Mixed>, bool> accumulate(const Mixed& value)
- {
- if (!value.is_null()) {
- return accumulate(value.get<Type>());
- }
- return false;
- }
- bool is_null() const
- {
- return m_count == 0;
- }
- ResultType result() const
- {
- REALM_ASSERT_EX(m_count > 0, m_count);
- return m_result / m_count;
- }
- static const char* description()
- {
- return "@avg";
- }
- size_t items_counted() const
- {
- return m_count;
- }
- private:
- size_t m_count = 0;
- ResultType m_result = {};
- };
- } // namespace realm::aggregate_operations
- #endif // REALM_AGGREGATE_OPS_HPP
|