b091ab24162f2399a57d8dfca9aa041b8634fe51
[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
24 /**
25  * Iterable that splices other iterables and iterates over them sequentially.
26  * User: dcheryasov
27  * Date: Nov 20, 2009 8:01:23 AM
28  */
29 public class ChainIterable<T> extends ChainedListBase<Iterable<T>> implements Iterable<T> {
30
31   public ChainIterable(@Nullable Iterable<T> initial) {
32     super(initial);
33   }
34
35   public ChainIterable() {
36     super(null);
37   }
38   
39   public ChainIterable(@NotNull T initial) {
40     super(Collections.singleton(initial));
41   }
42
43
44   public ChainIterable<T> add(@NotNull Iterable<T> another) {
45     return (ChainIterable<T>)super.add(another);
46   }
47
48   /**
49    * Apply wrapper to another and add the result. Convenience to avoid cluttering code with apply() calls.
50    * @param wrapper
51    * @param another
52    * @return
53    */
54   public ChainIterable<T> addWith(FP.Lambda1<Iterable<T>, Iterable<T>> wrapper, Iterable<T> another) {
55     return (ChainIterable<T>)super.add(wrapper.apply(another));
56   }
57
58   /**
59    * Convenience: add an item wrapping it into a SingleIterable behind the scenes.
60    */
61   public ChainIterable<T> addItem(@NotNull T item) {
62     return (ChainIterable<T>)super.add(Collections.<T>singleton(item));
63   }
64
65   /**
66    * Convenience, works without ever touching an iterator.
67    * @return true if the chain contains at least one iterable (but all iterables in the chain may happen to be empty).
68    */
69   public boolean isEmpty() {
70     return (myPayload == null);
71   }
72
73   public Iterator<T> iterator() {
74
75
76     class IterMixedIn extends ChainIterationMixin<T, Iterable<T>> {
77       IterMixedIn(ChainedListBase<Iterable<T>> link) {
78         super(link);
79       }
80
81       @Override
82       public Iterator<T> toIterator(Iterable<T> first) {
83         return first.iterator();
84       }
85     }
86     final IterMixedIn mixin = new IterMixedIn(this);
87
88
89     class Iter extends ChainedListBase<Iterable<T>> implements Iterator<T> {
90
91       Iter(ChainedListBase<Iterable<T>> piggybacked) {
92         super(piggybacked.myPayload);
93         myNext = piggybacked.myNext;
94       }
95
96       public boolean hasNext() {
97         return mixin.hasNext();
98       }
99
100       public void remove() {
101         throw new UnsupportedOperationException(); // we don't remove things
102       }
103
104       public T next() {
105         //noinspection RedundantCast
106         return (T)mixin.next();
107       }
108
109     }
110
111     return new Iter(this);
112
113   }
114
115   @Override
116   public String toString() {
117     return FP.fold(new FP.StringCollector<T>(), this, new StringBuilder()).toString();
118   }
119 }