Remove redundant iterator classes, make ChainIterator inner class of ChainIterable
[idea/community.git] / python / src / com / jetbrains / python / toolbox / ChainIterable.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.jetbrains.python.toolbox;
17
18 import org.jetbrains.annotations.NotNull;
19 import org.jetbrains.annotations.Nullable;
20
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.NoSuchElementException;
24
25 /**
26  * Iterable that splices other iterables and iterates over them sequentially.
27  * User: dcheryasov
28  * Date: Nov 20, 2009 8:01:23 AM
29  */
30 public class ChainIterable<T> extends ChainedListBase<Iterable<T>> implements Iterable<T> {
31
32   public ChainIterable(@Nullable Iterable<T> initial) {
33     super(initial);
34   }
35
36   public ChainIterable() {
37     super(null);
38   }
39   
40   public ChainIterable(@NotNull T initial) {
41     super(Collections.singleton(initial));
42   }
43
44
45   @Override
46   public ChainIterable<T> add(@NotNull Iterable<T> another) {
47     return (ChainIterable<T>)super.add(another);
48   }
49
50   /**
51    * Apply wrapper to another and add the result. Convenience to avoid cluttering code with apply() calls.
52    * @param wrapper
53    * @param another
54    * @return
55    */
56   public ChainIterable<T> addWith(FP.Lambda1<Iterable<T>, Iterable<T>> wrapper, Iterable<T> another) {
57     return (ChainIterable<T>)super.add(wrapper.apply(another));
58   }
59
60   /**
61    * Convenience: add an item wrapping it into a SingleIterable behind the scenes.
62    */
63   public ChainIterable<T> addItem(@NotNull T item) {
64     return add(Collections.singleton(item));
65   }
66
67   /**
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).
70    */
71   public boolean isEmpty() {
72     return (myPayload == null);
73   }
74
75   @Override
76   public Iterator<T> iterator() {
77     return new ChainIterator<T>(this);
78   }
79
80   @Override
81   public String toString() {
82     return FP.fold(new FP.StringCollector<T>(), this, new StringBuilder()).toString();
83   }
84
85   private static class ChainIterator<T> implements Iterator<T> {
86   
87     private ChainedListBase<Iterable<T>> myLink; // link of the chain we're currently at
88     private Iterator<T> myCurrent;
89   
90     public ChainIterator(@Nullable ChainedListBase<Iterable<T>> initial) {
91       myLink = initial;
92     }
93   
94     // returns either null or a non-exhausted iterator.
95     @Nullable
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;
101         }
102         else {
103           myLink= myLink.myNext;
104           myCurrent = null;
105         }
106       }
107       return myCurrent;
108     }
109   
110     @Override
111     public boolean hasNext() {
112       return getCurrent() != null;
113     }
114   
115     @Override
116     public T next() {
117       final Iterator<T> current = getCurrent();
118       if (current != null) {
119         return current.next();
120       }
121       else {
122         throw new NoSuchElementException();
123       }
124     }
125   
126     @Override
127     public void remove() {
128       throw new UnsupportedOperationException("Cannot remove from ChainIterator");
129     }
130   }
131 }