blob: 634feac7526b95b0b0e217ff37ab9e92385d9877 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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 SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_INTERNAL_H_
#define SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_INTERNAL_H_
#include "src/trace_processor/containers/string_pool.h"
#include "src/trace_processor/db/base_id.h"
#include "src/trace_processor/db/column_storage.h"
namespace perfetto {
namespace trace_processor {
namespace tc_internal {
// Serializer converts between the "public" type used by the rest of trace
// processor and the type we store in the ColumnStorage.
template <typename T, typename Enabled = void>
struct Serializer {
using serialized_type = T;
static serialized_type Serialize(T value) { return value; }
static T Deserialize(serialized_type value) { return value; }
static std::optional<serialized_type> Serialize(std::optional<T> value) {
return value;
}
static std::optional<T> Deserialize(std::optional<serialized_type> value) {
return value;
}
};
template <typename T>
using is_id = std::is_base_of<BaseId, T>;
// Specialization of Serializer for id types.
template <typename T>
struct Serializer<T, typename std::enable_if<is_id<T>::value>::type> {
using serialized_type = uint32_t;
static serialized_type Serialize(T value) { return value.value; }
static T Deserialize(serialized_type value) { return T{value}; }
static std::optional<serialized_type> Serialize(std::optional<T> value) {
return value ? std::make_optional(Serialize(*value)) : std::nullopt;
}
static std::optional<T> Deserialize(std::optional<serialized_type> value) {
return value ? std::make_optional(Deserialize(*value)) : std::nullopt;
}
};
// Specialization of Serializer for StringPool types.
template <>
struct Serializer<StringPool::Id> {
using serialized_type = StringPool::Id;
static serialized_type Serialize(StringPool::Id value) { return value; }
static StringPool::Id Deserialize(serialized_type value) { return value; }
static serialized_type Serialize(std::optional<StringPool::Id> value) {
// Since StringPool::Id == 0 is always treated as null, rewrite
// std::nullopt -> 0 to remove an extra check at filter time for
// std::nullopt. Instead, that code can assume that the ColumnStorage
// layer always returns a valid id and can handle the nullability at the
// stringpool level.
// TODO(lalitm): remove this special casing if we migrate all tables over
// to macro tables and find that we can remove support for null stringids
// in the stringpool.
return value ? Serialize(*value) : StringPool::Id::Null();
}
static std::optional<serialized_type> Deserialize(
std::optional<StringPool::Id> value) {
return value;
}
};
// TypeHandler (and it's specializations) allow for specialied handling of
// functions of a TypedColumn based on what is being stored inside.
// Default implementation of TypeHandler.
template <typename T>
struct TypeHandler {
using non_optional_type = T;
using sql_value_type =
typename Serializer<non_optional_type>::serialized_type;
using stored_type = typename Serializer<non_optional_type>::serialized_type;
static constexpr bool is_optional = false;
static constexpr bool is_string = false;
static stored_type Get(const ColumnStorage<stored_type>& nv, uint32_t idx) {
return nv.Get(idx);
}
static bool Equals(T a, T b) {
// We need to use equal_to here as it could be T == double and because we
// enable all compile time warnings, we will get complaints if we just use
// a == b.
return std::equal_to<T>()(a, b);
}
};
// Specialization for Optional types.
template <typename T>
struct TypeHandler<std::optional<T>> {
using non_optional_type = T;
using sql_value_type =
typename Serializer<non_optional_type>::serialized_type;
using stored_type =
std::optional<typename Serializer<non_optional_type>::serialized_type>;
static constexpr bool is_optional = true;
static constexpr bool is_string = false;
static stored_type Get(const ColumnStorage<stored_type>& nv, uint32_t idx) {
return nv.Get(idx);
}
static bool Equals(std::optional<T> a, std::optional<T> b) {
// We need to use equal_to here as it could be T == double and because we
// enable all compile time warnings, we will get complaints if we just use
// a == b. This is the same reason why we can't also just use equal_to using
// a and b directly because the optional implementation of equality uses
// == which again causes complaints.
return a.has_value() == b.has_value() &&
(!a.has_value() || std::equal_to<T>()(*a, *b));
}
};
// Specialization for std::optional<StringId> types.
template <>
struct TypeHandler<StringPool::Id> {
using non_optional_type = StringPool::Id;
using sql_value_type = NullTermStringView;
using stored_type = StringPool::Id;
static constexpr bool is_optional = false;
static constexpr bool is_string = true;
static StringPool::Id Get(const ColumnStorage<stored_type>& nv,
uint32_t idx) {
return nv.Get(idx);
}
static bool Equals(StringPool::Id a, StringPool::Id b) { return a == b; }
};
// Specialization for std::optional<StringId> types.
template <>
struct TypeHandler<std::optional<StringPool::Id>> {
// get_type removes the base::Optional since we convert std::nullopt ->
// StringPool::Id::Null (see Serializer<StringPool> above).
using non_optional_type = StringPool::Id;
using sql_value_type = NullTermStringView;
using stored_type = StringPool::Id;
// is_optional is false again because we always unwrap
// std::optional<StringPool::Id> into StringPool::Id.
static constexpr bool is_optional = false;
static constexpr bool is_string = true;
static std::optional<StringPool::Id> Get(const ColumnStorage<stored_type>& nv,
uint32_t idx) {
StringPool::Id id = nv.Get(idx);
return id.is_null() ? std::nullopt : std::make_optional(id);
}
static bool Equals(std::optional<StringPool::Id> a,
std::optional<StringPool::Id> b) {
// To match our handling of treating std::nullopt ==
// StringPool::Id::Null(), ensure that they both compare equal to each
// other.
return a == b || (!a && b->is_null()) || (!b && a->is_null());
}
};
} // namespace tc_internal
} // namespace trace_processor
} // namespace perfetto
#endif // SRC_TRACE_PROCESSOR_DB_TYPED_COLUMN_INTERNAL_H_