base: assert that stats bucket size is greater than 0
[gem5.git] / src / base / circlebuf.hh
index 66583b7dbab1fcac9d9ebdbaf54eb2ddc7f744ba..00aa37496d7fd8921263d3c4af50cbc29552d480 100644 (file)
@@ -1,6 +1,15 @@
 /*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
+ * Copyright (c) 2015,2017-2018 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Authors: Nathan Binkert
+ * Authors: Andreas Sandberg
  */
 
-#ifndef __CIRCLEBUF_HH__
-#define __CIRCLEBUF_HH__
+#ifndef __BASE_CIRCLEBUF_HH__
+#define __BASE_CIRCLEBUF_HH__
+
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+#include "base/circular_queue.hh"
+#include "base/logging.hh"
+#include "sim/serialize.hh"
+
+/**
+ * Circular buffer backed by a vector though a CircularQueue.
+ *
+ * The data in the cricular buffer is stored in a standard
+ * vector.
+ *
+ */
+template<typename T>
+class CircleBuf : public CircularQueue<T>
+{
+  public:
+    explicit CircleBuf(size_t size)
+        : CircularQueue<T>(size) {}
+    using CircularQueue<T>::empty;
+    using CircularQueue<T>::size;
+    using CircularQueue<T>::capacity;
+    using CircularQueue<T>::begin;
+    using CircularQueue<T>::end;
+    using CircularQueue<T>::pop_front;
+    using CircularQueue<T>::advance_tail;
+
+    /**
+     * Copy buffer contents without advancing the read pointer
+     *
+     * @param out Output iterator/pointer
+     * @param len Number of elements to copy
+     */
+    template <class OutputIterator>
+    void peek(OutputIterator out, size_t len) const {
+        peek(out, 0, len);
+    }
+
+    /**
+     * Copy buffer contents without advancing the read pointer
+     *
+     * @param out Output iterator/pointer
+     * @param offset Offset into the ring buffer
+     * @param len Number of elements to copy
+     */
+    template <class OutputIterator>
+    void peek(OutputIterator out, off_t offset, size_t len) const {
+        panic_if(offset + len > size(),
+                 "Trying to read past end of circular buffer.\n");
+
+        std::copy(begin() + offset, begin() + offset + len, out);
+    }
 
-#include <iosfwd>
+    /**
+     * Copy buffer contents and advance the read pointer
+     *
+     * @param out Output iterator/pointer
+     * @param len Number of elements to read
+     */
+    template <class OutputIterator>
+    void read(OutputIterator out, size_t len) {
+        peek(out, len);
+        pop_front(len);
+    }
 
-class CircleBuf
+    /**
+     * Add elements to the end of the ring buffers and advance.
+     *
+     * @param in Input iterator/pointer
+     * @param len Number of elements to read
+     */
+    template <class InputIterator>
+    void write(InputIterator in, size_t len) {
+        // Writes that are larger than the backing store are allowed,
+        // but only the last part of the buffer will be written.
+        if (len > capacity()) {
+            in += len - capacity();
+            len = capacity();
+        }
+
+        std::copy(in, in + len, end());
+        advance_tail(len);
+    }
+};
+
+/**
+ * Simple FIFO implementation backed by a circular buffer.
+ *
+ * This class provides the same basic functionallity as the circular
+ * buffer with the folling differences:
+ * <ul>
+ *    <li>Writes are checked to ensure that overflows can't happen.
+ *    <li>Unserialization ensures that the data in the checkpoint fits
+ *        in the buffer.
+ * </ul>
+ */
+template<typename T>
+class Fifo
 {
-  protected:
-    char *_buf;
-    bool _rollover;
-    int _buflen;
-    int _size;
-    int _start;
-    int _stop;
+  public:
+    typedef T value_type;
 
   public:
-    explicit CircleBuf(int l);
-    ~CircleBuf();
-
-    bool empty() const { return _size == 0; }
-    int size() const { return _size; }
-    void dump();
-    void flush();
-    void read(char *b, int len);
-    void read(int fd, int len);
-    void read(int fd);
-    void read(std::ostream &out);
-    void readall(int fd);
-    void write(char b);
-    void write(const char *b);
-    void write(const char *b, int len);
+    Fifo(size_t size)
+        : buf(size) {}
+
+    bool empty() const { return buf.empty(); }
+    size_t size() const { return buf.size(); }
+    size_t capacity() const { return buf.capacity(); }
+
+    void flush() { buf.flush(); }
+
+    template <class OutputIterator>
+    void peek(OutputIterator out, size_t len) const { buf.peek(out, len); }
+    template <class OutputIterator>
+    void read(OutputIterator out, size_t len) { buf.read(out, len); }
+
+    template <class InputIterator>
+    void write(InputIterator in, size_t len) {
+        panic_if(size() + len > capacity(),
+                 "Trying to overfill FIFO buffer.\n");
+        buf.write(in, len);
+    }
+
+  private:
+    CircleBuf<value_type> buf;
 };
 
-#endif // __CIRCLEBUF_HH__
+
+template <typename T>
+void
+arrayParamOut(CheckpointOut &cp, const std::string &name,
+              const CircleBuf<T> &param)
+{
+    std::vector<T> temp(param.size());
+    param.peek(temp.begin(), temp.size());
+    arrayParamOut(cp, name, temp);
+}
+
+template <typename T>
+void
+arrayParamIn(CheckpointIn &cp, const std::string &name,
+             CircleBuf<T> &param)
+{
+    std::vector<T> temp;
+    arrayParamIn(cp, name, temp);
+
+    param.flush();
+    param.write(temp.cbegin(), temp.size());
+}
+
+template <typename T>
+void
+arrayParamOut(CheckpointOut &cp, const std::string &name,
+              const Fifo<T> &param)
+{
+    std::vector<T> temp(param.size());
+    param.peek(temp.begin(), temp.size());
+    arrayParamOut(cp, name, temp);
+}
+
+template <typename T>
+void
+arrayParamIn(CheckpointIn &cp, const std::string &name,
+             Fifo<T> &param)
+{
+    std::vector<T> temp;
+    arrayParamIn(cp, name, temp);
+
+    fatal_if(param.capacity() < temp.size(),
+             "Trying to unserialize data into too small FIFO\n");
+
+    param.flush();
+    param.write(temp.cbegin(), temp.size());
+}
+
+#endif // __BASE_CIRCLEBUF_HH__