The Pedigree Project  0.1
RangeList.h
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #ifndef KERNEL_UTILITIES_RANGELIST_H
21 #define KERNEL_UTILITIES_RANGELIST_H
22 
23 #include "pedigree/kernel/compiler.h"
24 #include "pedigree/kernel/processor/types.h"
25 #include "pedigree/kernel/utilities/StaticString.h"
26 #include "pedigree/kernel/utilities/Vector.h"
27 
34 template <typename T, bool Reversed = false>
36 {
37  public:
39  inline RangeList() : m_List(), m_bPreferUsed(false)
40  {
41  }
43  inline RangeList(bool preferUsed) : m_List(), m_bPreferUsed(preferUsed)
44  {
45  }
49  RangeList(T Address, T Length, bool XXX, bool preferUsed = false)
50  : m_List(), m_bPreferUsed(preferUsed)
51  {
52  Range *range = new Range(Address, Length);
53  m_List.pushBack(range);
54  }
56  ~RangeList();
57 
58  RangeList(const RangeList &);
59  RangeList &operator=(const RangeList &l);
60 
62  struct Range
63  {
65  Range(T Address, T Length) : address(Address), length(Length)
66  {
67  }
68 
72  T length;
73 
74  bool operator==(const Range &other) const
75  {
76  return (address == other.address) && (length == other.length);
77  }
78  };
79 
85  void free(T address, T length, bool merge = true);
91  bool allocate(T length, T &address);
96  bool allocateSpecific(T address, T length);
97  void clear();
98 
101  inline size_t size() const
102  {
103  return m_List.count();
104  }
106  Range getRange(size_t index) const;
107 
109  void sweep();
110 
112  void dump(void (*emit_line)(const char *s)) const;
113 
114  private:
117 
120 
121  typedef typename decltype(m_List)::Iterator Iterator;
122  typedef typename decltype(m_List)::ConstIterator ConstIterator;
123  typedef typename decltype(m_List)::ReverseIterator ReverseIterator;
124  typedef
125  typename decltype(m_List)::ConstReverseIterator ConstReverseIterator;
126 };
127 
131 template <typename T, bool Reversed>
133 {
134  // Need to clean up all our existing ranges.
135  clear();
136 
137  for (ConstIterator it = other.m_List.begin(); it != other.m_List.end();
138  ++it)
139  {
140  Range *pRange = new Range((*it)->address, (*it)->length);
141  m_List.pushBack(pRange);
142  }
143 }
144 
145 template <typename T, bool Reversed>
147 operator=(const RangeList &other)
148 {
149  // Need to clean up all our existing ranges.
150  clear();
151 
152  for (ConstIterator it = other.m_List.begin(); it != other.m_List.end();
153  ++it)
154  {
155  Range *pRange = new Range((*it)->address, (*it)->length);
156  m_List.pushBack(pRange);
157  }
158 
159  return *this;
160 }
161 
162 template <typename T, bool Reversed>
163 void RangeList<T, Reversed>::free(T address, T length, bool merge)
164 {
165  if (merge)
166  {
167  Iterator cur = m_List.begin();
168  ConstIterator end = m_List.end();
169 
170  // Try and find a place to merge immediately.
171  bool needsNew = true;
172  for (; cur != end; ++cur)
173  {
174  // Region ends at our freed address.
175  if (((*cur)->address + (*cur)->length) == address)
176  {
177  // Update - all done.
178  (*cur)->length += length;
179  needsNew = false;
180  break;
181  }
182  // Region starts after our address.
183  else if ((*cur)->address == (address + length))
184  {
185  // Expand.
186  (*cur)->address -= length;
187  (*cur)->length += length;
188  needsNew = false;
189  break;
190  }
191  }
192 
193  if (!needsNew)
194  return;
195  }
196 
197  // Couldn't find a merge or didn't want one, so we need to add a new region.
198 
199  // Add the range back to our list, but in such a way that it is allocated
200  // last rather than first (if another allocation of the same length comes
201  // later).
202  Range *range = new Range(address, length);
203 
204  // Decide which side of the list to push to. If we prefer used ranges over
205  // fresh ranges, we want to invert the push decision.
206  bool front = Reversed;
207  if (m_bPreferUsed)
208  front = !front;
209 
210  if (front)
211  m_List.pushFront(range);
212  else
213  m_List.pushBack(range);
214 
215  // NOTE: we defer sweeping to allocate(), and only if a first attempt at
216  // allocate() fails to successfully find a range it can use. This saves
217  // time when freeing regions and is useful for RangeLists that are not
218  // heavily utilized.
219 }
220 
221 template <typename T, bool Reversed>
222 bool RangeList<T, Reversed>::allocate(T length, T &address)
223 {
224  bool bSuccess = false;
225 
226  for (int i = 0; i < 2; ++i)
227  {
228  auto it = Reversed ? m_List.rbegin() : m_List.begin();
229  auto end = Reversed ? m_List.rend() : m_List.end();
230 
231  for (; it != end; ++it)
232  {
233  if ((*it)->length < length)
234  {
235  continue;
236  }
237 
238  if (Reversed)
239  {
240  // Big enough. Cut into the END of this range.
241  T offset = (*it)->length - length;
242  address = (*it)->address + offset;
243  }
244  else
245  {
246  address = (*it)->address;
247  (*it)->address += length;
248  }
249  (*it)->length -= length;
250 
251  // Remove if the entry no longer exists.
252  if (!(*it)->length)
253  {
254  delete (*it);
255  m_List.erase(it);
256  }
257 
258  bSuccess = true;
259  break;
260  }
261 
262  if (bSuccess)
263  {
264  return true;
265  }
266  else if (!i)
267  {
268  // Failed on first pass, try another pass after a sweep.
269  // The sweep could merge some regions and let us allocate.
270  // This is better than sweeping on every single allocation, which
271  // could be really slow and unnecessary.
272  sweep();
273  }
274  }
275 
276  return bSuccess;
277 }
278 
279 template <typename T, bool Reversed>
281 {
282  bool bSuccess = false;
283  for (int i = 0; i < 2; ++i)
284  {
285  for (Iterator cur = m_List.begin(); cur != m_List.end(); ++cur)
286  {
287  // Precise match.
288  if ((*cur)->address == address && (*cur)->length == length)
289  {
290  delete *cur;
291  m_List.erase(cur);
292  bSuccess = true;
293  break;
294  }
295 
296  // Match at end.
297  else if (
298  (*cur)->address < address &&
299  ((*cur)->address + (*cur)->length) == (address + length))
300  {
301  (*cur)->length -= length;
302  bSuccess = true;
303  break;
304  }
305 
306  // Match at start.
307  else if ((*cur)->address == address && (*cur)->length > length)
308  {
309  (*cur)->address += length;
310  (*cur)->length -= length;
311  bSuccess = true;
312  break;
313  }
314 
315  // Match within.
316  else if (
317  (*cur)->address < address &&
318  ((*cur)->address + (*cur)->length) > (address + length))
319  {
320  // Need to split the range.
321  Range *newRange = new Range(
322  address + length,
323  (*cur)->address + (*cur)->length - address - length);
324  (*cur)->length = address - (*cur)->address;
325  m_List.pushBack(newRange);
326  bSuccess = true;
327  break;
328  }
329  }
330 
331  if (bSuccess)
332  {
333  return bSuccess;
334  }
335  else if (!i)
336  {
337  // Failed in the first pass, sweep to merge potential regions and
338  // then we'll try again.
339  sweep();
340  }
341  }
342 
343  return bSuccess;
344 }
345 
346 template <typename T, bool Reversed>
349 {
350  if (index >= m_List.size())
351  return Range(0, 0);
352 
353  return Range(*m_List[index]);
354 }
355 
356 template <typename T, bool Reversed>
358 {
359  clear();
360 }
361 
362 template <typename T, bool Reversed>
364 {
365  for (size_t i = 0; i < m_List.count(); ++i)
366  {
367  delete m_List[i];
368  }
369  m_List.clear();
370 }
371 
372 template <typename T, bool Reversed>
374 {
375  if (m_List.count() < 2)
376  {
377  return;
378  }
379 
380  for (size_t i = 0; i < (m_List.count() - 1);)
381  {
382  // Can we merge? (note: preincrement modifies the iterator)
383  Range *cur = m_List[i];
384  Range *next = m_List[i + 1];
385 
386  uintptr_t cur_address = cur->address;
387  uintptr_t next_address = next->address;
388  size_t cur_len = cur->length;
389  size_t next_len = next->length;
390 
391  if ((cur_address + cur_len) == next_address)
392  {
393  // Merge.
394  cur->length += next_len;
395  delete next;
396  m_List.erase(i + 1);
397  }
398  else if ((next_address + next_len) == cur_address)
399  {
400  cur->address -= next_len;
401  cur->length += next_len;
402  delete next;
403  m_List.erase(i + 1);
404  }
405  else
406  {
407  ++i;
408  }
409  }
410 }
411 
412 template <typename T, bool Reversed>
413 void RangeList<T, Reversed>::dump(void (*emit_line)(const char *s)) const
414 {
415  for (size_t i = 0; i < m_List.count(); ++i)
416  {
417  const Range *range = m_List[i];
418 
419  HugeStaticString str;
420  str.append("range ");
421  str.append(range->address, 16, 16, '0');
422  str.append(" -> ");
423  str.append(range->address + range->length, 16, 16, '0');
424  str.append(" (");
425  str.append(range->length, 10);
426  str.append(" bytes)");
427  emit_line(static_cast<const char *>(str));
428  }
429 }
430 
431 extern template class RangeList<uint64_t>; // IWYU pragma: keep
432 extern template class RangeList<uint32_t>; // IWYU pragma: keep
433 
434 #endif
void pushBack(const T &value)
Definition: Vector.h:270
Iterator begin()
Definition: Vector.h:148
Iterator end()
Definition: Vector.h:160
Range(T Address, T Length)
Definition: RangeList.h:65
size_t size() const
Definition: RangeList.h:101
size_t count() const
Definition: Vector.h:264
A vector / dynamic array.
RangeList()
Definition: RangeList.h:39
void free(T address, T length, bool merge=true)
Definition: RangeList.h:163
Range getRange(size_t index) const
Definition: RangeList.h:348
bool allocate(T length, T &address)
Definition: RangeList.h:222
void dump(void(*emit_line)(const char *s)) const
Definition: RangeList.h:413
~RangeList()
Definition: RangeList.h:357
bool allocateSpecific(T address, T length)
Definition: RangeList.h:280
void sweep()
Definition: RangeList.h:373
An iterator applicable for many data structures.
Definition: Iterator.h:43
size_t size() const
Definition: Vector.h:258
void pushFront(const T &value)
Definition: Vector.h:293
bool operator==(const Iterator< originalT, Struct, FunctionPrev, FunctionNext, T1 > &x1, const Iterator< originalT, Struct, FunctionPrev, FunctionNext, T2 > &x2)
Definition: Iterator.h:326
Vector< Range * > m_List
Definition: RangeList.h:116
RangeList(bool preferUsed)
Definition: RangeList.h:43
void clear(bool freeMem=false)
Definition: Vector.h:337
void erase(size_t index)
Definition: Vector.h:350
RangeList(T Address, T Length, bool XXX, bool preferUsed=false)
Definition: RangeList.h:49
bool m_bPreferUsed
Definition: RangeList.h:119