| // 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_INSPECT_DEPRECATED_HIERARCHY_H_ |
| #define SRC_LIB_INSPECT_DEPRECATED_HIERARCHY_H_ |
| |
| #include <fuchsia/inspect/deprecated/cpp/fidl.h> |
| #include <lib/fit/optional.h> |
| #include <lib/fit/variant.h> |
| |
| #include <limits> |
| #include <string> |
| #include <vector> |
| |
| namespace inspect_deprecated { |
| |
| // Namespace hierarchy contains classes representing the parts of a parsed |
| // ObjectHierarchy. |
| namespace hierarchy { |
| |
| // Describes how an array of values should be displayed. |
| enum class ArrayDisplayFormat { |
| // The array should be displayed as a flat list of numeric types. |
| FLAT, |
| |
| // The array consists of parameters and buckets for a linear histogram. |
| LINEAR_HISTOGRAM, |
| |
| // The array consists of parameters and buckets for an exponential |
| // histogram. |
| EXPONENTIAL_HISTOGRAM, |
| }; |
| |
| namespace internal { |
| template <typename T, size_t FormatIndex> |
| // Internal class wrapping a typed value. |
| class Value { |
| public: |
| // Index into the format enum for this type. |
| constexpr static size_t format_index = FormatIndex; |
| |
| // Construct an empty value. |
| Value() {} |
| |
| // Construct a Value wrapping the specific value. |
| explicit Value(T value) : value_(std::move(value)) {} |
| |
| // Obtain the wrapped value. |
| const T& value() const { return value_; } |
| |
| private: |
| T value_; |
| }; |
| |
| // An Array is a specialization of Value that contains multiple values as well |
| // as a display format. |
| template <typename T, size_t FormatIndex> |
| class Array : public Value<std::vector<T>, FormatIndex> { |
| public: |
| // Describes a single bucket in a histogram. |
| // |
| // This contains the count of values falling in interval [floor, upper_limit). |
| struct HistogramBucket { |
| // The floor of values falling in this bucket, inclusive. |
| T floor; |
| |
| // The upper limit for values falling in this bucket, exclusive. |
| T upper_limit; |
| |
| // The count of values falling in [floor, upper_limit). |
| T count; |
| |
| HistogramBucket(T floor, T upper_limit, T count) |
| : floor(floor), upper_limit(upper_limit), count(count) {} |
| }; |
| |
| // Constructs an array consisting of values and a display format. |
| Array(std::vector<T> values, ArrayDisplayFormat display_format) |
| : Value<std::vector<T>, FormatIndex>(std::move(values)), display_format_(display_format) {} |
| |
| // Gets the display format for this array. |
| ArrayDisplayFormat GetDisplayFormat() const { return display_format_; } |
| |
| // Gets the buckets for this array interpreted as a histogram. |
| // If the array does not represent a valid histogram, the returned array will |
| // be empty. |
| std::vector<HistogramBucket> GetBuckets() const; |
| |
| private: |
| // The display format for this array. |
| ArrayDisplayFormat display_format_; |
| }; |
| |
| template <typename T, size_t FormatIndex> |
| std::vector<typename Array<T, FormatIndex>::HistogramBucket> Array<T, FormatIndex>::GetBuckets() |
| const { |
| std::vector<HistogramBucket> ret; |
| |
| const auto& value = this->value(); |
| |
| if (display_format_ == ArrayDisplayFormat::LINEAR_HISTOGRAM) { |
| if (value.size() < 5) { |
| // We need at least floor, step_size, underflow, bucket 0, overflow. |
| return ret; |
| } |
| T floor = value[0]; |
| const T step_size = value[1]; |
| |
| if (std::numeric_limits<T>::has_infinity) { |
| ret.push_back(HistogramBucket(-std::numeric_limits<T>::infinity(), floor, value[2])); |
| } else { |
| ret.push_back(HistogramBucket(std::numeric_limits<T>::min(), floor, value[2])); |
| } |
| |
| for (size_t i = 3; i < value.size() - 1; i++) { |
| ret.push_back(HistogramBucket(floor, floor + step_size, value[i])); |
| floor += step_size; |
| } |
| |
| if (std::numeric_limits<T>::has_infinity) { |
| ret.push_back( |
| HistogramBucket(floor, std::numeric_limits<T>::infinity(), value[value.size() - 1])); |
| } else { |
| ret.push_back(HistogramBucket(floor, std::numeric_limits<T>::max(), value[value.size() - 1])); |
| } |
| |
| } else if (display_format_ == ArrayDisplayFormat::EXPONENTIAL_HISTOGRAM) { |
| if (value.size() < 6) { |
| // We need at least floor, initial_step, step_multiplier, underflow, |
| // bucket 0, overflow. |
| return ret; |
| } |
| T floor = value[0]; |
| T current_step = value[1]; |
| const T step_multiplier = value[2]; |
| |
| if (std::numeric_limits<T>::has_infinity) { |
| ret.push_back(HistogramBucket(-std::numeric_limits<T>::infinity(), floor, value[3])); |
| } else { |
| ret.push_back(HistogramBucket(std::numeric_limits<T>::min(), floor, value[3])); |
| } |
| |
| T current_floor = floor; |
| T offset = current_step; |
| for (size_t i = 4; i < value.size() - 1; i++) { |
| T upper = floor + offset; |
| ret.push_back(HistogramBucket(current_floor, upper, value[i])); |
| offset *= step_multiplier; |
| current_floor = upper; |
| } |
| |
| if (std::numeric_limits<T>::has_infinity) { |
| ret.push_back(HistogramBucket(current_floor, std::numeric_limits<T>::infinity(), |
| value[value.size() - 1])); |
| } else { |
| ret.push_back( |
| HistogramBucket(current_floor, std::numeric_limits<T>::max(), value[value.size() - 1])); |
| } |
| } |
| |
| return ret; |
| } |
| |
| // Internal class associating a name with one of several types of value. |
| template <typename TypeVariant, typename FormatType> |
| class NamedValue { |
| public: |
| // Constructs a NamedValue associating the given name with the value. |
| template <typename T> |
| NamedValue(std::string name, T value) : name_(std::move(name)) { |
| format_ = static_cast<FormatType>(T::format_index); |
| value_.template emplace<T::format_index>(std::move(value)); |
| } |
| |
| // Checks if this NamedValue contains the templated type. |
| template <typename T> |
| bool Contains() const { |
| return value_.index() == T::format_index; |
| } |
| |
| // Gets the value by type. If this NamedValue does not contain the given type, |
| // this method panics. |
| template <typename T> |
| const T& Get() const { |
| return value_.template get<T::format_index>(); |
| } |
| |
| // Gets the name of this NamedValue. |
| const std::string& name() const { return name_; } |
| |
| // Gets the format of the wrapped value. |
| FormatType format() const { return format_; } |
| |
| private: |
| FormatType format_; |
| std::string name_; |
| TypeVariant value_; |
| }; |
| |
| } // namespace internal |
| |
| // Describes the format of a parsed metric. |
| enum class MetricFormat { |
| INVALID = 0, |
| INT = 1, |
| UINT = 2, |
| DOUBLE = 3, |
| INT_ARRAY = 4, |
| UINT_ARRAY = 5, |
| DOUBLE_ARRAY = 6, |
| }; |
| |
| using IntMetric = internal::Value<int64_t, static_cast<size_t>(MetricFormat::INT)>; |
| using UIntMetric = internal::Value<uint64_t, static_cast<size_t>(MetricFormat::UINT)>; |
| using DoubleMetric = internal::Value<double, static_cast<size_t>(MetricFormat::DOUBLE)>; |
| using IntArray = internal::Array<int64_t, static_cast<size_t>(MetricFormat::INT_ARRAY)>; |
| using UIntArray = internal::Array<uint64_t, static_cast<size_t>(MetricFormat::UINT_ARRAY)>; |
| using DoubleArray = internal::Array<double, static_cast<size_t>(MetricFormat::DOUBLE_ARRAY)>; |
| |
| // Metric consist of a name and a value corresponding to one MetricFormat. |
| using Metric = |
| internal::NamedValue<fit::internal::variant<fit::internal::monostate, IntMetric, UIntMetric, |
| DoubleMetric, IntArray, UIntArray, DoubleArray>, |
| MetricFormat>; |
| |
| enum class PropertyFormat { |
| INVALID = 0, |
| STRING = 1, |
| BYTES = 2, |
| }; |
| |
| using StringProperty = internal::Value<std::string, static_cast<size_t>(PropertyFormat::STRING)>; |
| using ByteVectorProperty = |
| internal::Value<std::vector<uint8_t>, static_cast<size_t>(PropertyFormat::BYTES)>; |
| |
| // Property consists of a name and a value corresponding to one PropertyFormat. |
| using Property = internal::NamedValue< |
| fit::internal::variant<fit::internal::monostate, StringProperty, ByteVectorProperty>, |
| PropertyFormat>; |
| |
| // A Node stored in an ObjectHierarchy. |
| class Node { |
| public: |
| // Construct an empty Node. |
| Node() = default; |
| |
| // Construct a Node with a name and no properties or metrics. |
| explicit Node(std::string name); |
| |
| // Construct a Node with a name, properties, and metrics. |
| Node(std::string name, std::vector<Property> properties, std::vector<Metric> metrics); |
| |
| // Obtains reference to name. |
| const std::string& name() const { return name_; } |
| std::string& name() { return name_; } |
| |
| // Obtains reference to properties. |
| const std::vector<Property>& properties() const { return properties_; } |
| std::vector<Property>& properties() { return properties_; } |
| |
| // Obtains reference to metrics. |
| const std::vector<Metric>& metrics() const { return metrics_; } |
| std::vector<Metric>& metrics() { return metrics_; } |
| |
| // Sorts the metrics and properties of this object by name. |
| void Sort(); |
| |
| private: |
| // The name of this Node. |
| std::string name_; |
| |
| // The properties for this Node. |
| std::vector<Property> properties_; |
| |
| // The metrics for this Node. |
| std::vector<Metric> metrics_; |
| }; |
| } // namespace hierarchy |
| |
| // Represents a hierarchy of node objects rooted under one particular node. |
| // This class includes constructors that handle reading the hierarchy from |
| // various sources. |
| // |
| // TODO(CF-703): Rename to InspectHierarchy. |
| class ObjectHierarchy { |
| public: |
| ObjectHierarchy() = default; |
| |
| // Directly construct an object hierarchy consisting of a node and a list |
| // of children. |
| ObjectHierarchy(hierarchy::Node node, std::vector<ObjectHierarchy> children); |
| |
| // Allow moving, disallow copying. |
| ObjectHierarchy(ObjectHierarchy&&) = default; |
| ObjectHierarchy(const ObjectHierarchy&) = delete; |
| ObjectHierarchy& operator=(ObjectHierarchy&&) = default; |
| ObjectHierarchy& operator=(const ObjectHierarchy&) = delete; |
| |
| // Obtains the Node at this level of this hierarchy. |
| const hierarchy::Node& node() const { return node_; } |
| hierarchy::Node& node() { return node_; } |
| |
| // Obtains the name of the Node at this level of the hierarchy. |
| const std::string& name() const { return node_.name(); } |
| |
| // Gets the children of this object in the hierarchy. |
| const std::vector<ObjectHierarchy>& children() const { return children_; }; |
| std::vector<ObjectHierarchy>& children() { return children_; }; |
| |
| // Gets a child in this ObjectHierarchy by path. |
| // Returns NULL if the requested child could not be found. |
| const ObjectHierarchy* GetByPath(std::vector<std::string> path) const; |
| |
| // Sort metrics, properties, and children of this object by name. |
| void Sort(); |
| |
| private: |
| hierarchy::Node node_; |
| std::vector<ObjectHierarchy> children_; |
| }; |
| } // namespace inspect_deprecated |
| |
| #endif // SRC_LIB_INSPECT_DEPRECATED_HIERARCHY_H_ |