| //===-- esan_circular_buffer.h ----------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file is a part of EfficiencySanitizer, a family of performance tuners. |
| // |
| // Circular buffer data structure. |
| //===----------------------------------------------------------------------===// |
| |
| #include "sanitizer_common/sanitizer_common.h" |
| |
| namespace __esan { |
| |
| // A circular buffer for POD data whose memory is allocated using mmap. |
| // There are two usage models: one is to use initialize/free (for global |
| // instances) and the other is to use placement new with the |
| // constructor and to call the destructor or free (they are equivalent). |
| template<typename T> |
| class CircularBuffer { |
| public: |
| // To support global instances we cannot initialize any field in the |
| // default constructor. |
| explicit CircularBuffer() {} |
| CircularBuffer(uptr BufferCapacity) { |
| initialize(BufferCapacity); |
| WasConstructed = true; |
| } |
| ~CircularBuffer() { |
| if (WasConstructed) // Else caller will call free() explicitly. |
| free(); |
| } |
| void initialize(uptr BufferCapacity) { |
| Capacity = BufferCapacity; |
| // MmapOrDie rounds up to the page size for us. |
| Data = (T *)MmapOrDie(Capacity * sizeof(T), "CircularBuffer"); |
| StartIdx = 0; |
| Count = 0; |
| WasConstructed = false; |
| } |
| void free() { |
| UnmapOrDie(Data, Capacity * sizeof(T)); |
| } |
| T &operator[](uptr Idx) { |
| CHECK_LT(Idx, Count); |
| uptr ArrayIdx = (StartIdx + Idx) % Capacity; |
| return Data[ArrayIdx]; |
| } |
| const T &operator[](uptr Idx) const { |
| CHECK_LT(Idx, Count); |
| uptr ArrayIdx = (StartIdx + Idx) % Capacity; |
| return Data[ArrayIdx]; |
| } |
| void push_back(const T &Item) { |
| CHECK_GT(Capacity, 0); |
| uptr ArrayIdx = (StartIdx + Count) % Capacity; |
| Data[ArrayIdx] = Item; |
| if (Count < Capacity) |
| ++Count; |
| else |
| StartIdx = (StartIdx + 1) % Capacity; |
| } |
| T &back() { |
| CHECK_GT(Count, 0); |
| uptr ArrayIdx = (StartIdx + Count - 1) % Capacity; |
| return Data[ArrayIdx]; |
| } |
| void pop_back() { |
| CHECK_GT(Count, 0); |
| --Count; |
| } |
| uptr size() const { |
| return Count; |
| } |
| void clear() { |
| StartIdx = 0; |
| Count = 0; |
| } |
| bool empty() const { return size() == 0; } |
| |
| private: |
| CircularBuffer(const CircularBuffer&); |
| void operator=(const CircularBuffer&); |
| |
| bool WasConstructed; |
| T *Data; |
| uptr Capacity; |
| uptr StartIdx; |
| uptr Count; |
| }; |
| |
| } // namespace __esan |