/** * Copyright 2020 Huawei Technologies Co., Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef DATASET_CYCLIC_ARRAY_H #define DATASET_CYCLIC_ARRAY_H #include #include #include #include #include "dataset/core/constants.h" namespace mindspore { namespace dataset { /// \class CyclicArray "include/cyclic_array.h /// \brief This is a container with a contiguous memory layout that pnly keeps N last entries, /// when the number of entries exceeds the capacity /// Must be preallocated template class CyclicArray { public: using value_type = T; class Iterator { // Add operator[] and make fully compliant with random access iterator // and add a const iterator // add resize(), empty() public: using iterator_category = std::random_access_iterator_tag; using value_type = CyclicArray::value_type; using difference_type = std::ptrdiff_t; using pointer = CyclicArray::value_type *; using reference = CyclicArray::value_type &; Iterator() = default; Iterator(dsize_t idx, pointer ptr, dsize_t capacity, dsize_t head) : cur_idx_(idx), ptr_(ptr), capacity_(capacity), head_(head) {} Iterator(const Iterator &rhs) = default; ~Iterator() = default; Iterator &operator++() { cur_idx_ = (cur_idx_ + 1) % (capacity_ + 1); return *this; } Iterator operator++(int) { Iterator tmp(*this); cur_idx_ = (cur_idx_ + 1) % (capacity_ + 1); return tmp; } Iterator &operator--() { cur_idx_ = (cur_idx_ + capacity_) % (capacity_ + 1); return *this; } Iterator operator--(int) { Iterator tmp(*this); cur_idx_ = (cur_idx_ + capacity_) % (capacity_ + 1); return tmp; } Iterator operator+(dsize_t x) { return Iterator((cur_idx_ + x) % (capacity_ + 1), ptr_, capacity_, head_); } Iterator operator-(dsize_t x) { return Iterator((cur_idx_ + (capacity_ + 1 - x)) % (capacity_ + 1), ptr_, capacity_, head_); } bool operator<(const Iterator &rhs) { return (head_ + cur_idx_) % (capacity_ + 1) < (rhs.head_ + rhs.cur_idx_) % (capacity_ + 1); } bool operator>(const Iterator &rhs) { return (head_ + cur_idx_) % (capacity_ + 1) > (rhs.head_ + rhs.cur_idx_) % (capacity_ + 1); } bool operator>=(const Iterator &rhs) { return (head_ + cur_idx_) % (capacity_ + 1) >= (rhs.head_ + rhs.cur_idx_) % (capacity_ + 1); } bool operator<=(const Iterator &rhs) { return (head_ + cur_idx_) % (capacity_ + 1) <= (rhs.head_ + rhs.cur_idx_) % (capacity_ + 1); } difference_type operator-(const Iterator &rhs) { return (cur_idx_ - rhs.cur_idx_ + capacity_ + 1) % (capacity_ + 1); } reference operator*() { return ptr_[cur_idx_]; } pointer operator->() { return &(ptr_[cur_idx_]); } bool operator==(const Iterator &rhs) { return cur_idx_ == rhs.cur_idx_; } bool operator!=(const Iterator &rhs) { return cur_idx_ != rhs.cur_idx_; } private: dsize_t cur_idx_; pointer ptr_; dsize_t capacity_; dsize_t head_; }; /// \brief Default constructor CyclicArray() : buf_(nullptr), head_(0), tail_(0), size_(0), capacity_(0) {} /// \brief Constructor /// \param[in] capacity explicit CyclicArray(dsize_t capacity) : buf_(std::make_unique(capacity + 1)), head_(0), tail_(0), size_(0), capacity_(capacity) {} CyclicArray(const CyclicArray &rhs) : buf_(std::make_unique(rhs.capacity_ + 1)), head_(rhs.head_), tail_(rhs.tail_), size_(rhs.size_), capacity_(rhs.capacity_) { std::copy(rhs.begin(), rhs.end(), begin()); } CyclicArray(CyclicArray &&rhs) = default; ~CyclicArray() = default; /// \brief Iterator begin() Iterator begin() { return Iterator(head_, buf_.get(), capacity_, head_); } /// \brief Iterator end() Iterator end() { return Iterator(tail_, buf_.get(), capacity_, head_); } // not really const. Iterator begin() const { return Iterator(head_, buf_.get(), capacity_, head_); } Iterator end() const { return Iterator(tail_, buf_.get(), capacity_, head_); } /// \brief clear the array. Does not deallocate memory, capacity remains the same void clear() { head_ = 0; tail_ = 0; size_ = 0; } /// \brief returns current size dsize_t size() { return size_; } /// \brief returns capacity dsize_t capacity() { return capacity_; } /// \brief pushes a value /// \param[in] val value void push_back(T val) { buf_[tail_] = val; if (size_ >= capacity_) { (tail_ != capacity_) ? tail_++ : tail_ = 0; (head_ != capacity_) ? head_++ : head_ = 0; } else { tail_++; size_++; } } /// \brief returns const reference to an element of the array /// \param[in] idx index of the element /// \param[out] const T& reference to an element of the array const T &operator[](dsize_t idx) const { return buf_[(head_ + idx) % (capacity_ + 1)]; } /// \brief returns non-const reference to an element of the array /// \param[in] idx index of the element /// \param[out] T& reference to an element of the array T &operator[](dsize_t idx) { return buf_[(head_ + idx) % (capacity_ + 1)]; } private: std::unique_ptr buf_; dsize_t head_; dsize_t tail_; dsize_t size_; dsize_t capacity_; }; } // namespace dataset } // namespace mindspore #endif // DATASET_CYCLIC_ARRAY_H