circlebuf.hh revision 12334
12SN/A/* 211008Sandreas.sandberg@arm.com * Copyright (c) 2015 ARM Limited 311008Sandreas.sandberg@arm.com * All rights reserved 411008Sandreas.sandberg@arm.com * 511008Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall 611008Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual 711008Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating 811008Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software 911008Sandreas.sandberg@arm.com * licensed hereunder. You may use the software subject to the license 1011008Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated 1111008Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software, 1211008Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form. 132SN/A * 142SN/A * Redistribution and use in source and binary forms, with or without 152SN/A * modification, are permitted provided that the following conditions are 162SN/A * met: redistributions of source code must retain the above copyright 172SN/A * notice, this list of conditions and the following disclaimer; 182SN/A * redistributions in binary form must reproduce the above copyright 192SN/A * notice, this list of conditions and the following disclaimer in the 202SN/A * documentation and/or other materials provided with the distribution; 212SN/A * neither the name of the copyright holders nor the names of its 222SN/A * contributors may be used to endorse or promote products derived from 232SN/A * this software without specific prior written permission. 242SN/A * 252SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362665Ssaidi@eecs.umich.edu * 3711008Sandreas.sandberg@arm.com * Authors: Andreas Sandberg 382SN/A */ 392SN/A 4011008Sandreas.sandberg@arm.com#ifndef __BASE_CIRCLEBUF_HH__ 4111008Sandreas.sandberg@arm.com#define __BASE_CIRCLEBUF_HH__ 422SN/A 4311008Sandreas.sandberg@arm.com#include <algorithm> 4411008Sandreas.sandberg@arm.com#include <cassert> 4511008Sandreas.sandberg@arm.com#include <vector> 462SN/A 4712334Sgabeblack@google.com#include "base/logging.hh" 4811008Sandreas.sandberg@arm.com#include "sim/serialize.hh" 4911008Sandreas.sandberg@arm.com 5011008Sandreas.sandberg@arm.com/** 5111008Sandreas.sandberg@arm.com * Circular buffer backed by a vector 5211008Sandreas.sandberg@arm.com * 5311008Sandreas.sandberg@arm.com * The data in the cricular buffer is stored in a standard 5411008Sandreas.sandberg@arm.com * vector. _start designates the first element in the buffer and _stop 5511008Sandreas.sandberg@arm.com * points to the last element + 1 (i.e., the position of the next 5611008Sandreas.sandberg@arm.com * insertion). The _stop index may be outside the range of the backing 5711008Sandreas.sandberg@arm.com * store, which means that the actual index must be calculated as 5811008Sandreas.sandberg@arm.com * _stop % capacity. 5911008Sandreas.sandberg@arm.com * 6011008Sandreas.sandberg@arm.com * Invariants: 6111008Sandreas.sandberg@arm.com * <ul> 6211008Sandreas.sandberg@arm.com * <li>_start <= _stop 6311008Sandreas.sandberg@arm.com * <li>_start < capacity 6411008Sandreas.sandberg@arm.com * <li>_stop < 2 * capacity 6511008Sandreas.sandberg@arm.com * </ul> 6611008Sandreas.sandberg@arm.com */ 6711008Sandreas.sandberg@arm.comtemplate<typename T> 682SN/Aclass CircleBuf 692SN/A{ 7011008Sandreas.sandberg@arm.com public: 7111008Sandreas.sandberg@arm.com typedef T value_type; 722SN/A 73317SN/A public: 7411008Sandreas.sandberg@arm.com explicit CircleBuf(size_t size) 7511008Sandreas.sandberg@arm.com : buf(size), _start(0), _stop(0) {} 762SN/A 7711008Sandreas.sandberg@arm.com /** Is the buffer empty? */ 7811008Sandreas.sandberg@arm.com bool empty() const { return _stop == _start; } 7911008Sandreas.sandberg@arm.com /** 8011008Sandreas.sandberg@arm.com * Return the maximum number of elements that can be stored in 8111008Sandreas.sandberg@arm.com * the buffer at any one time. 8211008Sandreas.sandberg@arm.com */ 8311008Sandreas.sandberg@arm.com size_t capacity() const { return buf.size(); } 8411008Sandreas.sandberg@arm.com /** Return the number of elements stored in the buffer. */ 8511008Sandreas.sandberg@arm.com size_t size() const { return _stop - _start; } 8611008Sandreas.sandberg@arm.com 8711008Sandreas.sandberg@arm.com /** 8811008Sandreas.sandberg@arm.com * Remove all the elements in the buffer. 8911008Sandreas.sandberg@arm.com * 9011008Sandreas.sandberg@arm.com * Note: This does not actually remove elements from the backing 9111008Sandreas.sandberg@arm.com * store. 9211008Sandreas.sandberg@arm.com */ 9311008Sandreas.sandberg@arm.com void flush() { 9411008Sandreas.sandberg@arm.com _start = 0; 9511008Sandreas.sandberg@arm.com _stop = 0; 9611008Sandreas.sandberg@arm.com } 9711008Sandreas.sandberg@arm.com 9811008Sandreas.sandberg@arm.com /** 9911008Sandreas.sandberg@arm.com * Copy buffer contents without advancing the read pointer 10011008Sandreas.sandberg@arm.com * 10111008Sandreas.sandberg@arm.com * @param out Output iterator/pointer 10211008Sandreas.sandberg@arm.com * @param len Number of elements to copy 10311008Sandreas.sandberg@arm.com */ 10411008Sandreas.sandberg@arm.com template <class OutputIterator> 10511008Sandreas.sandberg@arm.com void peek(OutputIterator out, size_t len) const { 10611460Sandreas.sandberg@arm.com peek(out, 0, len); 10711460Sandreas.sandberg@arm.com } 10811460Sandreas.sandberg@arm.com 10911460Sandreas.sandberg@arm.com /** 11011460Sandreas.sandberg@arm.com * Copy buffer contents without advancing the read pointer 11111460Sandreas.sandberg@arm.com * 11211460Sandreas.sandberg@arm.com * @param out Output iterator/pointer 11311460Sandreas.sandberg@arm.com * @param offset Offset into the ring buffer 11411460Sandreas.sandberg@arm.com * @param len Number of elements to copy 11511460Sandreas.sandberg@arm.com */ 11611460Sandreas.sandberg@arm.com template <class OutputIterator> 11711460Sandreas.sandberg@arm.com void peek(OutputIterator out, off_t offset, size_t len) const { 11811460Sandreas.sandberg@arm.com panic_if(offset + len > size(), 11911008Sandreas.sandberg@arm.com "Trying to read past end of circular buffer.\n"); 12011008Sandreas.sandberg@arm.com 12111460Sandreas.sandberg@arm.com const off_t real_start((offset + _start) % buf.size()); 12211460Sandreas.sandberg@arm.com if (real_start + len <= buf.size()) { 12311460Sandreas.sandberg@arm.com std::copy(buf.begin() + real_start, 12411460Sandreas.sandberg@arm.com buf.begin() + real_start + len, 12511008Sandreas.sandberg@arm.com out); 12611008Sandreas.sandberg@arm.com } else { 12711460Sandreas.sandberg@arm.com const size_t head_size(buf.size() - real_start); 12811008Sandreas.sandberg@arm.com const size_t tail_size(len - head_size); 12911460Sandreas.sandberg@arm.com std::copy(buf.begin() + real_start, buf.end(), 13011008Sandreas.sandberg@arm.com out); 13111008Sandreas.sandberg@arm.com std::copy(buf.begin(), buf.begin() + tail_size, 13211008Sandreas.sandberg@arm.com out + head_size); 13311008Sandreas.sandberg@arm.com } 13411008Sandreas.sandberg@arm.com } 13511008Sandreas.sandberg@arm.com 13611008Sandreas.sandberg@arm.com /** 13711008Sandreas.sandberg@arm.com * Copy buffer contents and advance the read pointer 13811008Sandreas.sandberg@arm.com * 13911008Sandreas.sandberg@arm.com * @param out Output iterator/pointer 14011008Sandreas.sandberg@arm.com * @param len Number of elements to read 14111008Sandreas.sandberg@arm.com */ 14211008Sandreas.sandberg@arm.com template <class OutputIterator> 14311008Sandreas.sandberg@arm.com void read(OutputIterator out, size_t len) { 14411008Sandreas.sandberg@arm.com peek(out, len); 14511008Sandreas.sandberg@arm.com 14611008Sandreas.sandberg@arm.com _start += len; 14711008Sandreas.sandberg@arm.com normalize(); 14811008Sandreas.sandberg@arm.com } 14911008Sandreas.sandberg@arm.com 15011008Sandreas.sandberg@arm.com /** 15111008Sandreas.sandberg@arm.com * Add elements to the end of the ring buffers and advance. 15211008Sandreas.sandberg@arm.com * 15311008Sandreas.sandberg@arm.com * @param in Input iterator/pointer 15411008Sandreas.sandberg@arm.com * @param len Number of elements to read 15511008Sandreas.sandberg@arm.com */ 15611008Sandreas.sandberg@arm.com template <class InputIterator> 15711008Sandreas.sandberg@arm.com void write(InputIterator in, size_t len) { 15811008Sandreas.sandberg@arm.com // Writes that are larger than the backing store are allowed, 15911008Sandreas.sandberg@arm.com // but only the last part of the buffer will be written. 16011008Sandreas.sandberg@arm.com if (len > buf.size()) { 16111008Sandreas.sandberg@arm.com in += len - buf.size(); 16211008Sandreas.sandberg@arm.com len = buf.size(); 16311008Sandreas.sandberg@arm.com } 16411008Sandreas.sandberg@arm.com 16511008Sandreas.sandberg@arm.com const size_t next(_stop % buf.size()); 16611008Sandreas.sandberg@arm.com const size_t head_len(std::min(buf.size() - next, len)); 16711008Sandreas.sandberg@arm.com 16811008Sandreas.sandberg@arm.com std::copy(in, in + head_len, buf.begin() + next); 16911008Sandreas.sandberg@arm.com std::copy(in + head_len, in + len, buf.begin()); 17011008Sandreas.sandberg@arm.com 17111008Sandreas.sandberg@arm.com _stop += len; 17211008Sandreas.sandberg@arm.com // We may have written past the old _start pointer. Readjust 17311008Sandreas.sandberg@arm.com // the _start pointer to remove the oldest entries in that 17411008Sandreas.sandberg@arm.com // case. 17511008Sandreas.sandberg@arm.com if (size() > buf.size()) 17611008Sandreas.sandberg@arm.com _start = _stop - buf.size(); 17711008Sandreas.sandberg@arm.com 17811008Sandreas.sandberg@arm.com normalize(); 17911008Sandreas.sandberg@arm.com } 18011008Sandreas.sandberg@arm.com 18111008Sandreas.sandberg@arm.com protected: 18211008Sandreas.sandberg@arm.com /** 18311008Sandreas.sandberg@arm.com * Normalize the start and stop pointers to ensure that pointer 18411008Sandreas.sandberg@arm.com * invariants hold after updates. 18511008Sandreas.sandberg@arm.com */ 18611008Sandreas.sandberg@arm.com void normalize() { 18711008Sandreas.sandberg@arm.com if (_start >= buf.size()) { 18811008Sandreas.sandberg@arm.com _stop -= buf.size(); 18911008Sandreas.sandberg@arm.com _start -= buf.size(); 19011008Sandreas.sandberg@arm.com } 19111008Sandreas.sandberg@arm.com 19211008Sandreas.sandberg@arm.com assert(_start < buf.size()); 19311008Sandreas.sandberg@arm.com assert(_stop < 2 * buf.size()); 19411008Sandreas.sandberg@arm.com assert(_start <= _stop); 19511008Sandreas.sandberg@arm.com } 19611008Sandreas.sandberg@arm.com 19711008Sandreas.sandberg@arm.com protected: 19811008Sandreas.sandberg@arm.com std::vector<value_type> buf; 19911008Sandreas.sandberg@arm.com size_t _start; 20011008Sandreas.sandberg@arm.com size_t _stop; 20111008Sandreas.sandberg@arm.com 2022SN/A}; 2032SN/A 20411008Sandreas.sandberg@arm.com 20511008Sandreas.sandberg@arm.com/** 20611008Sandreas.sandberg@arm.com * Simple FIFO implementation backed by a circular buffer. 20711008Sandreas.sandberg@arm.com * 20811008Sandreas.sandberg@arm.com * This class provides the same basic functionallity as the circular 20911008Sandreas.sandberg@arm.com * buffer with the folling differences: 21011008Sandreas.sandberg@arm.com * <ul> 21111008Sandreas.sandberg@arm.com * <li>Writes are checked to ensure that overflows can't happen. 21211008Sandreas.sandberg@arm.com * <li>Unserialization ensures that the data in the checkpoint fits 21311008Sandreas.sandberg@arm.com * in the buffer. 21411008Sandreas.sandberg@arm.com * </ul> 21511008Sandreas.sandberg@arm.com */ 21611008Sandreas.sandberg@arm.comtemplate<typename T> 21711008Sandreas.sandberg@arm.comclass Fifo 21811008Sandreas.sandberg@arm.com{ 21911008Sandreas.sandberg@arm.com public: 22011008Sandreas.sandberg@arm.com typedef T value_type; 22111008Sandreas.sandberg@arm.com 22211008Sandreas.sandberg@arm.com public: 22311008Sandreas.sandberg@arm.com Fifo(size_t size) 22411008Sandreas.sandberg@arm.com : buf(size) {} 22511008Sandreas.sandberg@arm.com 22611008Sandreas.sandberg@arm.com bool empty() const { return buf.empty(); } 22711008Sandreas.sandberg@arm.com size_t size() const { return buf.size(); } 22811008Sandreas.sandberg@arm.com size_t capacity() const { return buf.capacity(); } 22911008Sandreas.sandberg@arm.com 23011008Sandreas.sandberg@arm.com void flush() { buf.flush(); } 23111008Sandreas.sandberg@arm.com 23211008Sandreas.sandberg@arm.com template <class OutputIterator> 23311008Sandreas.sandberg@arm.com void peek(OutputIterator out, size_t len) const { buf.peek(out, len); } 23411008Sandreas.sandberg@arm.com template <class OutputIterator> 23511008Sandreas.sandberg@arm.com void read(OutputIterator out, size_t len) { buf.read(out, len); } 23611008Sandreas.sandberg@arm.com 23711008Sandreas.sandberg@arm.com template <class InputIterator> 23811008Sandreas.sandberg@arm.com void write(InputIterator in, size_t len) { 23911008Sandreas.sandberg@arm.com panic_if(size() + len > capacity(), 24011008Sandreas.sandberg@arm.com "Trying to overfill FIFO buffer.\n"); 24111008Sandreas.sandberg@arm.com buf.write(in, len); 24211008Sandreas.sandberg@arm.com } 24311008Sandreas.sandberg@arm.com 24411008Sandreas.sandberg@arm.com private: 24511008Sandreas.sandberg@arm.com CircleBuf<value_type> buf; 24611008Sandreas.sandberg@arm.com}; 24711008Sandreas.sandberg@arm.com 24811008Sandreas.sandberg@arm.com 24911008Sandreas.sandberg@arm.comtemplate <typename T> 25012032Sandreas.sandberg@arm.comvoid 25111008Sandreas.sandberg@arm.comarrayParamOut(CheckpointOut &cp, const std::string &name, 25211008Sandreas.sandberg@arm.com const CircleBuf<T> ¶m) 25311008Sandreas.sandberg@arm.com{ 25411008Sandreas.sandberg@arm.com std::vector<T> temp(param.size()); 25511008Sandreas.sandberg@arm.com param.peek(temp.begin(), temp.size()); 25611008Sandreas.sandberg@arm.com arrayParamOut(cp, name, temp); 25711008Sandreas.sandberg@arm.com} 25811008Sandreas.sandberg@arm.com 25911008Sandreas.sandberg@arm.comtemplate <typename T> 26012032Sandreas.sandberg@arm.comvoid 26111008Sandreas.sandberg@arm.comarrayParamIn(CheckpointIn &cp, const std::string &name, 26211008Sandreas.sandberg@arm.com CircleBuf<T> ¶m) 26311008Sandreas.sandberg@arm.com{ 26411008Sandreas.sandberg@arm.com std::vector<T> temp; 26511008Sandreas.sandberg@arm.com arrayParamIn(cp, name, temp); 26611008Sandreas.sandberg@arm.com 26711008Sandreas.sandberg@arm.com param.flush(); 26811008Sandreas.sandberg@arm.com param.write(temp.cbegin(), temp.size()); 26911008Sandreas.sandberg@arm.com} 27011008Sandreas.sandberg@arm.com 27111008Sandreas.sandberg@arm.comtemplate <typename T> 27212032Sandreas.sandberg@arm.comvoid 27311008Sandreas.sandberg@arm.comarrayParamOut(CheckpointOut &cp, const std::string &name, 27411008Sandreas.sandberg@arm.com const Fifo<T> ¶m) 27511008Sandreas.sandberg@arm.com{ 27611008Sandreas.sandberg@arm.com std::vector<T> temp(param.size()); 27711008Sandreas.sandberg@arm.com param.peek(temp.begin(), temp.size()); 27811008Sandreas.sandberg@arm.com arrayParamOut(cp, name, temp); 27911008Sandreas.sandberg@arm.com} 28011008Sandreas.sandberg@arm.com 28111008Sandreas.sandberg@arm.comtemplate <typename T> 28212032Sandreas.sandberg@arm.comvoid 28311008Sandreas.sandberg@arm.comarrayParamIn(CheckpointIn &cp, const std::string &name, 28411008Sandreas.sandberg@arm.com Fifo<T> ¶m) 28511008Sandreas.sandberg@arm.com{ 28611008Sandreas.sandberg@arm.com std::vector<T> temp; 28711008Sandreas.sandberg@arm.com arrayParamIn(cp, name, temp); 28811008Sandreas.sandberg@arm.com 28911008Sandreas.sandberg@arm.com fatal_if(param.capacity() < temp.size(), 29011008Sandreas.sandberg@arm.com "Trying to unserialize data into too small FIFO\n"); 29111008Sandreas.sandberg@arm.com 29211008Sandreas.sandberg@arm.com param.flush(); 29311008Sandreas.sandberg@arm.com param.write(temp.cbegin(), temp.size()); 29411008Sandreas.sandberg@arm.com} 29511008Sandreas.sandberg@arm.com 29611008Sandreas.sandberg@arm.com#endif // __BASE_CIRCLEBUF_HH__ 297