st

package module
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 24, 2025 License: MIT Imports: 4 Imported by: 0

README

Span-Tools

Implements the universal span intersection algorithm. The algorithm represents a unified way to find intersections and overlaps of "one dimensional spans" of any data type. The package is built around the SpanUtil[E any] struct, and the manipulation of the SpanBoundry[E any] interface.

The SpanUtils[E any] struct requires 2 methods be passed to the constructor in order to implement the algorithm:

  • A "Compare" function see: cmp.Compare for more details.
  • A "Next" function, takes a given value and returns next value. The next value must be greater than the input value

The algorithm is primarily implemented by 3 methods of the SpanUtil[E] struct:

  • FirstSpan, finds the initial data span intersection.
  • NextSpan, finds all subsequent data span intersections.
  • CreateOverlapSpan, finds the most common intersection of all overlapping spans.

Other features of this package:

  • Provide ways to consolidate overlaps.
  • Iterate through intersections of multiple data sets.

Basic Example

In this example we will find the intersections of 3 sets of integers. The full example can be found: here.

Example Sets:

	(1,2)
	(2,7)
	(5,11)

Setup the package and imports:

We will need to import our "st" package along with the "fmt" and "cmp" packages in order to process the example data sets.

import (
	"github.com/akalinux/span-tools"
	"fmt"
	"cmp"
)

Create our SpanUtil[E] instance:

We will use the factory interface NewSpanUtil to generate our SpanUtil[int] instance for these examples. This ensures that the Validate and Sort options are by set to true for all base examples.

var u=st.NewSpanUtil(
	// use the standard Compare function
	cmp.Compare,
	// Define our Next function
	func(e int) int { return e+1},
)

Find our the initial SpanBoundry intersection:

We need to find the initial intersection, before we can iterate through of these data sets. The initial SpanBoundry is found by making a call to u.FirstSapn(list).

// Create our initial span 
var span,ok=u.FirstSpan(list)
	
// Denote our overlap set position
var count=0

Iterate through all of our SpanBoundry intersections:

We can now step through each data intersection point and output the results. Each subsequent intersection is found by making a call to u.NextSpan(span,list).

for ok {
	// Get the indexes of the columns this overlap relates to
	var sources=u.GetOverlapIndexes(span,list)
		
	// output our intersection data
	fmt.Printf("Overlap Set: %d, Span: %v, Columns: %v\n",count,span,sources)
		
	// update our overlap set
	count++
		
	// get our next set
	span,ok=u.NextSpan(span,list)
}

Resulting output:

Overlap Set: 0, Span: &{1 1}, Columns: &[0]
Overlap Set: 1, Span: &{2 2}, Columns: &[0 1]
Overlap Set: 2, Span: &{3 5}, Columns: &[1 2]
Overlap Set: 3, Span: &{6 7}, Columns: &[1 2]
Overlap Set: 4, Span: &{8 11}, Columns: &[2]

Beyond The Basics

The basic example works, but its not very useful. In the real world we generally have multiple data sources. Usually we want to find the intersections of between those different data sources.

In this example we create a ColumnSets instance from a SpanUtil instance. The instance of ColumnSets will be used to find the intersection of 3 data sets. Note: two of the data sets contain spans that overlap within themselves. When a source is processed as a column, the overlapping data sets are in that column consolidated together. Once all columns have been added, we iterate over the result set to see how our data intersects.

Example Data sets:

SetA:
		(1, 2),
		(3, 7),  // will consolidate to 3-11
		(5, 11), // will consolidate to 3-11
SetB:
		(3, 3),
		(5, 11),
SetC:
		(1, 7),  // will consolidate to 1-11
		(8, 11), // will consolidate to 1-11

Example Code:

The full source code can be found: here

Create a ColumnSets[E] instance:

The ColumnSets instance is created by a factory interface of SpanUtil. For each instance of ColumnSets, a properly scoped call to "defer ac.Close()" will require being made.

// Build our column accumulator
ac := u.NewColumnSets()

// Always make sure a defer to close is scoped correctly!
defer ac.Close()

Adding each data set to our ColumnSets:

Each data set will need to be added to the ColumnSets instance. The internals refer to each column as a source. Every source added receives an id starting from 0, for each new column/source the id is incremented by 1. As a note all AddCoulumnXXX methods of ColumnSets return the index of the column/source that was added. If there was an error adding that data source as a column, the returned id will be -1.

Note: once the iteration over the data sets begins, it is no longer possible to add additional columns to the ColumnSets instance. The iterators provided by the "st" class in general are considered one shot iterators.

// We will map our ColumnId to our Set Name
m := make(map[int]string)

var seta = &[]st.SpanBoundry[int]{
	u.Ns(1, 2),
	u.Ns(3, 7),  // will consolidate to 3-11
	u.Ns(5, 11), // will consolidate to 3-11
}
ac.AddColumnFromSpanSlice(seta)
m[0] = "SetA"

var setb = &[]st.SpanBoundry[int]{
	u.Ns(3, 3),
	u.Ns(5, 11),
}
ac.AddColumnFromSpanSlice(setb)
m[1] = "SetB"

var setc = &[]st.SpanBoundry[int]{
	u.Ns(1, 7),
	u.Ns(8, 11),
}
ac.AddColumnFromSpanSlice(setc)
m[2] = "SetC"

Iterate through the results:

Finally we want to iterate through the resulting overlaps and intersections found in our different data sets:

header := "+-----+--------------------+------------------------------------+\n"
fmt.Print(header)
fmt.Print("| Seq | Begin and End      | Set Name:(Row,Row)                 |\n")
for pos, res := range ac.Iter() {
	// check if there were errors
	if ac.Err != nil {
		fmt.Printf("Error: on Column: %s, error was: %v\n",m[ac.ErrCol],ac.Err)
		return
	}
	cols := res.GetColumns()
	names := []string{}
	for _, column := range *cols {
		str :=fmt.Sprintf("%s:(%d-%d)",m[column.ColumnId],column.GetSrcId(),column.GetEndId())
		names = append(names, str)
	}
	fmt.Print(header)
	fmt.Printf("| %- 3d | Begin:% 3d, End:% 3d | %- 34s |\n",
		pos,
		res.GetBegin(),
		res.GetEnd(),
		strings.Join(names, ", "),
	)
}
fmt.Print(header)

The resulting output:

