// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_GN_DEPS_ITERATOR_H_
#define TOOLS_GN_DEPS_ITERATOR_H_

#include <stddef.h>

#include "gn/label_ptr.h"

// Provides an iterator for iterating over multiple LabelTargetVectors to
// make it convenient to iterate over all deps of a target.
//
// This works by maintaining a simple stack of vectors (since we have a fixed
// number of deps types). When the stack is empty, we've reached the end. This
// means that the default-constructed iterator == end() for any sequence.
class DepsIterator {
 public:
  // Creates an empty iterator.
  DepsIterator();

  // Iterate over the deps in the given vectors. If passing less than three,
  // pad with nulls.
  DepsIterator(const LabelTargetVector* a,
               const LabelTargetVector* b,
               const LabelTargetVector* c);

  // Prefix increment operator. This assumes there are more items (i.e.
  // *this != DepsIterator()).
  //
  // For internal use, this function tolerates an initial index equal to the
  // length of the current vector. In this case, it will advance to the next
  // one.
  DepsIterator& operator++();

  // Comparison for STL-based loops.
  bool operator!=(const DepsIterator& other) const {
    return current_index_ != other.current_index_ ||
           vect_stack_[0] != other.vect_stack_[0] ||
           vect_stack_[1] != other.vect_stack_[1] ||
           vect_stack_[2] != other.vect_stack_[2];
  }

  // Dereference operator for STL-compatible iterators.
  const LabelTargetPair& operator*() const {
    DCHECK_LT(current_index_, vect_stack_[0]->size());
    return (*vect_stack_[0])[current_index_];
  }

 private:
  const LabelTargetVector* vect_stack_[3];

  size_t current_index_;
};

// Provides a virtual container implementing begin() and end() for a
// sequence of deps. This can then be used in range-based for loops.
class DepsIteratorRange {
 public:
  explicit DepsIteratorRange(const DepsIterator& b);
  ~DepsIteratorRange();

  const DepsIterator& begin() const { return begin_; }
  const DepsIterator& end() const { return end_; }

 private:
  DepsIterator begin_;
  DepsIterator end_;
};

#endif  // TOOLS_GN_DEPS_ITERATOR_H_
