Skip to content

File Stack.h

File List > external-docs > libDaisy > src > util > Stack.h

Go to the documentation of this file

Source Code

#pragma once

#include <stdint.h>
#include <stddef.h>
#include <initializer_list>

namespace daisy
{
template <typename T>
class StackBase
{
  protected:
    StackBase(T* buffer, size_t bufferSize)
    : buffer_(buffer), bufferSize_(bufferSize), bufferHead_(0)
    {
    }

    StackBase(T*                       buffer,
              size_t                   bufferSize,
              std::initializer_list<T> valuesToAdd)
    : buffer_(buffer), bufferSize_(bufferSize), bufferHead_(0)
    {
        PushBack(valuesToAdd);
    }

  public:
    StackBase<T>& operator=(const StackBase<T>& other)
    {
        bufferHead_ = 0;
        if(!other.IsEmpty())
        {
            const auto numCopy = (other.GetNumElements() < bufferSize_)
                                     ? other.GetNumElements()
                                     : bufferSize_;
            for(size_t i = 0; i < numCopy; i++)
                buffer_[i] = other[i];
            bufferHead_ = other.GetNumElements();
        }
        return *this;
    }

    ~StackBase() {}

    bool PushBack(const T& elementToAdd)
    {
        if(!IsFull())
        {
            buffer_[bufferHead_++] = elementToAdd;
            return true;
        }
        return false;
    }

    int PushBack(std::initializer_list<T> valuesToAdd)
    {
        int numAdded = 0;
        for(const auto& v : valuesToAdd)
        {
            if(IsFull())
                return numAdded;

            PushBack(v);
            numAdded++;
        }
        return numAdded;
    }

    T PopBack()
    {
        if(IsEmpty())
            return T();
        else
        {
            return buffer_[--bufferHead_];
        }
    }

    void Clear() { bufferHead_ = 0; }

    T& operator[](uint32_t idx) { return buffer_[idx]; }
    const T& operator[](uint32_t idx) const { return buffer_[idx]; }

    bool Remove(uint32_t idx)
    {
        if(idx >= bufferHead_)
            return false;

        for(uint32_t i = idx; i < bufferHead_ - 1; i++)
        {
            buffer_[i] = buffer_[i + 1];
        }
        bufferHead_--;
        return true;
    }

    int RemoveAllEqualTo(const T& element)
    {
        int numRemoved = 0;
        int idx        = bufferHead_ - 1;
        while(idx >= 0)
        {
            if(buffer_[idx] == element)
            {
                numRemoved++;
                Remove(idx);
                // was that the last element?
                if(decltype(bufferHead_)(idx) == bufferHead_)
                    idx--;
            }
            else
                idx--;
        }
        return numRemoved;
    }

    bool Insert(uint32_t idx, const T& item)
    {
        if(bufferHead_ >= bufferSize_)
            return false;
        if(idx > bufferHead_)
            return false;
        if(idx == bufferHead_)
        {
            buffer_[bufferHead_++] = item;
            return true;
        }

        for(uint32_t i = bufferHead_ - 1; i >= idx; i--)
        {
            buffer_[i + 1] = buffer_[i];
        }
        buffer_[idx] = item;
        bufferHead_++;
        return true;
    }

    bool Contains(const T& element)
    {
        int idx = bufferHead_ - 1;
        while(idx >= 0)
        {
            if(buffer_[idx] == element)
                return true;
            idx--;
        }
        return false;
    }

    size_t CountEqualTo(const T& element)
    {
        size_t result = 0;
        int    idx    = bufferHead_ - 1;
        while(idx >= 0)
        {
            if(buffer_[idx] == element)
                result++;
            idx--;
        }
        return result;
    }

    bool IsEmpty() const { return bufferHead_ == 0; }

    bool IsFull() const { return bufferHead_ == bufferSize_; }

    size_t GetNumElements() const { return bufferHead_; }

    size_t GetCapacity() const { return bufferSize_; }

  private:
    T*           buffer_;
    const size_t bufferSize_;
    size_t       bufferHead_;
};

template <typename T, size_t capacity>
class Stack : public StackBase<T>
{
  public:
    Stack() : StackBase<T>(buffer_, capacity) {}

    explicit Stack(std::initializer_list<T> valuesToAdd)
    : StackBase<T>(buffer_, capacity, valuesToAdd)
    {
    }

    template <size_t otherCapacity>
    Stack(const Stack<T, otherCapacity>& other)
    : StackBase<T>(buffer_, capacity)
    {
        *this = other;
    }

    template <size_t otherCapacity>
    Stack<T, capacity>& operator=(const Stack<T, otherCapacity>& other)
    {
        StackBase<T>::operator=(other);
        return *this;
    }

  private:
    T buffer_[capacity];
};

} // namespace daisy