Skip to content

Commit

Permalink
Merge bdde28e into bfada04
Browse files Browse the repository at this point in the history
  • Loading branch information
hovadur committed Jan 31, 2021
2 parents bfada04 + bdde28e commit d2dadbd
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 191 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci_pipline.yml
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest

container:
image: google/dart:latest
image: google/dart:beta

steps:
- uses: actions/checkout@v2
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,8 @@
# Changelog

## 2.0.0-nullsafety.0
- null safety

## 1.0.0
- `injector` dependency removed
- `lib/integers.dart`, `lib/range.dart` export files removed
Expand Down
19 changes: 10 additions & 9 deletions lib/src/generators/integers.dart
@@ -1,14 +1,15 @@
import 'package:xrange/src/range/num_range.dart';

Iterable<int> integers(int lower, int upper, {
Iterable<int> integers(
int lower,
int upper, {
int step = 1,
bool lowerClosed = true,
bool upperClosed = false,
}) => NumRange(
lower: lower,
upper: upper,
lowerClosed: lowerClosed,
upperClosed: upperClosed,
)
.values(step: step)
.map((el) => el.toInt());
}) =>
NumRange(
lower: lower,
upper: upper,
lowerClosed: lowerClosed,
upperClosed: upperClosed,
).values(step: step).map((el) => el.toInt());
33 changes: 22 additions & 11 deletions lib/src/range/num_range.dart
@@ -1,9 +1,16 @@
import 'package:xrange/src/range/range.dart';

