Skip to content

Commit

Permalink
integration with std iter package
Browse files Browse the repository at this point in the history
  • Loading branch information
Sean Foley committed Aug 19, 2024
1 parent 6806ba8 commit aaae6d8
Showing 1 changed file with 136 additions and 10 deletions.
146 changes: 136 additions & 10 deletions ipaddr/addriterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ type IteratorWithRemove[T any] interface {
Remove() T
}

//
type singleIterator[T any] struct {
empty bool
original T
Expand All @@ -52,7 +51,6 @@ func (it *singleIterator[T]) Next() (res T) {
return
}

//
type multiAddrIterator struct {
Iterator[*AddressSection]
zone Zone
Expand Down Expand Up @@ -134,7 +132,6 @@ func (iter ipAddrIterator) Next() *IPAddress {
return iter.Iterator.Next().ToIP()
}

//
type sliceIterator[T any] struct {
elements []T
}
Expand All @@ -151,7 +148,6 @@ func (iter *sliceIterator[T]) Next() (res T) {
return
}

//
type ipv4AddressIterator struct {
Iterator[*Address]
}
Expand All @@ -160,7 +156,6 @@ func (iter ipv4AddressIterator) Next() *IPv4Address {
return iter.Iterator.Next().ToIPv4()
}

//
type ipv6AddressIterator struct {
Iterator[*Address]
}
Expand All @@ -169,7 +164,6 @@ func (iter ipv6AddressIterator) Next() *IPv6Address {
return iter.Iterator.Next().ToIPv6()
}

//
type macAddressIterator struct {
Iterator[*Address]
}
Expand All @@ -178,7 +172,6 @@ func (iter macAddressIterator) Next() *MACAddress {
return iter.Iterator.Next().ToMAC()
}

//
type addressSeriesIterator struct {
Iterator[*Address]
}
Expand All @@ -190,7 +183,6 @@ func (iter addressSeriesIterator) Next() ExtendedSegmentSeries {
return wrapAddress(iter.Iterator.Next())
}

//
type ipaddressSeriesIterator struct {
Iterator[*IPAddress]
}
Expand All @@ -202,7 +194,6 @@ func (iter ipaddressSeriesIterator) Next() ExtendedIPSegmentSeries {
return iter.Iterator.Next().Wrap()
}

//
type sectionSeriesIterator struct {
Iterator[*AddressSection]
}
Expand All @@ -214,7 +205,6 @@ func (iter sectionSeriesIterator) Next() ExtendedSegmentSeries {
return wrapSection(iter.Iterator.Next())
}

//
type ipSectionSeriesIterator struct {
Iterator[*IPAddressSection]
}
Expand All @@ -225,3 +215,139 @@ func (iter ipSectionSeriesIterator) Next() ExtendedIPSegmentSeries {
}
return wrapIPSection(iter.Iterator.Next())
}

// StdPushIterator converts a "pull" iterator in this libary to a "push" iterator assignable to the type iter.Seq in the standard library.
//
// The returned iterator is a single-use iterator.
//
// This function does not return iter.Seq directly, instead it returns a func(yield func(V) bool) assignable to a variable of type iter.Seq[V].
// This avoids adding a dependency of this libary on Go version 1.23 while still integrating with the iter package introduced with Go 1.23.
//
// To convert an instance of IteratorWithRemove, wrap it by calling NewPointIteratorWithRemove first, then pass the returned iterator this function.
// To convert an instance of CachingTrieIterator, wrap it by calling NewPointCachingTrieIterator first, then pass the returned iterator this function.
//
// You should avoid doing a double conversion on an iterator from this library,
// first to a "push" iterator with StdPushIterator and then to a "pull" iterator using iter.Pull in the standard libary.
// The result is an iterator less efficient than the original that also requires a call to the "stop" function to release resources.
// Instead, use StdPullIterator to get a pull iterator with an API similar to that provided by iter.Pull.
func StdPushIterator[V any](iterator Iterator[V]) func(yield func(V) bool) {
return func(yield func(V) bool) {
for iterator.HasNext() && yield(iterator.Next()) {
}
}
}

// StdPullIterator converts a "pull" iterator from this library to a standard library "pull" iterator
// consisting of a single function for iterating, and a second function for stopping.
//
// Note that the stop function is a no-op for all iterators in this library.
// It does nothing, and can be ignored. It is provided only to match the returned values of iter.Pull.
// To convert an instance of IteratorWithRemove, wrap it by calling NewPointIteratorWithRemove first, then pass the returned iterator this function.
// To convert an instance of CachingTrieIterator, wrap it by calling NewPointCachingTrieIterator first, then pass the returned iterator this function.
//
// This function produces an iterator equivalent to the original. It is a single-use iterator, like the original.
//
// Use this function rather than a double conversion: firstly to a "push" iterator with StdPushIterator,
// and secondly to a "pull" iterator using iter.Pull from the standard libary.
// The double-conversion produces a final iterator less efficient than the original.
func StdPullIterator[V any](iterator Iterator[V]) (next func() (V, bool), stop func()) {
stop, next = func() {}, func() (V, bool) {
hasNext := iterator.HasNext()
return iterator.Next(), hasNext
}
return
}

// NewPointIteratorWithRemove can be used to convert an IteratorWithRemove to standard libary iterators.
// Call this function, and then pass the returned iterator to either StdPushIterator or StdPullIterator.
// This preserves access to the removal operation of the original iterator, now available through each element, IteratorWithRemovePosition.
func NewPointIteratorWithRemove[V any](iterator IteratorWithRemove[V]) Iterator[IteratorWithRemovePosition[V]] {
wrappedIter := pointIteratorWithRemove[V]{IteratorWithRemove: iterator}
castIter := Iterator[IteratorWithRemovePosition[V]](&wrappedIter)
return castIter
}

type pointIteratorWithRemove[V any] struct {
IteratorWithRemove[V]
}

func (iter pointIteratorWithRemove[V]) Next() IteratorWithRemovePosition[V] {
return IteratorWithRemovePosition[V]{
v: iter.IteratorWithRemove.Next(),
iter: iter.IteratorWithRemove,
}
}

func (iter pointIteratorWithRemove[V]) HasNext() bool {
return iter.IteratorWithRemove.HasNext()
}

// IteratorWithRemovePosition is an element returned from a PointIteratorWithRemove.
type IteratorWithRemovePosition[V any] struct {
v V
iter IteratorWithRemove[V]
}

// Value returns the iterator value associated with this iterator position.
func (iterPosition IteratorWithRemovePosition[V]) Value() V {
return iterPosition.v
}

// Remove removes the current iterated value from the underlying data structure or collection, and returns that element.
// If there is no such element, because it has been removed already or there are no more iterated elements, it returns the zero value for T.
func (iterPosition IteratorWithRemovePosition[V]) Remove() V {
return iterPosition.iter.Remove()
}

// NewPointCachingTrieIterator can be used to convert a CachingTrieIterator to standard libary iterators.
// Call this function, and then pass the returned iterator to either StdPushIterator or StdPullIterator.
// This preserves access to the removal and caching operations of the original iterator, now available through each element of type CachingTrieIteratorPosition.
func NewPointCachingTrieIterator[V any](iterator CachingTrieIterator[V]) Iterator[CachingTrieIteratorPosition[V]] {
wrappedIter := pointCachingTrieIterator[V]{CachingTrieIterator: iterator}
castIter := Iterator[CachingTrieIteratorPosition[V]](&wrappedIter)
return castIter
}

type pointCachingTrieIterator[V any] struct {
CachingTrieIterator[V]
}

func (iter pointCachingTrieIterator[V]) Next() CachingTrieIteratorPosition[V] {
return CachingTrieIteratorPosition[V]{
v: iter.CachingTrieIterator.Next(),
iter: iter.CachingTrieIterator,
}
}

func (iter pointCachingTrieIterator[V]) HasNext() bool {
return iter.CachingTrieIterator.HasNext()
}

// CachingTrieIteratorPosition is an element returned from an iterator created with NewPointCachingTrieIterator.
type CachingTrieIteratorPosition[V any] struct {
v V
iter CachingTrieIterator[V]
}

// Value returns the iterator value associated with this iterator position.
func (iterPosition CachingTrieIteratorPosition[V]) Value() V {
return iterPosition.v
}

// Remove removes the current iterated value from the underlying data structure or collection, and returns that element.
// If there is no such element, because it has been removed already or there are no more iterated elements, it returns the zero value for T.
func (iterPosition CachingTrieIteratorPosition[V]) Remove() V {
return iterPosition.iter.Remove()
}

func (iterPosition CachingTrieIteratorPosition[V]) GetCached() Cached {
return iterPosition.iter.GetCached()
}

func (iterPosition CachingTrieIteratorPosition[V]) CacheWithLowerSubNode(cached Cached) bool {
return iterPosition.iter.CacheWithLowerSubNode(cached)
}

func (iterPosition CachingTrieIteratorPosition[V]) CacheWithUpperSubNode(cached Cached) bool {
return iterPosition.iter.CacheWithUpperSubNode(cached)
}

0 comments on commit aaae6d8

Please sign in to comment.