Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 : #pragma once
18 :
19 : #include <bitset>
20 : #include <cstddef>
21 : #include <type_traits>
22 :
23 : #include <lib/core/CHIPError.h>
24 :
25 : namespace chip {
26 : namespace Retransmit {
27 :
28 : /**
29 : * Handles lifetimes of payloads.
30 : *
31 : * E.g. for buffers, handles reference counting.
32 : */
33 : template <typename PayloadType>
34 : struct Lifetime
35 : {
36 : static PayloadType Acquire(PayloadType & payload);
37 : static void Release(PayloadType & payload);
38 : };
39 :
40 : /**
41 : * This class maintains a cache of data that is sufficient to retransmit.
42 : *
43 : * Typical use is to keep track of unacknowledged packets and resend them
44 : * as needed.
45 : *
46 : * @tparam KeyType the key to identify a single message
47 : * @tparam PayloadType the type of payload to cache for the given peer address
48 : * @tparam N size of the available cache
49 : *
50 : * PayloadType MUST provide a way to reference count, as the data will
51 : * preserved until the cache is freed:
52 : *
53 : * PayloadType chip::Retransmit::Acquire(PayloadType&);
54 : * chip::Retransmit::Release(PayloadType&);
55 : */
56 : template <typename KeyType, typename PayloadType, size_t N>
57 : class Cache
58 : {
59 : public:
60 6 : Cache() {}
61 : Cache(const Cache &) = delete;
62 : Cache & operator=(const Cache &) = delete;
63 :
64 6 : ~Cache()
65 : {
66 61 : for (size_t i = 0; i < N; i++)
67 : {
68 55 : if (mInUse.test(i))
69 : {
70 9 : Lifetime<PayloadType>::Release(mEntries[i].payload);
71 : }
72 : }
73 6 : }
74 :
75 : /**
76 : * Add a payload to the cache.
77 : */
78 21 : CHIP_ERROR Add(const KeyType & key, PayloadType & payload)
79 : {
80 21 : if (mInUse.count() >= N)
81 : {
82 3 : return CHIP_ERROR_NO_MEMORY;
83 : }
84 :
85 41 : for (size_t i = 0; i < N; i++)
86 : {
87 41 : if (!mInUse.test(i))
88 : {
89 18 : mInUse.set(i);
90 18 : mEntries[i].key = key;
91 18 : mEntries[i].payload = Lifetime<PayloadType>::Acquire(payload);
92 18 : break;
93 : }
94 : }
95 :
96 18 : return CHIP_NO_ERROR;
97 : }
98 :
99 : /**
100 : * Remove a payload from the cache given the key.
101 : */
102 10 : CHIP_ERROR Remove(const KeyType & key)
103 : {
104 29 : for (size_t i = 0; i < N; i++)
105 : {
106 26 : if (mInUse.test(i) && (mEntries[i].key == key))
107 : {
108 7 : mInUse.reset(i);
109 7 : Lifetime<PayloadType>::Release(mEntries[i].payload);
110 7 : return CHIP_NO_ERROR;
111 : }
112 : }
113 :
114 3 : return CHIP_ERROR_KEY_NOT_FOUND;
115 : }
116 :
117 : /**
118 : * Remove any matching payloads. Used for mass removal, e.g. when a connection
119 : * is closed, relevant payloads need/can be cleared for the entire connection.
120 : *
121 : * @tparam Matcher is a generic matcher object defining a bool Matches method.
122 : */
123 : template <typename Matcher>
124 1 : void RemoveMatching(const Matcher & matcher)
125 : {
126 5 : for (size_t i = 0; i < N; i++)
127 : {
128 4 : if (mInUse.test(i) && matcher.Matches(mEntries[i].key))
129 : {
130 2 : mInUse.reset(i);
131 2 : Lifetime<PayloadType>::Release(mEntries[i].payload);
132 : }
133 : }
134 1 : }
135 :
136 : /**
137 : * Search for a specific entry within the cache.
138 : *
139 : * @tparam Matcher is a generic macher object defining a bool Maches method.
140 : *
141 : * @param matcher the entry to find
142 : * @param key - out set the key if found
143 : * @param payload - the payload if found
144 : *
145 : * Key and payload are only valid as long as no remove methods
146 : * are called on the class.
147 : */
148 : template <typename Matcher>
149 4 : bool Find(const Matcher & matcher, const KeyType ** key, const PayloadType ** payload)
150 : {
151 4 : *key = nullptr;
152 4 : *payload = nullptr;
153 :
154 16 : for (size_t i = 0; i < N; i++)
155 : {
156 14 : if (mInUse.test(i) && matcher.Matches(mEntries[i].key))
157 : {
158 2 : *key = &mEntries[i].key;
159 2 : *payload = &mEntries[i].payload;
160 2 : return true;
161 : }
162 : }
163 2 : return false;
164 : }
165 :
166 : private:
167 : struct Entry
168 : {
169 : KeyType key;
170 : PayloadType payload;
171 : };
172 :
173 : Entry mEntries[N]; // payload entries
174 : std::bitset<N> mInUse; // compact 'in use' marker for payloads
175 : }; // namespace Retransmit
176 :
177 : } // namespace Retransmit
178 : } // namespace chip
|