/* Copyright (c) 2011-2022 Reliancy LLC Licensed under the GNU LESSER GENERAL PUBLIC LICENSE Version 3. You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html. You may not use this file except in compliance with the License. */ package com.reliancy.rec; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Spliterators; import java.util.stream.Stream; import java.util.stream.StreamSupport; import com.reliancy.util.Arrays; /** * Iterator and Iterable for traversing {@link Slot} collections. * *

This class provides a unified interface for iterating over slots, * supporting both traditional iteration and Java 8+ Stream operations. * * Each header is iterated using local scope so you need to explictly specify an array in cases of inheritance. * *

Type Parameters:

* * *

Usage:

*
{@code
 * // For basic slots
 * Slots slots = new Slots<>(header);
 * 
 * // For fields (Field extends Slot, Entity extends Hdr)
 * Slots fields = new Slots<>(entity);
 * 
 * // Traditional iteration
 * for (Slot slot : slots) {
 *     System.out.println(slot.getName());
 * }
 * 
 * // Stream operations
 * fields.stream()
 *     .filter(f -> f.getName().startsWith("user_"))
 *     .forEach(f -> System.out.println(f.getName()));
 * }
* *

Utility Methods:

*

The {@link #current()}, {@link #currentHeader()}, and {@link #currentIndex()} methods * provide context about the current iteration state. Each refers to the element returned * by the most recent call to {@link #next()} (or {@code null}/-1 before any call). * These are useful for inspection or conditional logic during iteration. * * @param The slot type extending {@link Slot} * @param The header type extending {@link Hdr} * @see Slot * @see Hdr * @see Iterable * @see Iterator * @see Stream */ public class Slots implements Iterator, Iterable { public static Slots of(Hdr... headers){ return new Slots<>(headers); } public static interface Selector{ boolean select(Slot s); } public static final Selector SELECT_ALL=new Selector(){ public boolean select(Slot slot){ return true; } }; public static class SELECT_INCLUDING implements Selector{ int flags; public SELECT_INCLUDING(int flags){ this.flags=flags; } public boolean select(Slot slot){ return (slot.getFlags() & flags) != 0; } } public static class SELECT_EXCLUDING implements Selector{ int flags; public SELECT_EXCLUDING(int flags){ this.flags=flags; } public boolean select(Slot slot){ return (slot.getFlags() & flags) == 0; } } Hdr[] headers; Selector selector; // iterator state int h_next; List h_slots; int s_next; int s_current_index; S s_current_item; Hdr s_current_header; /** * Creates a new Slots iterator. * * @param headers The headers containing slots to iterate over */ public Slots(Hdr... headers) { this.headers=headers; rewind(); } public Slots considering(Hdr... headers){ this.headers=headers; rewind(); return this; } public Slots selectBy(Selector selector){ this.selector=selector; rewind(); return this; } public Slots clone(){ Slots cloned =new Slots<>(headers); if(selector!=null){ cloned.selectBy(selector); } return cloned; } /** * Filters fields to include only those with the specified flags set. * * @param flags The flag mask to match * @return This Fields instance for method chaining */ public Slots including(int flags) { selectBy(new Slots.SELECT_INCLUDING(flags)); return this; } /** * Filters fields to exclude those with the specified flags set. * * @param flags The flag mask to exclude * @return This Fields instance for method chaining */ public Slots excluding(int flags) { selectBy(new Slots.SELECT_EXCLUDING(flags)); return this; } public Slots rewind(){ h_next=0; h_slots=headers.length>0?headers[h_next].getOwnSlots():new ArrayList(); s_next=-1; seekNext(); // above seeknext is not consuming so we clear the current state s_current_index=-1; s_current_item=null; s_current_header=(0<=h_next && h_next(); s_next = -1; // we are done -lock in last item s_current_item=last_item; s_current_header=last_header; s_current_index+=1; } } } // ======================================================================== // Iterator Implementation // ======================================================================== /** * Returns the next element in the iteration. * * @return the next element in the iteration * @throws java.util.NoSuchElementException if the iteration has no more elements */ @Override public S next() { if(!hasNext()) throw new java.util.NoSuchElementException(); seekNext(); return s_current_item; } /** * Returns {@code true} if the iteration has more elements. * * @return {@code true} if the iteration has more elements */ @Override public boolean hasNext() { return 0<=s_next && s_next < h_slots.size(); } public S current(){ return s_current_item; } public Hdr currentHeader(){ return s_current_header; } /** * Returns the index of the last element returned by {@link #next()}. * *

Returns -1 if {@link #next()} has not been called yet (i.e., before the first * call to {@link #next()}). After each call to {@link #next()}, this value is * incremented to reflect the index of the element that was just returned. * * @return the index of the last returned element, or -1 if no elements have been returned yet */ public int currentIndex(){ return s_current_index; } /** * Removes from the underlying collection the last element returned * by this iterator (optional operation). * * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this iterator */ @Override public void remove() { throw new UnsupportedOperationException("forward only immutable view"); } // ======================================================================== // Iterable Implementation // ======================================================================== /** * Returns an iterator over elements of type {@code S}. * * @return an Iterator */ @Override public Iterator iterator() { return clone(); } // ======================================================================== // Stream Support // ======================================================================== /** * Returns a sequential {@code Stream} with this collection as its source. * *

This method allows the slots to be processed using Java 8+ Stream API: *

{@code
     * slots.stream()
     *     .filter(s -> s.getName().startsWith("user_"))
     *     .map(Slot::getName)
     *     .collect(Collectors.toList());
     * }
* * @return a sequential Stream over the slots */ public Stream stream() { return StreamSupport.stream( Spliterators.spliteratorUnknownSize(this, 0), false ); } /** * Returns a possibly parallel {@code Stream} with this collection as its source. * *

It is allowable for this method to return a sequential stream. * * @return a possibly parallel Stream over the slots */ public Stream parallelStream() { return StreamSupport.stream( Spliterators.spliteratorUnknownSize(this, 0), true ); } }