blob: 32f0d3fff7ad6a266a56384eb7864b8842b0a185 [file] [log] [blame]
Kostya Serebryanyd709a362018-08-29 21:00:01 +00001//===-- sanitizer_ring_buffer.h ---------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Simple ring buffer.
11//
12//===----------------------------------------------------------------------===//
13#ifndef SANITIZER_RING_BUFFER_H
14#define SANITIZER_RING_BUFFER_H
15
16#include "sanitizer_common.h"
17
18namespace __sanitizer {
19// RingBuffer<T>: fixed-size ring buffer optimized for speed of push().
20// T should be a POD type and sizeof(T) should be divisible by sizeof(void*).
21// At creation, all elements are zero.
22template<class T>
23class RingBuffer {
24 public:
25 COMPILER_CHECK(sizeof(T) % sizeof(void *) == 0);
26 static RingBuffer *New(uptr Size) {
27 void *Ptr = MmapOrDie(SizeInBytes(Size), "RingBuffer");
28 RingBuffer *RB = reinterpret_cast<RingBuffer*>(Ptr);
29 uptr End = reinterpret_cast<uptr>(Ptr) + SizeInBytes(Size);
30 RB->last_ = RB->next_ = reinterpret_cast<T*>(End - sizeof(T));
31 return RB;
32 }
33 void Delete() {
34 UnmapOrDie(this, SizeInBytes(size()));
35 }
36 uptr size() const {
37 return last_ + 1 -
38 reinterpret_cast<T *>(reinterpret_cast<uptr>(this) +
39 2 * sizeof(T *));
40 }
Kostya Serebryany68902c72018-09-05 23:52:31 +000041
42 uptr SizeInBytes() { return SizeInBytes(size()); }
43
Kostya Serebryanyd709a362018-08-29 21:00:01 +000044 void push(T t) {
45 *next_ = t;
46 next_--;
47 // The condition below works only if sizeof(T) is divisible by sizeof(T*).
48 if (next_ <= reinterpret_cast<T*>(&next_))
49 next_ = last_;
50 }
51
52 T operator[](uptr Idx) const {
53 CHECK_LT(Idx, size());
54 sptr IdxNext = Idx + 1;
55 if (IdxNext > last_ - next_)
56 IdxNext -= size();
57 return next_[IdxNext];
58 }
59
60 private:
61 RingBuffer() {}
62 ~RingBuffer() {}
63 RingBuffer(const RingBuffer&) = delete;
64
65 static uptr SizeInBytes(uptr Size) {
66 return Size * sizeof(T) + 2 * sizeof(T*);
67 }
68
69 // Data layout:
70 // LNDDDDDDDD
71 // D: data elements.
72 // L: last_, always points to the last data element.
73 // N: next_, initially equals to last_, is decremented on every push,
74 // wraps around if it's less or equal than its own address.
75
76 T *last_;
77 T *next_;
78 T data_[1]; // flexible array.
79};
80
81} // namespace __sanitizer
82
83#endif // SANITIZER_RING_BUFFER_H