• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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