+-----+--------------------+------------------------------------+
| Seq | Begin and End      | Set Name:(Row,Row)                 |
+-----+--------------------+------------------------------------+
|  0  | Begin:  1, End:  2 | SetA:(0-0), SetC:(0-0)             |
+-----+--------------------+------------------------------------+
|  1  | Begin:  3, End:  3 | SetA:(1-2), SetB:(0-0), SetC:(0-0) |
+-----+--------------------+------------------------------------+
|  2  | Begin:  4, End:  5 | SetA:(1-2), SetB:(1-1), SetC:(0-0) |
+-----+--------------------+------------------------------------+
|  3  | Begin:  6, End:  7 | SetA:(1-2), SetB:(1-1), SetC:(0-0) |
+-----+--------------------+------------------------------------+
|  4  | Begin:  8, End: 11 | SetA:(1-2), SetB:(1-1), SetC:(1-1) |
+-----+--------------------+------------------------------------+

Intersections and Go Routines

The previous example works, but has some significant scaling limitations. For one, the implementation is limited to pre-loaded slices in memory and the code doesn't really take advantage of go routines.

In the real world we would expect to be able to query a system in one go routine, and process the results in another go routine while the data is streamed back to us. The ColumnSets instance supports the use of go routines via a chan based iterator of OverlappingSpanSets.

This example will use the same data set but simulate calling multiple systems via go routines. We will also manually drive the accumulation of the data by iterating through each slice one element at a time, as if it was a result from an external system.

The full source code can be found: here

Creating an instance of ColumnSets

The creation of the ColumnSets instance remains unchanged from our previous example. No special changes or initialization settings are required to enable the use of chan based communications via go routines. The top level ColumnSets.AddColumnXX methods are agnostic to how the data is accumulated, so you can mix and match as many variations as needed.

Creation of our go routines

The creation of our go routines will be done from inside the declaration of a closure. Each call to our closure will spawn an new go routine and begin pushing data to our initialized chan instance. The closure will create and manage an instance of OlssChanStater[E] by calling the factory chain "u.NewSpanOverlapAccumulator().NewOlssChanStater()" and add it to our ColumnSets instance. From there on out the context management will be handled by the ColumnSets instances.

Here is the "Add" closure added in the "main" function:

var Add = func(list *[]st.SpanBoundry[int]) int {
	s := u.NewSpanOverlapAccumulator().NewOlssChanStater()

	// Please note, we must start the go routine before we add
	// the accumulator to the ColumnSets instance.  If not we
	// will run into a race condition.
	go func() {
		// Scope our cleanup code to the go routine
		defer s.Final()
	
		end := len(*list) - 1
		id := 0
		span := (*list)[id]
		for s.CanAccumulate(span) {
			id++
			if id > end {
				return
			}
			span = (*list)[id]
		}
	}()

	// Adding the st.OlssChanStater instance to the ColumnSets
	return ac.AddColumnFromNewOlssChanStater(s)
}

Since we are managing the OlssChanStater via the ColumnSets instance, we do not need to understand the lower level implementation details, but as a note. The OlssChanStater[E] struct contains 3 important instances:

  • The context.Context used to shutdown the should the iterator fail be stopped
  • The chan of OverlappingSpanSets[E] required to communicate back to the main thread running the ColumnSets instance
  • The Stater instance used to manage accumulation of SpanBoundry instances and push them to our chan of OverlappingSpanSets[E]

Adding our data sets

The "Add" closure will manage the creation of our go routines and will return the ColumnId. We can use the return value from the "Add" closure we created to denote the mapping of the ColumnId to the SetName.

// We will map our ColumnId to our Set Name
m := make(map[int]string)

m[Add(
	&[]st.SpanBoundry[int]{
		u.Ns(1, 2),
		u.Ns(3, 7),  // will consolidate to 3-11
		u.Ns(5, 11), // will consolidate to 3-11
	},
)] = "SetA"

m[Add(&[]st.SpanBoundry[int]{
	u.Ns(3, 3),
	u.Ns(5, 11),
})] = "SetB"

m[Add(&[]st.SpanBoundry[int]{
	u.Ns(1, 7),
	u.Ns(8, 11),
})] = "SetC"

Iteration through the result set

The rest of our code, the for loop, error checking and final output statements remains unchanged from our previous example. The difference is how we accumulated the data. Because the ColumnSets instance iterator manages the context.Context instances, the calls to s.CanAccumulate(span) will return true if we can write to the chan. If we call break from the for loop in main the main function, or the internals run into an error the required call to the context cancel function is made automatically.

The resulting output

Please note, because our data set is unchanged, our output is also going to be the same as our previous example.

SpanBoundry Consolidation of Duplicates and Overlaps

In the real world data sets are often messy, out of order, and contain duplicates/overlaps. The internals of the "st" package expect SpanBoundry instances to be provided in a specific order. If data is not provided in the correct order it cannot be processed correctly.

The expected order is as follows (i=SpanBoundry):

  • i.GetBegin() ascending order
  • i.GetEnd() in descending order

This is an example unordered data set

(7,11),
(20,21),
(2,11),
(2,12),
(5,19),

This is the same data ordered for consumption by the "st" package:

(2,12),
(2,11),
(5,19),
(7,11),
(20,21),

Sorting of data sets

The full source code can be found: here.

The SpanUtil[E] struct has a "Sort" flag, when set to true( the default ), all instances of SpanOverlapAccumulator[E] created with the factory interface u.NewSpanOverlapAccumulator() will have the Sort flag set to true by default. If you wish to disable sorting you can either set the sort flag to false on the u.Sort=false instance before creating the SpanOverlapAccumulator instance or you can change the flag on just the SpanOverlapAccumulator instance ac.Sort=false.

Creating our SpanOverlapAccumulator

The SpanUtil[E] instance provides a factory interface for the creation of SpanOverlapAccumulator instances, the method is u.NewSpanOverlapAccumulator().

ac :=u.NewSpanOverlapAccumulator()

Sorting and Consolidation

Now we need to step through the resulting sorted and consolidated results. The ac.NewOlssSeq2FromSbSlice(list) method provides an iter.Seq2 factory interface that can be used to driver our for loop for us.

// this slice will end up being sorted by the "st" internals
unsorted :=&[]st.SpanBoundry[int]{
	// Raw       // Will be sorted to
	u.Ns(7,11),  // Row: 3
	u.Ns(20,21), // Row: 4
	u.Ns(2,11),  // Row: 1
	u.Ns(2,12),  // Row: 0
	u.Ns(5,19),  // Row: 2
}

for id,span := range ac.NewOlssSeq2FromSbSlice(unsorted) {
	fmt.Printf("OverlappingSpanSets: %d SpanBoundry (%d,%d)\n ",id,span.GetBegin(),span.GetEnd())
	fmt.Print(" Original Span values:\n")
	for _,src :=range *span.GetSources() {
		fmt.Printf("    Row: %d span: %v\n",src.SrcId,src.SpanBoundry)
	}
}

Resulting output:

OverlappingSpanSets: 0 SpanBoundry (2,19)
  Original Span values:
    Row: 0 span: &{2 12}
    Row: 1 span: &{2 11}
    Row: 2 span: &{5 19}
    Row: 3 span: &{7 11}
