xref: /aosp_15_r20/external/pigweed/pw_fuzzer/examples/fuzztest/metrics.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2023 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "metrics.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <algorithm>
18*61c4878aSAndroid Build Coastguard Worker #include <cctype>
19*61c4878aSAndroid Build Coastguard Worker #include <cstring>
20*61c4878aSAndroid Build Coastguard Worker 
21*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h"
23*61c4878aSAndroid Build Coastguard Worker 
24*61c4878aSAndroid Build Coastguard Worker namespace pw::fuzzer::examples {
25*61c4878aSAndroid Build Coastguard Worker namespace {
Hash(std::string_view str)26*61c4878aSAndroid Build Coastguard Worker Metric::Key Hash(std::string_view str) {
27*61c4878aSAndroid Build Coastguard Worker   PW_CHECK(std::all_of(str.begin(), str.end(), isprint));
28*61c4878aSAndroid Build Coastguard Worker   return static_cast<Metric::Key>(std::hash<std::string_view>{}(str));
29*61c4878aSAndroid Build Coastguard Worker }
30*61c4878aSAndroid Build Coastguard Worker 
31*61c4878aSAndroid Build Coastguard Worker template <typename T>
32*61c4878aSAndroid Build Coastguard Worker using IsCopyable =
33*61c4878aSAndroid Build Coastguard Worker     std::enable_if_t<std::is_unsigned_v<T> && !std::is_same_v<T, bool>>;
34*61c4878aSAndroid Build Coastguard Worker 
35*61c4878aSAndroid Build Coastguard Worker template <typename T, typename = IsCopyable<T>>
CopyTo(pw::ByteSpan dst,size_t & offset,const T & src)36*61c4878aSAndroid Build Coastguard Worker Status CopyTo(pw::ByteSpan dst, size_t& offset, const T& src) {
37*61c4878aSAndroid Build Coastguard Worker   size_t len = sizeof(src);
38*61c4878aSAndroid Build Coastguard Worker   if (offset + len > dst.size()) {
39*61c4878aSAndroid Build Coastguard Worker     return Status::ResourceExhausted();
40*61c4878aSAndroid Build Coastguard Worker   }
41*61c4878aSAndroid Build Coastguard Worker   memcpy(&dst[offset], &src, len);
42*61c4878aSAndroid Build Coastguard Worker   offset += len;
43*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
44*61c4878aSAndroid Build Coastguard Worker }
45*61c4878aSAndroid Build Coastguard Worker 
46*61c4878aSAndroid Build Coastguard Worker template <typename T, typename = IsCopyable<T>>
CopyFrom(pw::ConstByteSpan src,size_t & offset,T & dst)47*61c4878aSAndroid Build Coastguard Worker Status CopyFrom(pw::ConstByteSpan src, size_t& offset, T& dst) {
48*61c4878aSAndroid Build Coastguard Worker   size_t len = sizeof(dst);
49*61c4878aSAndroid Build Coastguard Worker   if (offset + len > src.size()) {
50*61c4878aSAndroid Build Coastguard Worker     return Status::ResourceExhausted();
51*61c4878aSAndroid Build Coastguard Worker   }
52*61c4878aSAndroid Build Coastguard Worker   memcpy(&dst, &src[offset], len);
53*61c4878aSAndroid Build Coastguard Worker   offset += len;
54*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
55*61c4878aSAndroid Build Coastguard Worker }
56*61c4878aSAndroid Build Coastguard Worker 
57*61c4878aSAndroid Build Coastguard Worker }  // namespace
58*61c4878aSAndroid Build Coastguard Worker 
Metric(std::string_view name_,Value value_)59*61c4878aSAndroid Build Coastguard Worker Metric::Metric(std::string_view name_, Value value_)
60*61c4878aSAndroid Build Coastguard Worker     : name(name_), value(value_) {
61*61c4878aSAndroid Build Coastguard Worker   key = Hash(name_);
62*61c4878aSAndroid Build Coastguard Worker }
63*61c4878aSAndroid Build Coastguard Worker 
GetValue(std::string_view name) const64*61c4878aSAndroid Build Coastguard Worker std::optional<Metric::Value> Metrics::GetValue(std::string_view name) const {
65*61c4878aSAndroid Build Coastguard Worker   for (const auto& metric : metrics_) {
66*61c4878aSAndroid Build Coastguard Worker     if (metric.name == name) {
67*61c4878aSAndroid Build Coastguard Worker       return metric.value;
68*61c4878aSAndroid Build Coastguard Worker     }
69*61c4878aSAndroid Build Coastguard Worker   }
70*61c4878aSAndroid Build Coastguard Worker   return std::optional<Metric::Value>();
71*61c4878aSAndroid Build Coastguard Worker }
72*61c4878aSAndroid Build Coastguard Worker 
SetValue(std::string_view name,Metric::Value value)73*61c4878aSAndroid Build Coastguard Worker Status Metrics::SetValue(std::string_view name, Metric::Value value) {
74*61c4878aSAndroid Build Coastguard Worker   for (auto& metric : metrics_) {
75*61c4878aSAndroid Build Coastguard Worker     if (metric.name == name) {
76*61c4878aSAndroid Build Coastguard Worker       metric.value = value;
77*61c4878aSAndroid Build Coastguard Worker       return OkStatus();
78*61c4878aSAndroid Build Coastguard Worker     }
79*61c4878aSAndroid Build Coastguard Worker   }
80*61c4878aSAndroid Build Coastguard Worker   if (metrics_.full()) {
81*61c4878aSAndroid Build Coastguard Worker     return Status::ResourceExhausted();
82*61c4878aSAndroid Build Coastguard Worker   }
83*61c4878aSAndroid Build Coastguard Worker   metrics_.emplace_back(name, value);
84*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
85*61c4878aSAndroid Build Coastguard Worker }
86*61c4878aSAndroid Build Coastguard Worker 
GetMetrics() const87*61c4878aSAndroid Build Coastguard Worker const Vector<Metric>& Metrics::GetMetrics() const { return metrics_; }
88*61c4878aSAndroid Build Coastguard Worker 
SetMetrics(const Vector<Metric> & metrics)89*61c4878aSAndroid Build Coastguard Worker Status Metrics::SetMetrics(const Vector<Metric>& metrics) {
90*61c4878aSAndroid Build Coastguard Worker   if (metrics_.capacity() < metrics.size()) {
91*61c4878aSAndroid Build Coastguard Worker     return Status::ResourceExhausted();
92*61c4878aSAndroid Build Coastguard Worker   }
93*61c4878aSAndroid Build Coastguard Worker   metrics_.assign(metrics.begin(), metrics.end());
94*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
95*61c4878aSAndroid Build Coastguard Worker }
96*61c4878aSAndroid Build Coastguard Worker 
Serialize(pw::ByteSpan buffer) const97*61c4878aSAndroid Build Coastguard Worker StatusWithSize Metrics::Serialize(pw::ByteSpan buffer) const {
98*61c4878aSAndroid Build Coastguard Worker   size_t offset = 0;
99*61c4878aSAndroid Build Coastguard Worker   PW_TRY_WITH_SIZE(CopyTo(buffer, offset, metrics_.size()));
100*61c4878aSAndroid Build Coastguard Worker   for (const auto& metric : metrics_) {
101*61c4878aSAndroid Build Coastguard Worker     PW_TRY_WITH_SIZE(CopyTo(buffer, offset, metric.key));
102*61c4878aSAndroid Build Coastguard Worker     PW_TRY_WITH_SIZE(CopyTo(buffer, offset, metric.value));
103*61c4878aSAndroid Build Coastguard Worker   }
104*61c4878aSAndroid Build Coastguard Worker   return StatusWithSize(offset);
105*61c4878aSAndroid Build Coastguard Worker }
106*61c4878aSAndroid Build Coastguard Worker 
Deserialize(pw::ConstByteSpan buffer)107*61c4878aSAndroid Build Coastguard Worker Status Metrics::Deserialize(pw::ConstByteSpan buffer) {
108*61c4878aSAndroid Build Coastguard Worker   size_t offset = 0;
109*61c4878aSAndroid Build Coastguard Worker   size_t num_values = 0;
110*61c4878aSAndroid Build Coastguard Worker   PW_TRY(CopyFrom(buffer, offset, num_values));
111*61c4878aSAndroid Build Coastguard Worker   for (size_t i = 0; i < num_values; ++i) {
112*61c4878aSAndroid Build Coastguard Worker     Metric::Key key;
113*61c4878aSAndroid Build Coastguard Worker     PW_TRY(CopyFrom(buffer, offset, key));
114*61c4878aSAndroid Build Coastguard Worker     Metric::Value value;
115*61c4878aSAndroid Build Coastguard Worker     PW_TRY(CopyFrom(buffer, offset, value));
116*61c4878aSAndroid Build Coastguard Worker     bool found = false;
117*61c4878aSAndroid Build Coastguard Worker     for (auto& metric : metrics_) {
118*61c4878aSAndroid Build Coastguard Worker       if (metric.key == key) {
119*61c4878aSAndroid Build Coastguard Worker         metric.value = value;
120*61c4878aSAndroid Build Coastguard Worker         found = true;
121*61c4878aSAndroid Build Coastguard Worker         break;
122*61c4878aSAndroid Build Coastguard Worker       }
123*61c4878aSAndroid Build Coastguard Worker     }
124*61c4878aSAndroid Build Coastguard Worker     if (!found) {
125*61c4878aSAndroid Build Coastguard Worker       return Status::InvalidArgument();
126*61c4878aSAndroid Build Coastguard Worker     }
127*61c4878aSAndroid Build Coastguard Worker   }
128*61c4878aSAndroid Build Coastguard Worker   return OkStatus();
129*61c4878aSAndroid Build Coastguard Worker }
130*61c4878aSAndroid Build Coastguard Worker 
131*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::fuzzer::examples
132