Repository: google/filament
File: filament/src/FrameInfo.h (C/C++)

Code before:
    {
    }

    FrameInfoImpl& operator=(FrameInfoImpl&& rhs) noexcept {
        details::FrameInfo::operator=(rhs);
        frameId = rhs.frameId;
        beginFrame = rhs.beginFrame;
        endFrame = rhs.endFrame;
        backendBeginFrame = rhs.backendBeginFrame;
        backendEndFrame = rhs.backendEndFrame;
        gpuFrameComplete = rhs.gpuFrameComplete;
        vsync = rhs.vsync;
        fence = rhs.fence;
        ready.store(rhs.ready.load());
        return *this;
    }
};

template<typename T, size_t CAPACITY>
class CircularQueue {
public:
    using value_type = T;
    using reference = value_type&;
    using const_reference = value_type const&;

    class iterator {
    public:
        using iterator_category = std::forward_iterator_tag;
        using value_type = T;
        using difference_type = std::ptrdiff_t;
        using pointer = T*;
        using reference = T&;

        iterator() = default;
        iterator(CircularQueue* queue, size_t pos) noexcept : mQueue(queue), mPos(pos) {}

        reference operator*() const { return (*mQueue)[mPos]; }
        pointer operator->() const { return &(*mQueue)[mPos]; }
        iterator& operator++() { ++mPos; return *this; }
        iterator operator++(int) { iterator temp = *this; ++(*this); return temp; }
        friend bool operator==(const iterator& a, const iterator& b) { return a.mQueue == b.mQueue && a.mPos == b.mPos; }
        friend bool operator!=(const iterator& a, const iterator& b) { return !(a == b); }
    private:
        CircularQueue* mQueue = nullptr;
        size_t mPos = 0;
    };

    class const_iterator {
    public:
        using iterator_category = std::forward_iterator_tag;
        using value_type = const T;

Review comment (suggestion):
Could we make the iterator a templated class based on the pointer type (either `T*` or `const T*`)? This way we don't have duplication between `iterator` and `const_iterator`:

```
template<typename Ptr>
class iterator {
    ...
    using pointer = Ptr;
    ...
};
```

Code after:
    {
    }

    FrameInfoImpl& operator=(FrameInfoImpl&& rhs) noexcept {
        details::FrameInfo::operator=(rhs);
        frameId = rhs.frameId;
        beginFrame = rhs.beginFrame;
        endFrame = rhs.endFrame;
        backendBeginFrame = rhs.backendBeginFrame;
        backendEndFrame = rhs.backendEndFrame;
        gpuFrameComplete = rhs.gpuFrameComplete;
        vsync = rhs.vsync;
        fence = rhs.fence;
        ready.store(rhs.ready.load());
        return *this;
    }
};

template<typename T, size_t CAPACITY>
class CircularQueue {
public:
    using value_type = T;
    using reference = value_type&;
    using const_reference = value_type const&;

private:
    template<typename U>
    class Iterator {
    public:
        using iterator_category = std::forward_iterator_tag;
        using value_type = typename std::remove_const<T>::type;
        using difference_type = std::ptrdiff_t;
        using pointer = U*;
        using reference = U&;
        using QueuePtr = typename std::conditional<std::is_const<U>::value,
                const CircularQueue*, CircularQueue*>::type;

        Iterator() = default;
        Iterator(QueuePtr queue, size_t pos) noexcept : mQueue(queue), mPos(pos) {}

        // allow conversion from iterator to const_iterator
        operator Iterator<const T>() const { return { mQueue, mPos }; }

        reference operator*() const { return (*mQueue)[mPos]; }
        pointer operator->() const { return &(*mQueue)[mPos]; }
        Iterator& operator++() { ++mPos; return *this; }
        Iterator operator++(int) { Iterator temp = *this; ++(*this); return temp; }

        friend bool operator==(const Iterator& a, const Iterator& b) { return a.mQueue == b.mQueue && a.mPos == b.mPos; }
        friend bool operator!=(const Iterator& a, const Iterator& b) { return !(a == b); }