--- /dev/null
+/* teeiterator.vala
+ *
+ * Copyright (C) 2013 Maciej Piechotka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Maciej Piechotka <uzytkownik2@gmail.com>
+ */
+
+internal class Gee.TeeIterator<G> : Object, Traversable<G>, Iterator<G> {
+ internal TeeIterator (Node<G>? head, bool valid) {
+ _head = head;
+ _valid = valid;
+ }
+
+ public bool foreach (ForallFunc<G> f) {
+ Node<G> head = (owned)_head;
+ bool valid = _valid;
+ if (valid) {
+ if (!f (head._data.get ())) {
+ return false;
+ }
+ }
+ unowned Node<G>? next_head = head._next.value;
+ while (next_head != null) {
+ head = next_head;
+ valid = true;
+ if (!f (head._data.get ())) {
+ _head = (owned)head;
+ _valid = valid;
+ return false;
+ }
+ }
+ _head = (owned)head;
+ _valid = valid;
+ return true;
+ }
+
+ public bool next () {
+ unowned Node<G>? next = _head._next.value;
+ if (next != null) {
+ _head = next;
+ _valid = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public bool has_next () {
+ return _head._next.get () != null;
+ }
+
+ public G get () {
+ return _head._data.get ();
+ }
+
+ public void remove () {
+ assert_not_reached ();
+ }
+
+ public bool valid { get { return _valid; } }
+
+ public bool read_only { get { return true; } }
+
+ private Node<G> _head;
+ private bool _valid;
+
+ internal static Lazy<Node<G>?> create_nodes<G> (Iterator<G> iterator, Lazy<G> dependent) {
+ return new Lazy<Node<G>?>(() => {
+ dependent.eval ();
+ if (!iterator.next ())
+ return null;
+ Lazy<G> data = new Lazy<G> (() => {return iterator.get ();});
+ Lazy<Node<G>?> next = create_nodes<G> (iterator, data);
+ return new Node<G> ((owned)data, (owned)next);
+ });
+ }
+
+ internal class Node<G> {
+ public Node (owned Lazy<G> data, owned Lazy<Node<G>?> next) {
+ _data = (owned)data;
+ _next = (owned)next;
+ }
+ public Lazy<G> _data;
+ public Lazy<Node<G>?> _next;
+ }
+
+}
+
unowned Iterator<G>? self;
unowned Iterable<G>? iself;
// Yes - I've heard of polimorphism ;) but I don't want users to need to implement the method.
- if ((self = this as Iterator<G>) != null) {
+ if ((self = this as Iterator<G>) != null) {
return new StreamIterator<A, G> (self, (owned)f);
} else if ((iself = this as Iterable<G>) != null) {
return iself.iterator().stream<A> ((owned) f);
});
}
+ /**
+ * Splits the traversable into multiple ones, caching the result if needed.
+ *
+ * Note: In {@link Iterator} implementation using the parent iterator is
+ * not allowed. However if any of the forked iterators {@link next}
+ * return false then it is treated as if the parent iterator
+ * {@link next} returned false.
+ *
+ * Note: The returned arrey might contain parent iterator if it is allowed
+ * by implementation. For example the iteration over collection does
+ * not need to generate and cache the results.
+ *
+ * Note: the resulting iterators does not need to be thread safe.
+ *
+ * @param forks Number of iterators in array
+ * @returns An array with created iterators
+ * @since 0.11.5
+ */
+ public Iterator<G>[] tee (uint forks) {
+ unowned Iterator<G>? self;
+ unowned Iterable<G>? iself;
+ // Yes - I've heard of polimorphism ;) but I don't want users to need to implement the method.
+ if ((self = this as Iterator<G>) != null) {
+ if (forks == 0) {
+ return new Iterator<G>[0];
+ } else if (forks == 1) {
+ return new Iterator<G>[1]{self};
+ } else {
+ Iterator<G>[] result = new Iterator<G>[forks];
+ Lazy<G>? data;
+ bool is_valid = self.valid;
+ if (is_valid) {
+ data = new Lazy<G>(() => {return self.get ();});
+ } else {
+ data = new Lazy<G>.from_value (null);
+ }
+ var head = new TeeIterator.Node<G> (data, TeeIterator.create_nodes<G> (self, data));
+ for (uint i = 0; i < forks; i++) {
+ result[i] = new TeeIterator<G> (head, is_valid);
+ }
+ return result;
+ }
+ } else if ((iself = this as Iterable<G>) != null) {
+ var result = new Iterator<G>[forks];
+ for (uint i = 0; i < forks; i++) {
+ result[i] = iself.iterator ();
+ }
+ return result;
+ } else {
+ assert_not_reached ();
+ }
+ }
+
public enum Stream {
YIELD,
CONTINUE,