Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RangeSet and discontiguous collection operations #28161

Merged
merged 26 commits into from Feb 22, 2020

Conversation

natecook1000
Copy link
Member

@natecook1000 natecook1000 commented Nov 8, 2019

This adds the RangeSet and DiscontiguousSlice types, as well as collection operations for working with discontiguous ranges of elements. This also adds a COWLoggingArray type to the test suite to verify that mutable collection algorithms don't perform unexpected copy-on-write operations when mutating slices mid-operation.

Still to do:

  • Add documentation for RangeSet set algebra methods (since we aren't conforming, we don't inherit the docs from the protocol)
  • Add versioning attributes

This adds the RangeSet and DiscontiguousSlice types, as well as collection
operations for working with discontiguous ranges of elements. This also adds
a COWLoggingArray type to the test suite to verify that mutable collection
algorithms don't perform unexpected copy-on-write operations when mutating
slices mid-operation.
@natecook1000 natecook1000 added the swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review label Nov 8, 2019
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@theblixguy theblixguy added swift evolution approved Flag → feature: A feature that was approved through the Swift evolution process and removed swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review labels Feb 5, 2020
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000 natecook1000 marked this pull request as ready for review February 14, 2020 23:17
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

/// A set of ranges of any comparable value.
/// A set of any comparable value, represented by ranges.
///
/// You can use a range set to efficiently represent a set `Comparable` values
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“set of

//
//===----------------------------------------------------------------------===//

/// A set of any comparable value, represented by ranges.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“any comparable value__s__”?

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

Copy link
Contributor

@milseman milseman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talked with Nate on the phone, recording some points here.

/// - `_indicesOfRange(12..<19) == 1..<2`
/// - `_indicesOfRange(17..<19) == 2..<2`
/// - `_indicesOfRange(12..<22) == 1..<3`
func _indicesOfRange(_ range: Range<Bound>) -> Range<Int> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicit internal

/// - Complexity: O(*n* log *n*) where *n* is the number of elements.
/// - Precondition:
/// `n == distance(from: range.lowerBound, to: range.upperBound)`
@usableFromInline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can probably drop

///
/// - Complexity: O(log *n*), where *n* is the length of this collection if
/// the collection conforms to `RandomAccessCollection`, otherwise O(*n*).
@usableFromInline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can probably drop

/// - Complexity: O(*n* log *n*) where *n* is the length of the collection.
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
@discardableResult
@inlinable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop inlinable, doesn't buy us anything as written. If you add the rotate fast path, then hand-outline the rest of this code so it can be inlined. The end result is the same at run-time for users, but we have less code size and branches in user code.

/// - Returns: The new index of the element that was first pre-rotation.
///
/// - Complexity: O(*n*)
@usableFromInline
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can probably drop

/// - index: The index to include in the range set. `index` must be a
/// valid index of `collection` that isn't the collection's `endIndex`.
/// - collection: The collection that contains `index`.
public init<S, C>(_ indices: S, within collection: C)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a candidate for inlinable, depending on need. It's a bigger code size tradeoff than insert below.

///
/// - Complexity: O(*n*), where *n* is the number of ranges in the range
/// set.
public mutating func remove<C>(_ index: Bound, within collection: C)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inlinable could be a win.

/// - Complexity: O(*n*), where *n* is the number of ranges in the range
/// set.
@usableFromInline
internal func _inverted<C>(within collection: C) -> RangeSet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Candidate for inlinable if this is called heavily in other inlinable code.

internal struct _Pair<Element>: RandomAccessCollection {
var pair: (first: Element, second: Element)

init(_ first: Element, _ second: Element) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explicit internal on all these entities

//
//===----------------------------------------------------------------------===//

struct _RangeSetStorage<T: Comparable> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explicit internal

In particular, only adding inlining when functions can reduce or
eliminate generic parameters. I'll follow up with benchmarks to test
the effects of adding more inlinability.
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

where Base: BidirectionalCollection
{
public func index(before i: Index) -> Index {
_precondition(i != startIndex, "Can't move index before startIndex")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a policy for when we include out of bounds checks in index(after:)/index(before:)?

/// - distance(from: lhs.lowerBound, to: p) == distance(from:
/// rhs.lowerBound, to: q)
/// - p == lhs.upperBound || q == rhs.upperBound
mutating func _swapNonemptySubrangePrefixes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: missing an explicit internal

With availability annotations, the RangeSet subscript overloads aren't coming
through for these tests.
@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000
Copy link
Member Author

@swift-ci Please smoke test

@natecook1000 natecook1000 merged commit c6183ee into apple:master Feb 22, 2020
@natecook1000 natecook1000 deleted the nc_rangeset branch February 22, 2020 21:33
@drodriguez
Copy link
Collaborator

@compnerd: I am far from a real computer, but it seems that the Windows failures might simply be fixed moving the RangeSet.swift from test to validation-test. I only see import StdlibCollectionUnitests in the validation-test directory. I cannot find where that path is set, though.

@compnerd
Copy link
Collaborator

Validation test just effectively disables it (I need to rebase my patch to enable that on the Azure agents). Could just be something we are setting for that test suite. I'm waiting for an update to complete; Ill look at it once the update is complete.

@compnerd
Copy link
Collaborator

I think that there is a missing dependency

natecook1000 added a commit to natecook1000/swift that referenced this pull request May 15, 2020
natecook1000 added a commit that referenced this pull request May 16, 2020
* Revert "test: move RangeSet test into validation-test"

This reverts commit e9aaef4.

* Revert "Add RangeSet and discontiguous collection operations (#28161)"

This reverts commit c6183ee.
switch (lhs._storage, rhs._storage) {
case (.empty, .empty):
return true
case (.empty, .singleRange), (.singleRange, .empty):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When case .singleRange is empty, doesn’t it equal to case .empty?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
swift evolution approved Flag → feature: A feature that was approved through the Swift evolution process
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants