common-range-tools

Overview
The common-range-tools crate, is a library that, can be used to find all common intersections for ranges of generic types. It interoperates with the built in range types for rust via the std::ops::RangeBounds trait. When working with primitive numbers, the increment and decrementing of values are checked (see working with floats, for the exception). Support for all primitive number types in rust are implemented via the NumberIncDecCpCmp object.
For dealing with ranges beyond just intersections of numbers see: Generic Data Types. For working with custom data structures see: Beyond Generics. For working with custom Ranges and range factories see: Internal Range Trait. For consolidating duplicate and overlapping ranges see Consolidation of ranges. For finding intersections between muliple Iterator instances, see: Intersections of multiple Itertors.
Example
This is the most basic example, using the default values from NumberIncDecCpCmp. The OverlapIter is a DoubleEndedIterator and can be reversed.
use Intersector;
Any Range Example
This example converts std::ops::RangeBounds instances to std::ops::RangeInclusive. The bounds to the left or right of .. represent the ($ty::MIN)..($ty::MAX), defined by the NumberIncDecCpCmp object. The min and max numbers can be changed, but this example uses the defaults.
// Import the Intersector
use Intersector;
Numeric Boundries
When working with boundries it is useful to be able to control how ranges are interpeted. The defaults provided by NumberIncDecCpCmp are useful but do not cover all casees. The internals of this crate allow for setting various options to control how both ranges and intersections are computed.
In this example we set the following:
| Field | What it does |
|---|---|
| step | sets the value used to progress to the next begin or end value for a given range |
| rebound | sets the value used to redefine a range value fom an instance of: std::ops::Bound::Excluded |
| min | the minimum value for ranges in the context of: .. |
| max | the maximum vaue for ranges in the context of: .. |
// Import the Intersector
use Intersector;
Working with Floats
When working with floating points, it’s nessesary to understand how floats are handled by the NumberIncDecCpCmp. Floating point numbers are in a word imprecise; The internals of NumberIncDecCpCmp does not check f32 or f64 for over or underflow; The internals of NumberIncDecCpCmp simply checks that the values properly increment and decrement.
use ;
Generic Data types
The AnyIncDecCpCmp object supports working with any data type, provided it implements: PartialOrd, std::ops::Add, std::ops::Sub, Copy, and Clone. When working with generics, the value used by step and rebound values do not have to be the same type as the values used by a range. A practical example of this is how std::time::Duration and std::time::SystemTime handle std::ops::Add and std::ops::Sub.
This is an example that shows how to use std::time::Duration to provide the step and rebound values and std::time::SystemTime to operate as the range values:
use Intersector;
use ;
Beyond Generics
In some cases the range values do not implement: PartialOrd, std::ops::Add, std::ops::Sub, Copy, Clone or do so in a way that is incompatable with the required data structure used as a value for the range. The internals of OverlapIter use a proxy layer which can be customized to meet most requirements. This example shows how to work with ragnes of custom data strcutres.
use ;
const MIN: Point = Point ;
const MAX: Point = Point ;
Internal Range Trait
Rust has no single trait representing rages aside from std::ops::RangeBounds, which can require recomputing the begin and or end values of a range on each evaluation. To work around this the internals of this crate use a common trait range type of GetBeginEnd. There is also a factory trait for creating instances called GetBeginEndOption. This example shows how to create and use both the factory: GetBeginEndOption and the range: GetBeginEnd. As a note the GetBeginEnd trait is implemnted for std::ops::RangeInclusive for the internals of this crate.
use ;
Consolidation of ranges
The Consolidate object can be used to consolidate duplicate and overlapping ranges via an Iterator of ranges. It is recommended to convert an instance of Consolidate into an instance of ConsolidateChecker instance to verify the integrity of the data returned by the Iterator.
The ranges returned by the Iterator must be in ConsolidationOrder.
- For ConsolidationOrder::Forward the expected order is: start asc, end desc. For more information see: crate::sort_forward.
- For ConsolidationOrder::Reverse the expected order is: end desc, start asc. For more information see: crate::sort_reverse.
This example demonstrates how to use Consolidate wrapped in an instance of ConsolidateChecker using ConsolidationOrder::Forward:
use ;
// Resulting Output will be:
// Outer Range: 1->5
// Row: 0, Range: 1->4
// Row: 1, Range: 3->5
// Outer Range: 10->12
// Row: 2, Range: 10->12
// Row: 3, Range: 10->11
// Error: Out of Forward Sequence, Expected: Before|Last|Overlap, got: After,
// Produced range: 1->13
// Caused by: Row: 4, Range: 13->13
// Caused by: Row: 5, Range: 1->2
Intersections of multiple Itertors
The Columns object is a factory can be used to construct an Iterator that steps through multiple Iterator instances of ranges that can contain duplicate and overlapping ranges that intersect with one another. Each Column added to Columns is wrapped in an instance of ConsolidateChecker to ensure that the consolidation is occuring in the expected ConsolidationOrder. The ranges returned by the Iterator must be in ConsolidationOrder, see: Consolidation of ranges for more information. Finding the intersections from multiple Iterator instances is a complex process and is error prone if the data is not provided in the proper order.
The ranges returned by each Iterator must be in same ConsolidationOrder as all other Iterator instances.
- For ConsolidationOrder::Forward the expected order is: start asc, end desc. For more information see: crate::sort_forward.
- For ConsolidationOrder::Reverse the expected order is: end desc, start asc. For more information see: crate::sort_reverse.
This example demonstrates how to create a ColumnsIter from a Columns instance and walk the results. This example also includes an example of how to use crate::sort_forward.
use ;
// The resulting output will be
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | Overlap | State(id) | Column(A) | Column(B) | Column(C) |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 0 ->2 | Ok(0) | [0->11](0(0->11),1(2->3),2(7->9)) | | |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 3 ->5 | Ok(1) | [0->11](0(0->11),1(2->3),2(7->9)) | | [3->9](0(3->9),1(3->4),2(4->6)) |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 6 ->9 | Ok(2) | [0->11](0(0->11),1(2->3),2(7->9)) | [6->22](0(6->9),1(6->9),2(6->7),3(7->11),4(9->9),5(11->22)) | [3->9](0(3->9),1(3->4),2(4->6)) |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 10->11 | Ok(3) | [0->11](0(0->11),1(2->3),2(7->9)) | [6->22](0(6->9),1(6->9),2(6->7),3(7->11),4(9->9),5(11->22)) | |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 12->21 | Ok(4) | | [6->22](0(6->9),1(6->9),2(6->7),3(7->11),4(9->9),5(11->22)) | |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 22->22 | Ok(5) | [22->33](3(22->33)) | [6->22](0(6->9),1(6->9),2(6->7),3(7->11),4(9->9),5(11->22)) | |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 23->29 | Ok(6) | [22->33](3(22->33)) | | |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 30->33 | Ok(7) | [22->33](3(22->33)) | | [30->41](3(30->41)) |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 34->39 | Ok(8) | [34->39](4(34->39)) | | [30->41](3(30->41)) |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
// | 40->41 | Ok(9) | | | [30->41](3(30->41)) |
// +---------+-----------+-----------------------------------+-------------------------------------------------------------+-----------------------------------+
Motivation
In truth there doesn’t seem to be a library on crates.io provides the following functionality:
- A range intersection library that handles columns of Iterator ranges and progress through those ranges correctly.
- An intersection library that could be quickly extended to work with any data structure.
- An intersection library that can support any range type via a a common trait.
- A reversable range intersection iterator.
Other implementations: