// Copyright 2011 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef GESTURES_VECTOR_H__
#define GESTURES_VECTOR_H__

#include <algorithm>

#include "include/logging.h"

namespace gestures {

// This class allows range-based for loops to iterate over a subset of
// array elements, by only yielding those elements for which the
// AcceptMethod returns true.
// This class wraps around a pair of iterators, all changes to the
// yielded elements will modify the original array.
template <typename ValueType>
class FilteredRange {
 public:
  typedef bool (*AcceptMethod)(const ValueType&);

  // This class defineds a basic forward iterator that iterates over
  // an array but skips elements for which the AcceptMethod yields false.
  class RangeIterator {
   public:
    // creates a new iterator and advances to the first accepted
    // element in the array.
    RangeIterator(ValueType* i, ValueType* end, AcceptMethod accept)
        : iter_(i), end_(end), accept_(accept) {
      NextAcceptedIter();
    }

    // operator++ is required by the STL for forward iterators.
    // Instead of advancing to the next array element, this iterator
    // will advance to the next accepted array element
    ValueType* operator++ () {
      ++iter_;
      NextAcceptedIter();
      return iter_;
    }

    // operator* is required by the STL for forward iterators.
    ValueType& operator*() {
      return *iter_;
    }

    // operator-> is required by the STL for forward iterators.
    ValueType& operator->() {
      return *iter_;
    }

    // operator!= is required by the STL for forward iterators.
    bool operator!= (const RangeIterator& o) {
      return iter_ != o.iter_;
    }

    // operator== is required by the STL for forward iterators.
    bool operator== (const RangeIterator& o) {
      return iter_ == o.iter_;
    }

   private:
    void NextAcceptedIter() {
      while (!accept_(*iter_) && iter_ != end_)
        ++iter_;
    }

    ValueType* iter_;
    ValueType* end_;
    AcceptMethod accept_;
  };

  // Create a new filtered range from begin/end pointer to an array.
  FilteredRange(ValueType* begin, ValueType* end, AcceptMethod accept)
      : begin_(begin), end_(end), accept_(accept) {}

  // Returns a forward iterator to the first accepted element of the array.
  RangeIterator begin() {
    return RangeIterator(begin_, end_, accept_);
  }

  // Returns an iterator to the element after the last element of the array.
  RangeIterator end() {
    return RangeIterator(end_, end_, accept_);
  }

 private:
  ValueType* begin_;
  ValueType* end_;
  AcceptMethod accept_;
};

// The vector class mimicks a subset of the std::vector functionality
// while using a fixed size of memory to avoid calls to malloc/free.
// The limitations of this class are:
// - All insert operations might invalidate existing iterators
// - Currently, the ValueType type should be a POD type or aggregate of PODs,
//   since ctors/dtors aren't called propertly on ValueType objects.
// - Out of range element access will always return the end() iterator
//   and print an error, instead of throwing an exception.
// This class includes a non-standard extension to return a
// FilteredRange object iterating over the underlying array.
template<typename ValueType, size_t kMaxSize>
class vector {
 public:
  typedef ValueType value_type;
  typedef ValueType* iterator;
  typedef const ValueType* const_iterator;
  typedef std::reverse_iterator<iterator> reverse_iterator;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  typedef bool (*AcceptMethod)(const ValueType&);

  vector() : size_(0) {}
  vector(const vector<ValueType, kMaxSize>& that) {
    *this = that;
  }
  template<size_t kThatSize>
  vector(const vector<ValueType, kThatSize>& that) {
    *this = that;
  }

  size_t size() const { return size_; }
  bool empty() const { return size() == 0; }

  // methods for const element access

  const_iterator begin() const { return buffer_; }
  const_iterator end() const { return &buffer_[size_]; }
  const_reverse_iterator rbegin() const {
    return const_reverse_iterator(end());
  }
  const_reverse_iterator rend() const {
    return const_reverse_iterator(begin());
  }
  const_iterator find(const ValueType& value) const {
    for (size_t i = 0; i < size_; ++i)
      if (buffer_[i] == value)
        return const_iterator(&buffer_[i]);
    return end();
  }
  const ValueType& at(size_t idx) const {
    if (idx >= size()) {
      Err("vector::at: index out of range");
      idx = size() - 1;
    }
    return buffer_[idx];
  }
  const ValueType& operator[](size_t idx) const { return buffer_[idx]; }

  // methods for non-const element access:

  iterator begin() { return buffer_; }
  iterator end() { return &buffer_[size_]; }
  reverse_iterator rbegin() { return reverse_iterator(end()); }
  reverse_iterator rend() { return reverse_iterator(begin()); }
  iterator find(const ValueType& value) {
    return const_cast<iterator>(
        const_cast<const vector<ValueType, kMaxSize>*>(this)->find(value));
  }
  ValueType& at(size_t idx) {
    return const_cast<ValueType&>(
        const_cast<const vector<ValueType, kMaxSize>*>(this)->at(idx));
  }
  ValueType& operator[](size_t idx) { return buffer_[idx]; }

  // methods for inserting elements
  // note that all these methods might invalidate existing iterators

  void push_back(const ValueType& value) {
    insert(end(), value);
  }

  iterator insert(iterator position, const ValueType& value) {
    return insert(position, &value, (&value) + 1);
  }

  iterator insert(iterator position, const_iterator first,
                  const_iterator last) {
    size_t count = last - first;
    if (size_ + count > kMaxSize) {
      Err("vector::insert: out of space!");
      return end();
    }

    std::copy(rbegin(), reverse_iterator(position),
              reverse_iterator(end() + count));
    size_ = size_ + count;
    std::copy(first, last, position);
    return position;
  }

  // methods for erasing elements
  // note that all these methods might invalidate existing iterators

  iterator erase(iterator it) {
    return erase(it, it + 1);
  }

  iterator erase(iterator first, iterator last) {
    size_t count = last - first;
    std::copy(last, end(), first);
    for (iterator it = end() - count, e = end(); it != e; ++it)
      (*it).~ValueType();
    size_ = size_ - count;
    return first;
  }

  void clear() {
    erase(begin(), end());
  }

  template<size_t kThatSize>
  vector<ValueType, kMaxSize>& operator=(
      const vector<ValueType, kThatSize>& that) {
    clear();
    insert(begin(), that.begin(), that.end());
    return *this;
  }

 private:
  ValueType buffer_[kMaxSize];
  size_t size_;
};

}  // namespace gestures

#endif  // GESTURES_VECTOR_H__
