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 <type_traits>
17
18 #include "pw_bloat/bloat_this_binary.h"
19 #include "pw_containers/internal/intrusive_item.h"
20 #include "pw_containers/intrusive_list.h"
21 #include "pw_containers/size_report/size_report.h"
22
23 namespace pw::containers::size_report {
24
25 /// A simple item for intrusive lists that wraps a moveable value.
26 template <typename T>
27 struct ListItem : public future::IntrusiveList<ListItem<T>>::Item {
28 using Base = typename future::IntrusiveList<ListItem<T>>::Item;
29
ListItemListItem30 constexpr explicit ListItem(T value) : value_(value) {}
31
ListItemListItem32 ListItem(ListItem&& other) { *this = std::move(other); }
33
34 ListItem& operator=(ListItem&& other) {
35 value_ = std::move(other.value_);
36 return *this;
37 }
38
39 bool operator<(const ListItem& rhs) const { return value_ < rhs.value_; }
40
41 bool operator==(const ListItem& rhs) const { return value_ == rhs.value_; }
42
43 T value_ = 0;
44 };
45
46 /// Invokes methods of the pw::containers::future::IntrusiveList type.
47 ///
48 /// This method is used both to measure intrusive lists directly, as well as
49 /// to provide a baseline for measuring other types that use intrusive lists and
50 /// want to only measure their contributions to code size.
51 template <typename ItemType, int&... kExplicitGuard, typename Iterator>
MeasureIntrusiveList(Iterator first,Iterator last,uint32_t mask)52 int MeasureIntrusiveList(Iterator first, Iterator last, uint32_t mask) {
53 mask = SetBaseline(mask);
54 auto& list1 = GetContainer<future::IntrusiveList<ItemType>>();
55 future::IntrusiveList<ItemType> list2;
56 auto iter1 = first;
57 for (size_t i = 0; i < 3; ++i) {
58 if (iter1 != last) {
59 ++iter1;
60 }
61 }
62 list1.assign(first, iter1);
63 list2.assign(iter1, last);
64 mask = MeasureContainer(list1, mask);
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 auto& item2 = list1.front();
82 auto iter2 = list1.erase(item2);
83 ++iter2;
84 PW_BLOAT_EXPR(list1.insert(iter2, item2), mask);
85 PW_BLOAT_EXPR(list1.splice(list1.end(), list2), mask);
86
87 return list1.empty() ? 1 : 0;
88 }
89
90 } // namespace pw::containers::size_report
91