2 * Copyright 2000-2014 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.jetbrains.python.toolbox;
18 import org.jetbrains.annotations.NotNull;
19 import org.jetbrains.annotations.Nullable;
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.NoSuchElementException;
26 * Iterable that splices other iterables and iterates over them sequentially.
28 * Date: Nov 20, 2009 8:01:23 AM
30 public class ChainIterable<T> extends ChainedListBase<Iterable<T>> implements Iterable<T> {
32 public ChainIterable(@Nullable Iterable<T> initial) {
36 public ChainIterable() {
40 public ChainIterable(@NotNull T initial) {
41 super(Collections.singleton(initial));
46 public ChainIterable<T> add(@NotNull Iterable<T> another) {
47 return (ChainIterable<T>)super.add(another);
51 * Apply wrapper to another and add the result. Convenience to avoid cluttering code with apply() calls.
56 public ChainIterable<T> addWith(FP.Lambda1<Iterable<T>, Iterable<T>> wrapper, Iterable<T> another) {
57 return (ChainIterable<T>)super.add(wrapper.apply(another));
61 * Convenience: add an item wrapping it into a SingleIterable behind the scenes.
63 public ChainIterable<T> addItem(@NotNull T item) {
64 return add(Collections.singleton(item));
68 * Convenience, works without ever touching an iterator.
69 * @return true if the chain contains at least one iterable (but all iterables in the chain may happen to be empty).
71 public boolean isEmpty() {
72 return (myPayload == null);
76 public Iterator<T> iterator() {
77 return new ChainIterator<T>(this);
81 public String toString() {
82 return FP.fold(new FP.StringCollector<T>(), this, new StringBuilder()).toString();
85 private static class ChainIterator<T> implements Iterator<T> {
87 private ChainedListBase<Iterable<T>> myLink; // link of the chain we're currently at
88 private Iterator<T> myCurrent;
90 public ChainIterator(@Nullable ChainedListBase<Iterable<T>> initial) {
94 // returns either null or a non-exhausted iterator.
96 private Iterator<T> getCurrent() {
97 while ((myCurrent == null || !myCurrent.hasNext()) && (myLink != null && myLink.myPayload != null)) { // fix myCurrent
98 if (myCurrent == null) {
99 myCurrent = myLink.myPayload.iterator();
100 assert myCurrent != null;
103 myLink= myLink.myNext;
111 public boolean hasNext() {
112 return getCurrent() != null;
117 final Iterator<T> current = getCurrent();
118 if (current != null) {
119 return current.next();
122 throw new NoSuchElementException();
127 public void remove() {
128 throw new UnsupportedOperationException("Cannot remove from ChainIterator");