blob: 7346133862db688086e20950413151fe01f8d903 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_STORAGE_VFS_CPP_METRICS_OFFSETS_H_
#define SRC_LIB_STORAGE_VFS_CPP_METRICS_OFFSETS_H_
#include <cstdint>
#include <type_traits>
namespace fs_metrics {
// This library provides the mechanisms for calculating the offsets or positions of an object, given
// their attributes. An object is struct that inhertics from structs providing the Attribtue compile
// time contract.
//
// The benefit comes when dealing with large fixed numbers of objects(e.g. metrics), that are stored
// in a contiguous buffer and there is a need to map a set of attribtues to individual objects.
//
// These objects must provide the following compile-time interface:
//
// OperationInfo::kStart -> Position where the first object is stored.
//
// Note: that for consistency, AttributeList must remain in the same order in all instantiations.
namespace internal {
template <typename OperationInfo>
constexpr uint64_t CalculateRelativeOffset(const typename OperationInfo::AttributeData& attributes,
uint64_t aggregated_offset,
uint64_t accumulated_dimensions) {
return aggregated_offset;
}
// Recursive step, for every attribute in the argument pack, or |AttributeList| calculate and
// aggregatre the respective offsets.
template <typename OperationInfo, typename Attribute, typename... RemainingAttributes>
constexpr uint64_t CalculateRelativeOffset(const typename OperationInfo::AttributeData& attributes,
uint64_t aggregated_offset,
uint64_t accumulated_dimensions) {
if constexpr (std::is_base_of<Attribute, OperationInfo>::value) {
uint64_t offset = Attribute::OffsetOf(attributes.*Attribute::kAttributeValue);
aggregated_offset += offset * accumulated_dimensions;
accumulated_dimensions *= Attribute::kSize;
}
return CalculateRelativeOffset<OperationInfo, RemainingAttributes...>(
attributes, aggregated_offset, accumulated_dimensions);
}
template <typename OperationInfo>
constexpr uint64_t CountInstances(uint64_t accumulated_count) {
return accumulated_count;
}
template <typename OperationInfo, typename Attribute, typename... RemainingAttributes>
constexpr uint64_t CountInstances(uint64_t accumulated_count) {
if constexpr (std::is_base_of<Attribute, OperationInfo>::value) {
accumulated_count *= Attribute::kSize;
}
return CountInstances<OperationInfo, RemainingAttributes...>(accumulated_count);
}
} // namespace internal
// Provides specialiazation based on the parameter pack, keeping it consistent across calls and
// a single point of update for adding and changing attribtues.
// Recommended use is:
// using MyOffsets = fs_metrics::MyOffsets<Attribute_1, Attribute_2, ...>;
template <typename... AttributeList>
struct Offsets {
template <typename OperationInfo>
static constexpr uint64_t RelativeOffset(
const typename OperationInfo::AttributeData& attributes) {
return internal::CalculateRelativeOffset<OperationInfo, AttributeList...>(attributes, 0, 1);
}
template <typename OperationInfo>
static constexpr uint64_t AbsoluteOffset(
const typename OperationInfo::AttributeData& attributes) {
return OperationInfo::kStart + RelativeOffset<OperationInfo>(attributes);
}
// Returns the number of objects that are being tracked for a single OperationInfo. This is how
// many different objects can be mapped to all possible attribute values in AttributeData for a
// specific element.
template <typename OperationInfo>
static constexpr uint64_t Count() {
return internal::CountInstances<OperationInfo, AttributeList...>(1);
}
template <typename OperationInfo>
static constexpr uint64_t Begin() {
return OperationInfo::kStart;
}
template <typename OperationInfo>
static constexpr uint64_t End() {
return OperationInfo::kStart + Count<OperationInfo>();
}
};
} // namespace fs_metrics
#endif // SRC_LIB_STORAGE_VFS_CPP_METRICS_OFFSETS_H_