1 // Copyright 2025 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include "pw_bloat/bloat_this_binary.h"
17 #include "pw_containers/intrusive_forward_list.h"
18 #include "pw_containers/size_report/size_report.h"
19
20 namespace pw::containers::size_report {
21
22 /// A simple item for intrusive forward lists that wraps a moveable value.
23 template <typename T>
24 struct ForwardListItem : public IntrusiveForwardList<ForwardListItem<T>>::Item {
25 using Base = typename IntrusiveForwardList<ForwardListItem<T>>::Item;
26
ForwardListItemForwardListItem27 constexpr explicit ForwardListItem(T value) : value_(value) {}
28
ForwardListItemForwardListItem29 ForwardListItem(ForwardListItem&& other) { *this = std::move(other); }
30
31 ForwardListItem& operator=(ForwardListItem&& other) {
32 value_ = other.value_;
33 return *this;
34 }
35
36 bool operator<(const ForwardListItem& rhs) const {
37 return value_ < rhs.value_;
38 }
39
40 bool operator==(const ForwardListItem& rhs) const {
41 return value_ == rhs.value_;
42 }
43
44 T value_;
45 };
46
47 /// Invokes methods of the pw::IntrusiveForwardList type.
48 ///
49 /// This method is used both to measure intrusive forward lists directly, as
50 /// well as to provide a baseline for measuring other types that use intrusive
51 /// forward lists and want to only measure their contributions to code size.
52 template <typename ItemType, int&... kExplicitGuard, typename Iterator>
MeasureIntrusiveForwardList(Iterator first,Iterator last,uint32_t mask)53 int MeasureIntrusiveForwardList(Iterator first, Iterator last, uint32_t mask) {
54 mask = SetBaseline(mask);
55 auto& list1 = GetContainer<IntrusiveForwardList<ItemType>>();
56 IntrusiveForwardList<ItemType> list2;
57 auto iter1 = first;
58 for (size_t i = 0; i < 3; ++i) {
59 if (iter1 != last) {
60 ++iter1;
61 }
62 }
63 list1.assign(first, iter1);
64 list2.assign(iter1, last);
65
66 auto& item1 = list1.front();
67 PW_BLOAT_EXPR(list1.pop_front(), mask);
68 PW_BLOAT_EXPR(list2.push_front(item1), mask);
69 if constexpr (std::is_move_assignable_v<ItemType>) {
70 PW_BLOAT_EXPR(list1.swap(list2), mask);
71 PW_BLOAT_EXPR(list1.reverse(), mask);
72 }
73 if constexpr (internal::is_weakly_orderable_v<ItemType>) {
74 PW_BLOAT_EXPR(list1.sort(), mask);
75 PW_BLOAT_EXPR(list1.merge(list2), mask);
76 PW_BLOAT_COND(list1.unique() != 0, mask);
77 }
78 PW_BLOAT_EXPR(list2.clear(), mask);
79 PW_BLOAT_EXPR(list1.remove(item1), mask);
80
81 ItemType& item2 = list1.front();
82 auto iter2 = list1.erase_after(list1.before_begin());
83 PW_BLOAT_EXPR(list1.insert_after(iter2, item2), mask);
84 PW_BLOAT_EXPR(list1.splice_after(list1.begin(), list2), mask);
85
86 return list1.empty() ? 1 : 0;
87 }
88
89 } // namespace pw::containers::size_report
90