class NumRange extends Range<num> {
NumRange({num lower, num upper, bool lowerClosed, bool upperClosed}) :
super(lower: lower, upper: upper, lowerClosed: lowerClosed,
upperClosed: upperClosed);
NumRange(
{required num lower,
required num upper,
bool lowerClosed = false,
bool upperClosed = false})
: super(
lower: lower,
upper: upper,
lowerClosed: lowerClosed,
upperClosed: upperClosed);

NumRange.open(num lower, num upper) : super.open(lower, upper);

Expand All @@ -25,29 +32,33 @@ class NumRange extends Range<num> {

NumRange.singleton(num value) : super.singleton(value);

int get firstValue {
if (lower == null) {
int? get firstValue {
final l = lower;
if (l == null) {
return null;
}
return (lowerClosed ? lower : lower + 1).toInt();
return (lowerClosed ? l : l + 1).toInt();
}

int get lastValue {
if (upper == null) {
int? get lastValue {
final u = upper;
if (u == null) {
return null;
}
return (upperClosed ? upper : upper - 1).toInt();
return (upperClosed ? u : u - 1).toInt();
}

Iterable<num> values({int step = 1}) sync* {
if (step <= 0) {
throw ArgumentError.value(step, 'A step should be greater than 0');
}
if (!bounded) {
final f = firstValue;
final l = lastValue;
if (!bounded || l == null || f == null) {
throw Exception('There is no bound, '
'${lower == null ? '`lower`' : '`upper`'} is not defined');
}
for (var val = firstValue; val <= lastValue; val += step) {
for (var val = f; val <= l; val += step) {
yield val;
}
}
Expand Down
105 changes: 70 additions & 35 deletions lib/src/range/range.dart
Expand Up @@ -6,9 +6,13 @@
class Range<T extends Comparable<T>> {
/// An interval constructed from its [Bound]s.
///
/// If [lowerBound] or [upperBound] are `null`, then the interval is unbounded
/// If [lowerBound] or [upperBound] are `false`, then the interval is unbounded
/// in that direction.
Range({this.lower, this.upper, this.lowerClosed, this.upperClosed}) {
Range(
{this.lower,
this.upper,
this.lowerClosed = false,
this.upperClosed = false}) {
_checkNotOpenAndEqual(_checkBoundOrder());
}

Expand Down Expand Up @@ -45,16 +49,18 @@ class Range<T extends Comparable<T>> {
}

/// `[`[lower]`.. +∞ )`
Range.atLeast(this.lower)
Range.atLeast(T l)
: upper = null,
lower = l,
lowerClosed = true,
upperClosed = false {
if (lower == null) throw ArgumentError('lower cannot be null');
}

/// `( -∞ ..`[upper]`]`
Range.atMost(this.upper)
Range.atMost(T u)
: lower = null,
upper = u,
lowerClosed = false,
upperClosed = true {
if (upper == null) throw ArgumentError('upper cannot be null');
Expand Down Expand Up @@ -84,9 +90,7 @@ class Range<T extends Comparable<T>> {
: lower = value,
upper = value,
lowerClosed = true,
upperClosed = true {
if (value == null) throw ArgumentError('value cannot be null');
}
upperClosed = true;

/// The minimal interval which [contains] each value in [values].
///
Expand Down Expand Up @@ -121,23 +125,25 @@ class Range<T extends Comparable<T>> {
var upperClosed = interval.upperClosed;
while (iterator.moveNext()) {
interval = iterator.current;
if (interval.lower == null) {
final l = interval.lower;
if (l == null) {
lower = null;
lowerClosed = false;
if (upper == null) break;
} else {
if (lower != null && Comparable.compare(lower, interval.lower) >= 0) {
lower = interval.lower;
if (lower != null && Comparable.compare(lower, l) >= 0) {
lower = l;
lowerClosed = lowerClosed || interval.lowerClosed;
}
}
if (interval.upper == null) {
final u = interval.upper;
if (u == null) {
upper = null;
upperClosed = false;
if (lower == null) break;
} else {
if (upper != null && Comparable.compare(upper, interval.upper) <= 0) {
upper = interval.upper;
if (upper != null && Comparable.compare(upper, u) <= 0) {
upper = u;
upperClosed = upperClosed || interval.upperClosed;
}
}
Expand All @@ -150,10 +156,10 @@ class Range<T extends Comparable<T>> {
}

/// The lower bound value if it exists, or null.
final T lower;
final T? lower;

/// The upper bound value if it exists, or null.
final T upper;
final T? upper;

/// Whether `this` contains [lower]. [lower] may also be contained
/// if [upperClosed] and [lower] equals [upper].
Expand Down Expand Up @@ -185,13 +191,17 @@ class Range<T extends Comparable<T>> {
bool get upperBounded => upper != null;

/// Whether `this` [contains] any values.
bool get isEmpty => _boundValuesEqual && !isClosed;
bool get isEmpty => _boundValuesEqual && !isClosed;

/// Whether `this` [contains] exactly one value.
bool get isSingleton => _boundValuesEqual && isClosed;

bool get _boundValuesEqual =>
bounded && Comparable.compare(lower, upper) == 0;
bool get _boundValuesEqual {
final l = lower;
final u = upper;
if (l == null || u == null) return false;
return bounded && Comparable.compare(l, u) == 0;
}

/// Returns an interval which contains the same values as `this`, except any
/// closed bounds become open.
Expand All @@ -202,8 +212,10 @@ class Range<T extends Comparable<T>> {
Range<T> get closure => isClosed ? this : Range<T>.closed(lower, upper);

int _checkBoundOrder() {
if (lower == null || upper == null) return -1;
final compare = Comparable.compare(lower, upper);
final l = lower;
final u = upper;
if (l == null || u == null) return -1;
final compare = Comparable.compare(l, u);
if (compare > 0) {
throw ArgumentError('upper must not be less than lower');
}
Expand All @@ -218,12 +230,14 @@ class Range<T extends Comparable<T>> {

/// Whether `this` contains [test].
bool contains(T test) {
if (lower != null) {
final lowerCompare = Comparable.compare(lower, test);
final l = lower;
if (l != null) {
final lowerCompare = Comparable.compare(l, test);
if (lowerCompare > 0 || (!lowerClosed && lowerCompare == 0)) return false;
}
if (upper != null) {
final upperCompare = Comparable.compare(upper, test);
final u = upper;
if (u != null) {
final upperCompare = Comparable.compare(u, test);
if (upperCompare < 0 || (!upperClosed && upperCompare == 0)) return false;
}
return true;
Expand All @@ -235,9 +249,17 @@ class Range<T extends Comparable<T>> {
if (!other.lowerBounded) {
return false;
} else {
final lowerCompare = Comparable.compare(lower, other.lower);
if (lowerCompare > 0 || (lowerCompare == 0 && !lowerClosed &&
other.lowerClosed)) {
final l = lower;
if (l == null) {
return false;
}
final ol = other.lower;
if (ol == null) {
return false;
}
final lowerCompare = Comparable.compare(l, ol);
if (lowerCompare > 0 ||
(lowerCompare == 0 && !lowerClosed && other.lowerClosed)) {
return false;
}
}
Expand All @@ -246,9 +268,17 @@ class Range<T extends Comparable<T>> {
if (!other.upperBounded) {
return false;
} else {
final upperCompare = Comparable.compare(upper, other.upper);
if (upperCompare < 0 || (upperCompare == 0 && !upperClosed &&
other.upperClosed)) {
final u = upper;
if (u == null) {
return false;
}
final ou = other.upper;
if (ou == null) {
return false;
}
final upperCompare = Comparable.compare(u, ou);
if (upperCompare < 0 ||
(upperCompare == 0 && !upperClosed && other.upperClosed)) {
return false;
}
}
Expand All @@ -260,20 +290,26 @@ class Range<T extends Comparable<T>> {
/// [Range]).
bool connectedTo(Range<T> other) {
bool overlapping(Range<T> lower, Range<T> upper) {
if (lower.lower == null || upper.upper == null) return true;
final comparison = lower.lower.compareTo(upper.upper);
final l = lower.lower;
final u = upper.upper;
if (l == null || u == null) return true;
final comparison = l.compareTo(u);
return comparison < 0 ||
(comparison == 0 && (lower.lowerClosed || upper.upperClosed));
}

return overlapping(this, other) && overlapping(other, this);
}

@override
int get hashCode => lower.hashCode ^ upper.hashCode ^ lowerClosed.hashCode ^
int get hashCode =>
lower.hashCode ^
upper.hashCode ^
lowerClosed.hashCode ^
upperClosed.hashCode;

@override
bool operator == (Object other) =>
bool operator ==(Object other) =>
other is Range<T> &&
lower == other.lower &&
upper == other.upper &&
Expand All @@ -286,5 +322,4 @@ class Range<T extends Comparable<T>> {
final close = '${upper ?? '+∞'}${upperClosed ? ']' : ')'}';
return '$open..$close';
}

}
12 changes: 5 additions & 7 deletions pubspec.yaml
@@ -1,15 +1,13 @@
name: xrange
version: 1.0.0
version: 2.0.0-nullsafety.0
description: Provides classes and methods allowing to work with ranges
homepage: https://github.com/gyrdym/xrange

environment:
sdk: '>=2.7.0 <3.0.0'
sdk: '>=2.12.0-0 <3.0.0'

dev_dependencies:
build_runner: ^1.1.2
build_test: ^0.10.2
mockito: ^4.1.1
pedantic: ^1.9.2
test: ^1.2.0
mockito: ^5.0.0-nullsafety.5
pedantic: ^1.10.0-nullsafety.3
test: ^1.16.0-nullsafety.17
test_coverage: ^0.5.0
6 changes: 6 additions & 0 deletions test/num_range_test.dart
Expand Up @@ -74,6 +74,12 @@ void main() {
expect(range.firstValue, isNull);
});

test('should return `0` if the singleton is 0', () {
final range = NumRange.singleton(0);
expect(range.firstValue, 0);
expect(range.lastValue, 0);
});

test('should return a finite number if the range is open', () {
final range = NumRange.open(-20, 30);
expect(range.firstValue, -19);
Expand Down

0 comments on commit d2dadbd

Please sign in to comment.