OverlappingSpanSets: 1 SpanBoundry (20,21)
  Original Span values:
    Row: 4 span: &{20 21}

Manual Consolidation and Error Checking

Data integrity is very important: the internals of the "st" package check for errors by default. Error checking can be disabled on the SpanUltil instance by setting u.Valudate=false. The iterators of the "st" package stop progressing if an error is encountered. Typically error checking is done in an instance of SpanOverlapAccumulator. This is generally a good place to stop the iteration process. The SpanOverlapAccumulator instance provides a method called s.Accumulate(SpanBoundry). This method returns both the OverlappingSpanSets instance and a pointer to error. If the error instance is not nil then the SpanOverlapAccumulator has encountered an error.

The SpanUtil[E] instance provides a check method for validating both SpanBondry instances and validating SpanBoundry instances in sequence. The name of the method is Check.

Error checking Example:

This example checks each element of a slice of SpanBoundry instances to see if they are both valid and in the correct order.

Example code can be found: here

To check if a SpanBoundry instance is valid:

In this case if err is not nil, then the span is valid. Validity is defined as span.GetBegin() is less than or equal to span.GetEnd().

err :=u.Check(span,nil)

if err!=nil {
  // invalid span
}	

To check if the next SpanBoundry should be after the current SpanBoundry:

This method performs 2 checks

  • First next is checked for validity
  • Checks if next comes after current or is equal to current

Note: current is not checked for validity.

err :=u.Check(next,current)

if err!=nil {
  // next is out of order in relation to current
}	

Manual Consolidation with Error checking:

As noted, error checking is enabled by default. In this example we will iterate through the SpanBoundry slice twice. In the first pass we will provide an unsorted list that will error out during the consolidation process. The 2nd pass we will first sort our list and then enter the consolidation process, which is expected to pass the 2nd time.

The source code for this example can be found: here.

We will be using the same data set as our previous example, the main differences come in 3 parts.

  • The import of the "slices" package for sorting
  • Turning validation on
  • The introduction of an additional function into the "main" package

In our main package we define a function called AccumulateSet, and it handles processing each manual accumulation pass. Please see the source code here for more details

Example1, the expected error pass:

// This pass will error out
fmt.Print("Processing our data with an invalid order\n")
AccumulateSet(unsorted)

Output from this section:

Notice that we run into an error when we get to SpanBoundry (2,11). The error is caused by the detection of a sequencing inconsistency.

Processing our data with an invalid order
  &{7 11} has spawned an new OverlappingSpanSets: (7,11)
  &{20 21} has spawned an new OverlappingSpanSets: (20,21)
  Failed to accumulate: &{2 11}, error was: SpanBoundry out of sequence

Example 2, the expected success pass:

// Once the data is sorted consolidation will work correctly
slices.SortFunc(*unsorted, u.Compare)
fmt.Print("\nProcessing post sort\n")
AccumulateSet(unsorted)

Output from this section:

In the output data set, take note that the OverlappingSpanSets expands from (2,12) to encompass (2,19) and a new OverlappingSpanSets is only created when a non overlapping SpanBoundry is introduced to the Accumulator method.

Processing post sort
  &{2 12} has spawned an new OverlappingSpanSets: (2,12)
  &{2 11} has been absorbed into OverlappingSpanSets: (2,12)
  &{5 19} has been absorbed into OverlappingSpanSets: (2,19)
  &{7 11} has been absorbed into OverlappingSpanSets: (2,19)
  &{20 21} has spawned an new OverlappingSpanSets: (20,21)

Overloading SpanBoundry Factory Interface

The "st" package is designed and implemented to manipulate instances of the SpanBoundry[E] interface.

The SpanBoundry[E] interface has 2 methods:

  • GetBegin() E, the value returned is expected to be less than or equal to the value returned by GetEnd()
  • GetEnd() E, the value returned is expected to be greater than or equal to the value returned by GetBegin()

Since the SpanBoundry[E] is an interface, the details of how the object is implemented is up to the developer. That said the internal factory interfaces will by default create new instances via the st.Span[E] struct. If you implement your own SpanBoundry[E] instance, you can overload the factory interface on the SpanUtils[E] instance by setting the SpanFactory instance function.

Example overloading the default SpanFactory on a SpanUtils[E] instance:

The full example can be found: here.

package main

import (
	"github.com/akalinux/span-tools"
)

type MySpan struct {
	a int
	b int 
}

// Implement our GetBegin
func (s *MySpan) GetBegin() int {
	return s.a
}

// Implement our GetEnd
func (s *MySpan) GetEnd() int {
	return s.b
}

func init() {
	// overload the default SpanFactory
	u.SpanFactory=func (a,b int) st.SpanBoundry[int] {
		return &MySpan{a,b}
	}
}

Thesis of Universal Span Intersection Algorithm

The "Universal Span Intersection Algorithm" is implemented by breaking operations down into their constituent parts. The process of finding the overlaps in data sets is in no way constrained by the types of data. We simply need a way to define our spans, compare values, and create a next value.

The parts can be described as follows:

Required tools:

  • A way to compare values
  • Creating a new next value
  • A way to define the begin and end values of the sets

The Iterative process:

  1. Finding the first span
  2. Finding the next span
  3. Repeating step 2 until no more overlaps are found

Finding the first span

The act of "Finding the first span" is performed in 3 stages:

  1. The first stage requires finding the smallest begin and end value of all of our spans.
  2. If a begin value in our sets is both greater than the smallest begin value and less than or equal to smallest end value, then the initial end value must set to the smallest begin value, else we use the smallest end value.
  3. We will use the begin value from stage 1 and the end value from stage 2 as our "first span"

Finding the next span

The act of "Finding the next span" is performed in 4 stages:

  1. The first stage we create a "new next value" that is greater than our last span end value. This "new next value" will be used as the "begin" value for step 3.
  2. We look for the next smallest begin or end value in our sets that are, greater than or equal to our "new next value". The value from this process will be used as our next "end" value for step 3.
  3. For each set that overlaps with the span defined by the "begin" from step 1 and the "end" from step 2: We need to look for the largest begin value and the smallest end value.
  4. We will used the largest begin value and smallest end value as our "next span"

We can repeat the "Finding the next set" until step 1 yields a value beyond any end value in our sets.

Thesis of How to find intersections in a list of sets of sets

The core thesis works for finding overlaps in a list of spans, but does not scale to a list of list of spans. For comparison of lists of list of spans, we need to define constraints for our data sets beyond just the concept of begin and end values.

Defining our constraints:

