blob: 40038387c89339f384079c073a2219a34aa3b374 [file] [log] [blame]
// Copyright 2018 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 LIB_INSPECT_CPP_VMO_TYPES_H_
#define LIB_INSPECT_CPP_VMO_TYPES_H_
#include <string>
#include <vector>
#include <lib/inspect/cpp/vmo/block.h>
#include <zircon/types.h>
namespace inspect {
class Node;
class State;
namespace internal {
// A property containing a templated numeric type. All methods wrap the
// corresponding functionality on |State|, and concrete
// implementations are available only for int64_t, uint64_t and double.
template <typename T>
class NumericProperty final {
public:
// Construct a default numeric metric. Operations on this metric are
// no-ops.
NumericProperty() = default;
~NumericProperty();
// Allow moving, disallow copying.
NumericProperty(const NumericProperty& other) = delete;
NumericProperty(NumericProperty&& other) = default;
NumericProperty& operator=(const NumericProperty& other) = delete;
NumericProperty& operator=(NumericProperty&& other);
// Set the value of this numeric metric to the given value.
void Set(T value);
// Add the given value to the value of this numeric metric.
void Add(T value);
// Subtract the given value from the value of this numeric metric.
void Subtract(T value);
// Return true if this metric is stored in a buffer. False otherwise.
explicit operator bool() { return state_ != nullptr; }
private:
friend class ::inspect::State;
NumericProperty(std::shared_ptr<State> state, BlockIndex name, BlockIndex value)
: state_(std::move(state)), name_index_(name), value_index_(value) {}
// Reference to the state containing this metric.
std::shared_ptr<State> state_;
// Index of the name block in the state.
BlockIndex name_index_;
// Index of the value block in the state.
BlockIndex value_index_;
};
// A value containing an array of numeric types. All methods wrap the
// corresponding functionality on |State|, and concrete
// implementations are available only for int64_t, uint64_t and double.
template <typename T>
class ArrayValue final {
public:
// Construct a default array value. Operations on this value are
// no-ops.
ArrayValue() = default;
~ArrayValue();
// Allow moving, disallow copying.
ArrayValue(const ArrayValue& other) = delete;
ArrayValue(ArrayValue&& other) = default;
ArrayValue& operator=(const ArrayValue& other) = delete;
ArrayValue& operator=(ArrayValue&& other);
// Set the value of the given index of this array.
void Set(size_t index, T value);
// Add the given value to the value of this numeric metric.
void Add(size_t index, T value);
// Subtract the given value from the value of this numeric metric.
void Subtract(size_t index, T value);
// Return true if this metric is stored in a buffer. False otherwise.
explicit operator bool() { return state_ != nullptr; }
private:
friend class ::inspect::State;
ArrayValue(std::shared_ptr<State> state, BlockIndex name, BlockIndex value)
: state_(std::move(state)), name_index_(name), value_index_(value) {}
// Reference to the state containing this value.
std::shared_ptr<State> state_;
// Index of the name block in the state.
BlockIndex name_index_;
// Index of the value block in the state.
BlockIndex value_index_;
};
template <typename T>
class LinearHistogram final {
public:
// Create a default histogram.
// Operations on the metric will have no effect.
LinearHistogram() = default;
// Insert the given value once to the correct bucket of the histogram.
void Insert(T value) { Insert(value, 1); }
// Insert the given value |count| times to the correct bucket of the
// histogram.
void Insert(T value, T count) { array_.Add(GetIndexForValue(value), count); }
private:
friend class ::inspect::Node;
// First slots are floor, step_size, and underflow.
static const size_t kBucketOffset = 3;
// Get the number of buckets, which excludes the two parameter slots and the
// two overflow slots.
size_t BucketCount() { return array_size_ - 4; }
// Calculates the correct array index to store the given value.
size_t GetIndexForValue(T value) {
if (array_size_ == 0) {
return 0;
}
size_t ret = kBucketOffset - 1;
T current_floor = floor_;
for (; value >= current_floor && ret < array_size_ - 1; current_floor += step_size_, ret++) {
}
return ret;
}
// Internal constructor wrapping an array.
LinearHistogram(T floor, T step_size, size_t array_size, ArrayValue<T> array)
: floor_(floor), step_size_(step_size), array_size_(array_size), array_(std::move(array)) {
ZX_ASSERT(array_size_ > 4);
array_.Set(0, floor_);
array_.Set(1, step_size_);
}
const T floor_ = 0;
const T step_size_ = 0;
const size_t array_size_ = 0;
ArrayValue<T> array_;
};
template <typename T>
class ExponentialHistogram final {
public:
// Create a default histogram.
// Operations on the metric will have no effect.
ExponentialHistogram() = default;
// Insert the given value once to the correct bucket of the histogram.
void Insert(T value) { Insert(value, 1); }
// Insert the given value |count| times to the correct bucket of the
// histogram.
void Insert(T value, T count) { array_.Add(GetIndexForValue(value), count); }
private:
friend class ::inspect::Node;
// First slots are floor, initial_step, step_multiplier, and underflow.
static const size_t kBucketOffset = 4;
// Get the number of buckets, which excludes the two parameter slots and the
// two overflow slots.
size_t BucketCount() { return array_size_ - 5; }
// Calculates the correct array index to store the given value.
size_t GetIndexForValue(T value) {
if (array_size_ == 0) {
return 0;
}
T current_floor = floor_;
T current_step = initial_step_;
size_t ret = kBucketOffset - 1;
for (; value >= current_floor && ret < array_size_ - 1;
current_floor += current_step, current_step *= step_multiplier_, ret++) {
}
return ret;
}
// Internal constructor wrapping a VMO type.
ExponentialHistogram(T floor, T initial_step, T step_multiplier, size_t array_size,
ArrayValue<T> array)
: floor_(floor),
initial_step_(initial_step),
step_multiplier_(step_multiplier),
array_size_(array_size),
array_(std::move(array)) {
ZX_ASSERT(array_size_ > 5);
array_.Set(0, floor_);
array_.Set(1, initial_step_);
array_.Set(2, step_multiplier_);
}
const T floor_ = 0;
const T initial_step_ = 0;
const T step_multiplier_ = 0;
const size_t array_size_ = 0;
ArrayValue<T> array_;
};
// A property containing a string value.
// All methods wrap the corresponding functionality on |State|.
template <typename T>
class Property final {
public:
// Construct a default property. Operations on this property are
// no-ops.
Property() = default;
~Property();
// Allow moving, disallow copying.
Property(const Property& other) = delete;
Property(Property&& other) = default;
Property& operator=(const Property& other) = delete;
Property& operator=(Property&& other);
// Return true if this property is stored in a buffer. False otherwise.
explicit operator bool() { return state_ != nullptr; }
// Set the value of this property.
void Set(const T& value);
private:
friend class ::inspect::State;
Property(std::shared_ptr<State> state, BlockIndex name, BlockIndex value)
: state_(std::move(state)), name_index_(name), value_index_(value) {}
// Reference to the state containing this property.
std::shared_ptr<State> state_;
// Index of the name block in the state.
BlockIndex name_index_;
// Index of the value block in the state.
BlockIndex value_index_;
};
} // namespace internal
using IntProperty = internal::NumericProperty<int64_t>;
using UintProperty = internal::NumericProperty<uint64_t>;
using DoubleProperty = internal::NumericProperty<double>;
using IntArray = internal::ArrayValue<int64_t>;
using UintArray = internal::ArrayValue<uint64_t>;
using DoubleArray = internal::ArrayValue<double>;
using LinearIntHistogram = internal::LinearHistogram<int64_t>;
using LinearUintHistogram = internal::LinearHistogram<uint64_t>;
using LinearDoubleHistogram = internal::LinearHistogram<double>;
using ExponentialIntHistogram = internal::ExponentialHistogram<int64_t>;
using ExponentialUintHistogram = internal::ExponentialHistogram<uint64_t>;
using ExponentialDoubleHistogram = internal::ExponentialHistogram<double>;
using StringProperty = internal::Property<std::string>;
using ByteVectorProperty = internal::Property<std::vector<uint8_t>>;
// An node under which properties, metrics, and other nodes may be nested.
// All methods wrap the corresponding functionality on |State|.
class Node final {
public:
// Construct a default node. Operations on this node are
// no-ops.
Node() = default;
~Node();
// Allow moving, disallow copying.
Node(const Node& other) = delete;
Node(Node&& other) = default;
Node& operator=(const Node& other) = delete;
Node& operator=(Node&& other);
// Create a new |Node| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created node will
// also not be stored in a buffer.
Node CreateChild(const std::string& name);
// Create a new |IntProperty| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created metric will
// also not be stored in a buffer.
IntProperty CreateInt(const std::string& name, int64_t value);
// Create a new |UintProperty| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created metric will
// also not be stored in a buffer.
UintProperty CreateUint(const std::string& name, uint64_t value);
// Create a new |DoubleProperty| with the given name that is a child of this node.
// If this node is not stored in a buffer, the created metric will
// also not be stored in a buffer.
DoubleProperty CreateDouble(const std::string& name, double value);
// Create a new |StringProperty| with the given name and value that is a child of this node.
// If this node is not stored in a buffer, the created property will
// also not be stored in a buffer.
StringProperty CreateString(const std::string& name, const std::string& value);
// Create a new |ByteVectorProperty| with the given name and value that is a child of this node.
// If this node is not stored in a buffer, the created property will
// also not be stored in a buffer.
ByteVectorProperty CreateByteVector(const std::string& name, const std::vector<uint8_t>& value);
// Create a new |IntArray| with the given name and slots that is a child of this node.
// If this node is not stored in a buffer, the created value will
// also not be stored in a buffer.
IntArray CreateIntArray(const std::string& name, size_t slots);
// Create a new |UintArray| with the given name and slots that is a child of this node.
// If this node is not stored in a buffer, the created value will
// also not be stored in a buffer.
UintArray CreateUintArray(const std::string& name, size_t slots);
// Create a new |DoubleArray| with the given name and slots that is a child of this node.
// If this node is not stored in a buffer, the created value will
// also not be stored in a buffer.
DoubleArray CreateDoubleArray(const std::string& name, size_t slots);
// Create a new |LinearIntHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
LinearIntHistogram CreateLinearIntHistogram(const std::string& name, int64_t floor,
int64_t step_size, size_t buckets);
// Create a new |LinearUintHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
LinearUintHistogram CreateLinearUintHistogram(const std::string& name, uint64_t floor,
uint64_t step_size, size_t buckets);
// Create a new |LinearDoubleHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
LinearDoubleHistogram CreateLinearDoubleHistogram(const std::string& name, double floor,
double step_size, size_t buckets);
// Create a new |ExponentialIntHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
ExponentialIntHistogram CreateExponentialIntHistogram(const std::string& name, int64_t floor,
int64_t initial_step,
int64_t step_multiplier, size_t buckets);
// Create a new |ExponentialUintHistogram| with the given name and format that is a child of this
// node. If this node is not stored in a buffer, the created value will also not be stored in
// a buffer.
ExponentialUintHistogram CreateExponentialUintHistogram(const std::string& name, uint64_t floor,
uint64_t initial_step,
uint64_t step_multiplier, size_t buckets);
// Create a new |ExponentialDoubleHistogram| with the given name and format that is a child of
// this node. If this node is not stored in a buffer, the created value will also not be
// stored in a buffer.
ExponentialDoubleHistogram CreateExponentialDoubleHistogram(const std::string& name, double floor,
double initial_step,
double step_multiplier,
size_t buckets);
// Return true if this node is stored in a buffer. False otherwise.
explicit operator bool() { return state_ != nullptr; }
private:
friend class ::inspect::State;
Node(std::shared_ptr<State> state, BlockIndex name, BlockIndex value)
: state_(std::move(state)), name_index_(name), value_index_(value) {}
// Reference to the state containing this metric.
std::shared_ptr<State> state_;
// Index of the name block in the state.
BlockIndex name_index_;
// Index of the value block in the state.
BlockIndex value_index_;
};
} // namespace inspect
#endif // LIB_INSPECT_CPP_VMO_TYPES_H_