In order to compare a list of list of spans we will add the following constraints:

  1. Each list of list of spans must be presented in a specific order. The order is defined as: begin value in ascending order, end value in descending order.
  2. Each time a overlapping value is encountered a new Larger span consisting of the smallest begin value and largest end value must be created. As a side effect of this the original spans that caused this overlapping set should be retained to explain where this new larger span came from.
  3. To find the end of an overlapping set we must continue until we find the next span that does not overlap with our current span or we run out of spans to process.

Finding intersections with our constraints applied:

With our constraints applied, we can now consolidate list of list of spans, however we will need to add some enhancements to the process.

The enhancements are as follows:

  1. Now our our "Finding the first span" list of spans are pulled the first member of each constrained and consolidated list list of spans. We will refer the "first span" as the "current span".
  2. For each constrained list of spans: iterate through each constrained span and save all the constrained spans that overlap with our current span. When we find a span with an end or begin value beyond the current span end value we or we have exhausted this list of spans, this list iteration is complete.
  3. Now we apply "Finding the next span" to our current list of constrained spans. We will refer to the "next span" as the "current span"
  4. Repeat steps 2 and 3 until we have exhausted all lists of constrained spans.

More Examples

For more examples see the Examples folder [examples](https://github.com/akalinux/span-tools/tree/main/examples

Documentation

Overview

SpanTools Overview

Implements the universal span intersection algorithm. The algorithm represents a unified way to find intersections and overlaps of "one dimensional spans" of any data type. The package is built around the SpanUtil[E any] struct, and the manipulation of the SpanBoundry[E any] interface.

For examples and extended documentation please see the Project page.

How it works

The "Universal Span Intersection Algorithm" is implemented by breaking operations down into their constituent parts.

Finding intersections of one dimensional spans of generic data types requires the following:

  • A way contian the begin and end values, representing our span
  • Method to compare values.
  • Method to create a next value

Instance Construction

The st.NewSpanUtil[E any](Cmp,Next) function requires 2 methods be passed to the constructor in order to implement the algorithm:

  • A "Compare" function see: cmp.Compare for more details.
  • A "Next" function, takes a given value and returns next value. The next value must be greater than the input value

Example of creating a new instance of SpanUtil[int]:

var u = st.NewSpanUtil(
  //use the standard Compare function
  cmp.Compare,
  //Define our Next function
  func(e int) int { return e + 1 },
)

The algorithm is primarily implemented by 2 methods of the SpanUtil[E any] struct:

  • FirstSpan, finds the initial data span intersection.
  • NextSpan, finds all subsequent data span intersections.

Basic example

Our Example Set data:

var list = &[]st.SpanBoundry[int]{
  u.Ns(1, 2),
  u.Ns(2, 7),
  u.Ns(5, 11),
}

The act of "Finding the first span" is performed in 3 stages:

  1. The first stage requires finding the smallest begin and end value of all of our spans.
  2. If a begin value in our sets is both greater than the smallest begin value and less than or equal to smallest end value, then the initial end value must set to the smallest begin value, else we use the smallest end value.
  3. We will use the begin value from stage 1 and the end value from stage 2 as our "first span"

Example code snipped:

var span, ok = u.FirstSpan(list)

The act of "Finding the next span" is performed in 4 stages:

  1. The first stage we create a "new next value" that is greater than our last span end value. This "new next value" will be used as the "begin" value for step 3.
  2. We look for the next smallest begin or end value in our sets that are, greater than or equal to our "new next value". The value from this process will be used as our next "end" value for step 3.
  3. For each set that overlaps with the span defined by the "begin" from step 1 and the "end" from step 2: We need to look for the largest begin value and the smallest end value.
  4. We will used the largest begin value and smallest end value as our "next span"

We can repeat the "Finding the next set" until step 1 yields a value beyond any end value in our sets:

// Denote which set we are on
var count = 0

for ok {
  // Find the indexes of our input set
  var sources = u.GetOverlapIndexes(span, list)
  fmt.Printf("Overlap Set: %d, Span: %v, Columns: %v\n", count, span, sources)
  count++
  span, ok = u.NextSpan(span, list)
}

Beyond the basics

Finding overlaps between lists of lists takes a bit more work, but is greatly simplified by this package. In this example we will create an instance of st.ColumnSets[int]. The ColumnSets instance is created by a factory interface of SpanUtil.

Build our column accumulator:

ac := u.NewColumnSets()
// Always make sure a defer to close is scoped correctly!
defer ac.Close()

In order to compare a list of list of spans we will add the following constraints:

  1. Each list of list of spans must be presented in a specific order. The order is defined as: begin value in ascending order, end value in descending order.
  2. Each time a overlapping value is encountered a new Larger span consisting of the smallest begin value and largest end value must be created. As a side effect of this the original spans that caused this overlapping set should be retained to explain where this new larger span came from.
  3. To find the end of an overlapping set we must continue until we find the next span that does not overlap with our current span or we run out of spans to process.

Example data set:

// We will map our ColumnId to our Set Name
m := make(map[int]string)

var seta = &[]st.SpanBoundry[int]{
  u.Ns(1, 2),
  u.Ns(3, 7),  // will consolidate to 3-11
  u.Ns(5, 11), // will consolidate to 3-11
}
m[0] = "SetA"

var setb = &[]st.SpanBoundry[int]{
  u.Ns(3, 3),
  u.Ns(5, 11),
}
m[1] = "SetB"
var setc = &[]st.SpanBoundry[int]{
  u.Ns(1, 7),
  u.Ns(8, 11),
}
m[2] = "SetC"

// The internals sort slices and applys the constrains automatically
ac.AddColumnFromSpanSlice(seta)
ac.AddColumnFromSpanSlice(setb)
ac.AddColumnFromSpanSlice(setc)

With our constraints applied, we can now consolidate list of list of spans, however we will need to add some enhancements to the process.

The enhancements are as follows:

  1. Now our our "Finding the first span" list of spans are pulled the first member of each constrained and consolidated list list of spans. We will refer the "first span" as the "current span".
  2. For each constrained list of spans: iterate through each constrained span and save all the constrained spans that overlap with our current span. When we find a span with an end or begin value beyond the current span end value we or we have exhausted this list of spans, this list iteration is complete.
  3. Now we apply "Finding the next span" to our current list of constrained spans. We will refer to the "next span" as the "current span"
  4. Repeat steps 2 and 3 until we have exhausted all lists of constrained spans.

Example Iterator loop:

header := "+-----+--------------------+------------------------------------+\n"
fmt.Print(header)
fmt.Print("| Seq | Begin and End      | Set Name:(Row,Row)                 |\n")
for pos, res := range ac.Iter() {
// check if there were errors
if ac.Err != nil {
  fmt.Printf("Error: on Column: %s, error was: %v\n",m[ac.ErrCol],ac.Err)
  return
}
cols := res.GetColumns()
names := []string{}
for _, column := range *cols {
  str :=fmt.Sprintf("%s:(%d-%d)",m[column.ColumnId],column.GetSrcId(),column.GetEndId())
  names = append(names, str)
  }
  fmt.Print(header)
  fmt.Printf("| %- 3d | Begin:% 3d, End:% 3d | %- 34s |\n",
    pos,
    res.GetBegin(),
    res.GetEnd(),
    strings.Join(names, ", "),
  )
}
fmt.Print(header)

Integrating go routines and streaming data sets

The internals of the st package, can be used to create context instances to mange communication between go routines for us. If the spans are recived out of order or fail to pass error checking constraints, then the main iterator loop will be halted. In this example we will simulate streaming the same data set via go routines.

First we create an "Add" function to create our go routien and push data into our column channel based iterators:

var Add = func(list *[]st.SpanBoundry[int]) int {
  s := u.NewSpanOverlapAccumulator().NewOlssChanStater()

  // Please note, we must start the go routine before we add
  // the accumulator to the ColumnSets instance.  If not we
  // will run into a race condition.
  go func() {
    // Scope our cleanup code to the go routine
    defer s.Final()

    end := len(*list) - 1
    id := 0
    span := (*list)[id]
    for s.CanAccumulate(span) {
      id++
      if id > end {
        return
      }
      span = (*list)[id]
    }
    }()

  // Adding the st.OlssChanStater instance to the ColumnSets
  return ac.AddColumnFromNewOlssChanStater(s)
}

We can now add our data sets:

Add(&[]st.SpanBoundry[int]{
  u.Ns(1, 2),
  u.Ns(3, 7),  // will consolidate to 3-11
  u.Ns(5, 11), // will consolidate to 3-11
})
Add(&[]st.SpanBoundry[int]{
  u.Ns(3, 3),
  u.Ns(5, 11),
})
Add(&[]st.SpanBoundry[int]{
  u.Ns(1, 7),
  u.Ns(8, 11),
})

The for loop and map remain unchanged from our previous example. The only differnce is the internals have no way to sort the data before it is consolidated.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ColumnOverlap

type ColumnOverlap[E any] interface {
	SpanBoundry[E]
	// Returns the first index point from the soruce data set
	GetSrcId() int
	// Returns the last index point from the soruce data set
	GetEndId() int
	GetOverlaps() *[]*OverlappingSpanSets[E]
	// Returns both the index point of the first data soruce, and the original SpanBoundry.
	GetFirstSpan() (int, SpanBoundry[E])
	// Returns both the index point of the last data soruce, and the original SpanBoundry.
	GetLastSpan() (int, SpanBoundry[E])
	// Returns all intersecting SpanBoundry instances and their indexes
	GetSources() *[]*OvelapSources[E]
}

Represents an intersection of data. Intersections can represent data that overlaps from a given source, or intersections between multiple sources.

Representation as a SpanBoundry is as follows:

  • GetBegin() returns the smallest most intersection boundry.
  • GetEnd() returns the largest most intersection boundry.

type ColumnOverlapAccumulator

type ColumnOverlapAccumulator[E any] struct {
	// Representation of the data that intersected with an SpanBoundry passed to GetNext.
	// A value of nil means no data overlaps.
	Overlaps *[]*OverlappingSpanSets[E]

	// Where Overlaps begins relative to our OverlappingSpanSets[E,T] iteration.
	// A value of -1 means there was no overlap with the last SpanBoundry[E,T] compared.
	SrcStart int
	// Where Overlaps ends relative to our OverlappingSpanSets[E,T] iteration.
	// A value of -1 means there was no overlap with the last SpanBoundry[E,T] compared.
	SrcEnd int

	// Span utility instance
	Util *SpanUtil[E]

	// The iter.Pull2 "next" method generated from the iter.Seq2 instance.
	ItrGetNext func() (int, *OverlappingSpanSets[E], bool)
	// The iter.Pull2 "stop" method generated from the iter.Seq2 instance.
	ItrStop func()

	// The next set to operate on, when nil.
	Next *OverlappingSpanSets[E]

	// Denotes if the object is closed
	Closed bool

	Err error
}

This structure represents a "data source" and how it intersects with an external SpanBoundry. Contains the current iterator control functions and represents the column position in the iterator process.

func (*ColumnOverlapAccumulator[E]) Close

func (s *ColumnOverlapAccumulator[E]) Close()

This method is used to call the stop method of the iter.Pull2 iterator method. If you are managing an instance of ColumnOverlapAccumulator[E,T] on your own, make sure to setup a defer SpanOverlapColumnAccumulator[E,T].Close() to ensure your code does not leak memory or run into undefined behaviors.

func (*ColumnOverlapAccumulator[E]) GetBegin

func (s *ColumnOverlapAccumulator[E]) GetBegin() E

func (*ColumnOverlapAccumulator[E]) GetEnd

func (s *ColumnOverlapAccumulator[E]) GetEnd() E

func (*ColumnOverlapAccumulator[E]) GetEndId

func (s *ColumnOverlapAccumulator[E]) GetEndId() int

Returns the last positional id from the orignal data set for this column.

func (*ColumnOverlapAccumulator[E]) GetFirstSpan

func (s *ColumnOverlapAccumulator[E]) GetFirstSpan() (int, SpanBoundry[E])

Returns the first span that intersecs with this set.

func (*ColumnOverlapAccumulator[E]) GetLastSpan

func (s *ColumnOverlapAccumulator[E]) GetLastSpan() (int, SpanBoundry[E])

Returns the last span that intersecs with this set.

func (*ColumnOverlapAccumulator[E]) GetOverlaps

func (s *ColumnOverlapAccumulator[E]) GetOverlaps() *[]*OverlappingSpanSets[E]

Returns the overlap sets.

func (*ColumnOverlapAccumulator[E]) GetSources

func (s *ColumnOverlapAccumulator[E]) GetSources() *[]*OvelapSources[E]

Returns all spans with the sequence id from the orginal data source.

func (*ColumnOverlapAccumulator[E]) GetSrcId

func (s *ColumnOverlapAccumulator[E]) GetSrcId() int

Returns the first positional id from the orignal data set for this column.

func (*ColumnOverlapAccumulator[E]) HasNext

func (s *ColumnOverlapAccumulator[E]) HasNext() bool

Returns true if there are more elements in this column.

func (*ColumnOverlapAccumulator[E]) InOverlap

func (s *ColumnOverlapAccumulator[E]) InOverlap() bool

When true this instance contains elements in "Overlaps" that intersect with the last value passed to SetNext.

func (*ColumnOverlapAccumulator[E]) SetNext

func (s *ColumnOverlapAccumulator[E]) SetNext(overlap SpanBoundry[E])

This method updates the state of the instance instance in relation to overlap. The overlap is considered an external point for comparison, and the internal data sets are updated to reflect the current intersection points if any.

type ColumnResults

type ColumnResults[E any] interface {
	// Returns the current columns
	GetColumns() *[]*CurrentColumn[E]

	// Denotes how many columns overlap with the current span.
	OverlapCount() int
	// Returns the SpanBoundry representing the current position in our data set.
	GetSpan() SpanBoundry[E]

	SpanBoundry[E]
}

type ColumnSets

type ColumnSets[E any] struct {
	Util *SpanUtil[E]

	// The last error, nil if there were no errors
	Err error
	// ColumnId the our last error came from
	ErrCol  int
	OnClose *[]func()
	// contains filtered or unexported fields
}

This struct acts as the majordomo of the constrained span intersection iteration process.

For every instance created make sure to scope the proper defer call:

defer i.Close()

func (*ColumnSets[E]) AddColumn

func (s *ColumnSets[E]) AddColumn(c *ColumnOverlapAccumulator[E]) int

Appends an a column accumulator to the current column set. Returns the id of the column, if the instance is closed returns -1.

func (*ColumnSets[E]) AddColumnFromNewOlssChanStater

func (s *ColumnSets[E]) AddColumnFromNewOlssChanStater(sa *OlssChanStater[E]) int

Adds a context aware channel based ColumnOverlapAccumulator.

Warning

If you don't start the go routine that appends to the channel before calling this method, it will cause a race condition that will prevent the ColumnSets instancce from working correctly.

func (*ColumnSets[E]) AddColumnFromOverlappingSpanSets

func (s *ColumnSets[E]) AddColumnFromOverlappingSpanSets(list *[]*OverlappingSpanSets[E]) int

Adds list as a column to the internals.

func (*ColumnSets[E]) AddColumnFromSpanSlice

func (s *ColumnSets[E]) AddColumnFromSpanSlice(list *[]SpanBoundry[E]) (int, *SpanOverlapAccumulator[E])

This is a helper method that constructs an SpanOverlapAccumulator and then produces an iterator from the SpanOverlapAccumulator based on list.

func (*ColumnSets[E]) AddOnClose

func (s *ColumnSets[E]) AddOnClose(todo func())

Adds a function to call when the close operation is called or the iterator optations have been completed.

func (*ColumnSets[E]) Close

func (s *ColumnSets[E]) Close()

Shuts down and cleans up the instance, and any go routines that were registered.

func (*ColumnSets[E]) GetBegin

func (s *ColumnSets[E]) GetBegin() E

This is a wrapper for s.GetSpan.GetBegin().

func (*ColumnSets[E]) GetColumns

func (s *ColumnSets[E]) GetColumns() *[]*CurrentColumn[E]

func (*ColumnSets[E]) GetEnd

func (s *ColumnSets[E]) GetEnd() E

This is a wrapper for s.GetSpan.GetEnd().

func (*ColumnSets[E]) GetSpan

func (s *ColumnSets[E]) GetSpan() SpanBoundry[E]

Returns the SpanBoundry instance that represents the intersection of our current column state.

func (*ColumnSets[E]) Iter

func (s *ColumnSets[E]) Iter() iter.Seq2[int, ColumnResults[E]]

Creates an iteraotr to walk all added columns and find the overlaps.

func (*ColumnSets[E]) OverlapCount

func (s *ColumnSets[E]) OverlapCount() int

Denotes how many columns overlap with this span, if the set of current colums is empty then the returned value will be -1.

type CurrentColumn

type CurrentColumn[E any] struct {
	ColumnOverlap[E]
	ColumnId int
}

Represents a source data set of the culumn consolidation process.

type OlssChanStater

type OlssChanStater[E any] struct {
	Chan       chan *OverlappingSpanSets[E]
	Closed     bool
	Stater     SpanIterSeq2Stater[E]
	Ctx        context.Context
	Cancel     func()
	IsShutDown bool
}

Context aware goroutine channel accumulator instance. This struct is meant to be instantiated factory interfaces. If you are managing an instance ouside of the normal factory methods, you will need to add the following defer statements in the properly scopes:

  • in the main thread add a defer s.Shutdown()
  • in the go routine add a defer s.Final()

func (*OlssChanStater[E]) CanAccumulate

func (s *OlssChanStater[E]) CanAccumulate(span SpanBoundry[E]) bool

Acts as a control method in for loops, handles pushing data to the channel from within a goroutine.

Example:

defer s.Final()
for s.CanAccumulate(span) {
  // get your next SpanBoundry
}

func (*OlssChanStater[E]) Final

func (s *OlssChanStater[E]) Final() bool

Call this method with a derfer statement in your goroutine when you are done processing SpanBoundry instances.

Example:

defer s.Final()

func (*OlssChanStater[E]) Push

func (s *OlssChanStater[E]) Push(next *OverlappingSpanSets[E]) bool

Attempts to push the next value to the channel, if this instance is Closed or if the context has been cancled, then the method returns false.

func (*OlssChanStater[E]) Shutdown

func (s *OlssChanStater[E]) Shutdown()

Shuts down the context from the Column accumulator thread. Do not call this outside of the thread running the ColumnOverlapAccumulator instance or you will get undefined behavior.

type OvelapSources

type OvelapSources[E any] struct {
	SpanBoundry[E]
	SrcId int
}

Represents the SpanBoundry[E] that caused this intersection and its index point.

type OverlappingSpanSets

type OverlappingSpanSets[E any] struct {

	// The Span that contains all Spans in this instance.
	Span SpanBoundry[E]

	// When nil, Span is the only value representing this Span.
	// When not nil, contains all the Spans accumulated to create this instance.
	Contains *[]SpanBoundry[E]

	// Starting position in the original data set
	SrcBegin int

	// Ending position in the original data set
	SrcEnd int

	Err error
}

A representation of accumulated Span from a given source. The *Span[E,T] represents the span that contains all SpanBoundry[E,T] in *Contains. When *Contains is nil, then this struct only has 1 SpanBoundry[E,T]. When *Contains is not nil, the original *SpanBoundry[E,T] values are contained within.

func (*OverlappingSpanSets[E]) GetBegin

func (s *OverlappingSpanSets[E]) GetBegin() E

Implementation required for this object instance to act as a SpanBoundry[E] instance.

func (*OverlappingSpanSets[E]) GetContains

func (s *OverlappingSpanSets[E]) GetContains() *[]SpanBoundry[E]

Returns all of the span values that drive this current intersection.

func (*OverlappingSpanSets[E]) GetEnd

func (s *OverlappingSpanSets[E]) GetEnd() E

Implementation required for this object instance to act as a SpanBoundry[E] instance.

func (*OverlappingSpanSets[E]) GetEndId

func (s *OverlappingSpanSets[E]) GetEndId() int

Returns the indexed sequence point of the last original span representing this intersection.

func (*OverlappingSpanSets[E]) GetFirstSpan

func (s *OverlappingSpanSets[E]) GetFirstSpan() (int, SpanBoundry[E])

Returns the first span that created this interseciton.

func (*OverlappingSpanSets[E]) GetLastSpan

func (s *OverlappingSpanSets[E]) GetLastSpan() (int, SpanBoundry[E])

Returns the last span that created this interseciton.

func (*OverlappingSpanSets[E]) GetOverlaps

func (s *OverlappingSpanSets[E]) GetOverlaps() *[]*OverlappingSpanSets[E]

Returns the slice of OverlappingSpanSets that drive this current intersection.

func (*OverlappingSpanSets[E]) GetSources

func (s *OverlappingSpanSets[E]) GetSources() *[]*OvelapSources[E]

Returns all of the spans and thier indexes that caused this current intersection.

func (*OverlappingSpanSets[E]) GetSrcId

func (s *OverlappingSpanSets[E]) GetSrcId() int

Returns the indexed sequence point of the first original span representing this intersection.

func (*OverlappingSpanSets[E]) IsUnique

func (s *OverlappingSpanSets[E]) IsUnique() bool

Returns true of there are no overlaps with this span.

type Span

type Span[E any] struct {
	// Start of the Span.
	Begin E
	// End of the Span.
	End E
}

Representation of a Span/Range of values in a generic context. The assumption is that Begin is less than or equal to the End value.

func (*Span[E]) GetBegin

func (s *Span[E]) GetBegin() E

Returns the Begin value

func (*Span[E]) GetEnd

func (s *Span[E]) GetEnd() E

Returns the End value

type SpanBoundry

type SpanBoundry[E any] interface {
	// Returns the Begin value.
	GetBegin() E

	// Returns the End value.
	GetEnd() E
}

This interface acts as the core representation of spans for the "st" pacakge. Spans are represent by 2 values a "Begin" value and an "End" value. The Begin value should be returned by GetBegin and should be greater than or equal to the End value returned by GetEnd.

type SpanIterSeq2Stater

type SpanIterSeq2Stater[E any] struct {
	Current *OverlappingSpanSets[E]
	Next    *OverlappingSpanSets[E]
	Sa      *SpanOverlapAccumulator[E]
	Id      int
}

Represents the stater for going to the: next span.

func (*SpanIterSeq2Stater[E]) GetNext

func (s *SpanIterSeq2Stater[E]) GetNext() (int, *OverlappingSpanSets[E])

Returns the current index and intersection if any.

func (*SpanIterSeq2Stater[E]) HasNext

func (s *SpanIterSeq2Stater[E]) HasNext() bool

Returns true if we have any more intersections.

func (*SpanIterSeq2Stater[E]) SetNext

func (s *SpanIterSeq2Stater[E]) SetNext(span SpanBoundry[E]) bool

Returns true if this SpanBoundry[E] created a new data intersrection. If the value is true you must make a call to s.GetNext() instance method before calling this method again!

type SpanOverlapAccumulator

type SpanOverlapAccumulator[E any] struct {
	Rss *OverlappingSpanSets[E]
	*SpanUtil[E]
	// When true slices passed in will be sorted.
	Sort bool

	// When not nil, this object has encounter an error
	Err error

	// Sequence counter
	Pos int

	// Turns validation on/off, default false or off
	Validate bool

	// Turns consolidation of adjacent spans on or off, default false or off
	Consolidate bool
}

This is a stater structure, used to drive the creation of new OverlappingSpanSets. Each source of spans should have their own instance of SpanOverlapAccumulator.

func (*SpanOverlapAccumulator[E]) Accumulate

func (s *SpanOverlapAccumulator[E]) Accumulate(span SpanBoundry[E]) (*OverlappingSpanSets[E], error)

The Accumulate method.

For a given span provided: When the span overlaps with the current internal span, the OverlappingSpanSets is expanded and the span is append to the Contains slice. When the span is outside of the current internal span, then a new OverlappingSpanSets is created with this span as its current span. The error value is nil, by default, when an error has happend it is no longer nil.

func (*SpanOverlapAccumulator[E]) NewCoaFromOlssChan

func (s *SpanOverlapAccumulator[E]) NewCoaFromOlssChan(c <-chan *OverlappingSpanSets[E]) *ColumnOverlapAccumulator[E]

Factory for convering a channel of OverlappingSpanSets[E] to a ColumnOverlapAccumulator[E].

func (*SpanOverlapAccumulator[E]) NewCoaFromSbSlice

func (s *SpanOverlapAccumulator[E]) NewCoaFromSbSlice(list *[]SpanBoundry[E]) *ColumnOverlapAccumulator[E]

This is a convenience method for initializing the iter.Seq2 stater internals based on a slice of SpanBoundry.

func (*SpanOverlapAccumulator[E]) NewOlssChanStater

func (s *SpanOverlapAccumulator[E]) NewOlssChanStater() *OlssChanStater[E]

Creates a new context aware context.Context aware SpanBoundry[E] accumulation instance.

func (*SpanOverlapAccumulator[E]) NewOlssSeq2FromOlssSlice

func (s *SpanOverlapAccumulator[E]) NewOlssSeq2FromOlssSlice(list *[]*OverlappingSpanSets[E]) iter.Seq2[int, *OverlappingSpanSets[E]]

Helper function to create an overlap iterator from a slice of list.

func (*SpanOverlapAccumulator[E]) NewOlssSeq2FromSbChan

func (s *SpanOverlapAccumulator[E]) NewOlssSeq2FromSbChan(c <-chan SpanBoundry[E]) iter.Seq2[int, *OverlappingSpanSets[E]]

Generates a iter.Seq2 iterator, for a channel of SpanBoundry instances.

func (*SpanOverlapAccumulator[E]) NewOlssSeq2FromSbSlice

func (s *SpanOverlapAccumulator[E]) NewOlssSeq2FromSbSlice(list *[]SpanBoundry[E]) iter.Seq2[int, *OverlappingSpanSets[E]]

Factory interface for converting slices of SpanBoundaries instances into iterator sequences of OverlappingSpanSets.

func (*SpanOverlapAccumulator[E]) NewSpanIterSeq2Stater

func (s *SpanOverlapAccumulator[E]) NewSpanIterSeq2Stater() *SpanIterSeq2Stater[E]

Factory interface for stater creator.

type SpanUtil

type SpanUtil[E any] struct {

	// Compare function.  This function should be atomic and be able t compare the E type by return -1,0,1.
	Cmp func(a, b E) int

	// Turns validation on for new child objects created.
	Validate bool

	// Next value function, should return the next E.
	// The new E value must always be greater than the argument passed in
	Next func(e E) E

	// Flag denoting if overlaps that are adjacent should be consolidated.
	// Example of when true: 1,2 and 2,3 consolidate to 1,3, when false they do not consolidate.
	// Default is false.
	Consolidate bool

	// Denotes if objects created should sort by default.
	Sort bool

	SpanFactory func(begin, end E) SpanBoundry[E]
}

Core of the span utilities: Provides methods for processing ranges.

func NewSpanUtil

func NewSpanUtil[E any](cmp func(a, b E) int, next func(e E) E) *SpanUtil[E]

Creates an instance of *SpanUtil[E], the value of cmp is expected to be able to compare the Span.Begin and Span.End values. See: cmp.Compare for more info.

The default SpanFormat is set to: "Span: [%s -> %s], Tag: %s"

func (*SpanUtil[E]) Check

func (s *SpanUtil[E]) Check(next, current SpanBoundry[E]) error

This method is used to verify the sanity of the next and current value. The comparison operation is performed in 2 stages: 1. next.GetBegin() must be less than or equal to next.GetEnd(). 2. When the current value is not nil, then next must come after current. Returns nil when checks pass, the error is not nil when checks fail.

func (*SpanUtil[E]) Compare

func (s *SpanUtil[E]) Compare(a, b SpanBoundry[E]) int

This method is used to sort slice of spans in the accumulation order. For more details see: slices.SortFunc.

func (*SpanUtil[E]) ContainedBy

func (s *SpanUtil[E]) ContainedBy(a, b SpanBoundry[E]) (int, int)

This method is used to determine the outer bounds of ranges a and b. The first int represents comparing a.Begin to b.Begin and the second int represents comparing a.End to b.End.

func (*SpanUtil[E]) Contains

func (s *SpanUtil[E]) Contains(a SpanBoundry[E], b E) bool

Returns true if a contains b.

func (*SpanUtil[E]) CreateOverlapSpan

func (s *SpanUtil[E]) CreateOverlapSpan(list *[]SpanBoundry[E]) (SpanBoundry[E], bool)

Generates the "common overlapping span". This method assumes that all SpanBoundry instances in list overlap, and does not check if some SpanBoundry instances do not overlap. If some SpanBoundry instances do not overlap, then this will result in the creation of an invalid SpanBoundry.

How the "common overlapping span" is created is as follows:

  • Find the largest begin value in list and uses that as the begin value.
  • Find the smallest end value in list and uses that as the end value.

func (*SpanUtil[E]) FirstSpan

func (s *SpanUtil[E]) FirstSpan(list *[]SpanBoundry[E]) (SpanBoundry[E], bool)

Generates the first valid span representing the smallest overlapping set. If list is nil, or contains no spans, then the span is nil and the bool value will be false.

Finding the "initial span" is done by first finding the smallest begin and end values. The resulting span is referred to as the "initial span". If there is a begin value in list, that overlaps with the smallest end value, then the "initial span" begin value will also be set as the end value for the "initial span".

func (*SpanUtil[E]) GetOverlapIndexes

func (s *SpanUtil[E]) GetOverlapIndexes(overlap SpanBoundry[E], list *[]SpanBoundry[E]) *[]int

Given overlap and list, returns the indexs of the SpanBoundry instances that intersect with overlap.

func (*SpanUtil[E]) GetP

func (s *SpanUtil[E]) GetP(x E) *E

Wrapper function to return a pointer to the value passed in.

func (*SpanUtil[E]) NewCoaFromOlssSeq2

func (s *SpanUtil[E]) NewCoaFromOlssSeq2(driver iter.Seq2[int, *OverlappingSpanSets[E]]) *ColumnOverlapAccumulator[E]

This method takes a iter.Seq2 iterator of OverlappingSpanSets and initializes the ColumnOverlapAccumulator struct.

Warning

This methods creates an iter.Pull2 and exposes the resulting functions in the returned struct pointer. If you are using this method outside of the normal operations, you should a setup a defer call to ColumnOverlapAccumulator[E].Close() method to clean the instance up in order to prevent memory leaks or undefined behavior.

func (*SpanUtil[E]) NewColumnOverlapAccumulator

func (s *SpanUtil[E]) NewColumnOverlapAccumulator(next func() (int, *OverlappingSpanSets[E], bool), stop func()) *ColumnOverlapAccumulator[E]

This method takes the next and stop functions and creates a new fully initialized instance of ColumnOverlapAccumulator[E]. Each data set should have its own accumulator.

func (*SpanUtil[E]) NewColumnSets

func (s *SpanUtil[E]) NewColumnSets() *ColumnSets[E]

func (*SpanUtil[E]) NewOlssSeq2FromOlssChan

func (s *SpanUtil[E]) NewOlssSeq2FromOlssChan(c <-chan *OverlappingSpanSets[E]) iter.Seq2[int, *OverlappingSpanSets[E]]

Creates a channel iterator for channel of OverlappingSpanSets.

func (*SpanUtil[E]) NewSpan

func (s *SpanUtil[E]) NewSpan(a, b E) (SpanBoundry[E], error)

Creates a new span, error is nil unless a is greater than b.

func (*SpanUtil[E]) NewSpanOverlapAccumulator

func (s *SpanUtil[E]) NewSpanOverlapAccumulator() *SpanOverlapAccumulator[E]

Factory interface for the creation of SpanOverlapAccumulator[E]. Each set of data should have its on unique instance of an accumulator.

func (*SpanUtil[E]) NextSpan

func (s *SpanUtil[E]) NextSpan(start SpanBoundry[E], list *[]SpanBoundry[E]) (SpanBoundry[E], bool)

Finds the next common overlapping SpanBoundry[E] span in list after start, If the bool value is false, then there are no more elements in the set.

How the span is generated:

The begin is generated by calling the Next method.

The end value is found via the following process:

  • Find the smallest end greater than equal to the value generated by Next
  • If a span begin value is greater than the Next value and less than all other end values then it will be used as the new end value for the initial span.
  • Once the new begin and end values are found, a call to CreateOverlapSpan is made, with our "initial span" and "list" to create our new span.

func (*SpanUtil[E]) Ns

func (s *SpanUtil[E]) Ns(a, b E) SpanBoundry[E]

Creates a new SpanBoundry[E], but does not do any error checking.

func (*SpanUtil[E]) Overlap

func (s *SpanUtil[E]) Overlap(a, b SpanBoundry[E]) bool

Returns true if a overlaps with b or if be overlaps with a.

Directories

Path Synopsis
examples
ErrorExample command
beyondbasics command
example01 command
multichan command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL