Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
# Contributing to SpanExtensions.Net

### Did you catch a bug?

**!!!Important!!!**
If the bug poses a threat to the security of dependent applications, please refer to our [Security Policy](SECURITY.md).
If the bug poses a threat to the security of dependent applications, please refer to our [Security Policy](SECURITY.md).

There are two options available:

1. You can open an issue describing exactly:
- What is the bug and what did you expect to happen?
- How may it be reproduced (It is often helpful to include images or alike).
- Include the Version of SpanExtensions.Net affected.
2. Even better, you can fix the issue yourself by submitting a pull reqest.
1. You can open an issue describing exactly:
- What the bug is and what you expected to happen?
- How it may be reproduced (It is often helpful to include images or alike).
- hich versions of SpanExtensions.Net affected.
2. Even better, fix any issue yourself by submitting a pull request.

### Do you have a feature request?

Tell us all about it (here)[]. Please consider however, that features should generally be implementable via Extension Methods, otherwise they are unlikely to be accepted.

### Did you notice a mistake or an error in the documentation?
### Did you notice a mistake or an error in the documentation?

If you found a spelling mistake or an ambigous or unclear sentence or phrase in the XML documentation in C# source files or in any of the documentation for this repository (for example: Readme.md), do one of the following:
If you found a spelling mistake or an ambigous or unclear sentence or phrase in the XML documentation in C# source files or in any of the documentation for this repository (for example: Readme.md), do one of the following:

[Open an **Issue**](https://github.com/draconware-dev/SpanExtensions.Net/issues/new/choose) with the tag `documentation`. It is recommended to follow the [example template](https://github.com/draconware-dev/SpanExtensions.Net/issues/new?assignees=&labels=documentation&projects=&template=documentation-report.md&title=Documentation+Error).
[Open an **Issue**](https://github.com/draconware-dev/SpanExtensions.Net/issues/new/choose) with the tag `documentation`. It is recommended to follow the [example template](https://github.com/draconware-dev/SpanExtensions.Net/issues/new?assignees=&labels=documentation&projects=&template=documentation-report.md&title=Documentation+Error).

**OR**

[Open a **Pull Request**](https://github.com/draconware-dev/SpanExtensions.Net/compare) linked to an **Issue** tagged `documentation`, as grammatical errors are usually easier to fix, than they are to describe. In this case it is not necessary to describe the error in detail, a brief report with reasoning should do, unless it is not evident from the Pull Request, what actually was changed or why it was changed.
[Open a **Pull Request**](https://github.com/draconware-dev/SpanExtensions.Net/compare) linked to an **Issue** tagged `documentation`, as grammatical errors are usually easier to fix, than they are to describe. In this case it is not necessary to describe the error in detail, a brief report with reasoning should do, unless it is not evident from the Pull Request, what actually was changed or why it was changed.
75 changes: 4 additions & 71 deletions .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,84 +5,17 @@
[![GitHub License](https://img.shields.io/github/license/draconware-dev/SpanExtensions.Net)](https://github.com/draconware-dev/SpanExtensions.Net/blob/main/LICENSE)

## About
**`ReadonlySpan<T>`** and **`Span<T>`** are great Types in _C#_, but unfortunately working with them can sometimes be sort of a hassle and some use cases seem straight up impossible, even though they are not.

**SpanExtensions.Net** aims to help developers use `ReadonlySpan<T>` and `Span<T>` more **productively**, **efficiently** and **safely** and write overall more **performant** Programs.

Never again switch back to using `string` instead of `ReadonlySpan<T>`, just because the method you seek is not supported.

**SpanExtensions.Net** provides alternatives for many missing Extension Methods for **`ReadonlySpan<T>`** and **`Span<T>`**, ranging from `string.Split()` over `Enumerable.Skip()` and `Enumerable.Take()` to an improved `ReadOnlySpan<T>.IndexOf()`.
Never again switch back to using `string` instead of `ReadonlySpan<T>`, just because the method you seek is not supported.

## Methods
The following **Extension Methods** are contained:

#### String Methods made available for **`ReadonlySpan<T>`** and **`Span<T>`**:

- `(ReadOnly-)Span<T>.Split(T delimiter)`
- `(ReadOnly-)Span<T>.Split(T delimiter, int count)`
- `(ReadOnly-)Span<T>.Split(T delimiter, StringSplitOptions options)`
- `(ReadOnly-)Span<T>.Split(T delimiter, StringSplitOptions options, int count)`
- `(ReadOnly-)Span<T>.Split(ReadOnlySpan<T> delimiters)`
- `(ReadOnly-)Span<T>.Split(ReadOnlySpan<T> delimiters, int count)`
- `(ReadOnly-)Span<T>.Split(ReadOnlySpan<T> delimiters, StringSplitOptions options)`
- `(ReadOnly-)Span<T>.Split(ReadOnlySpan<T> delimiters, StringSplitOptions options, int count)`
- `(ReadOnly-)Span<T>.SplitAny(ReadOnlySpan<T> delimiters)`
- `(ReadOnly-)Span<T>.SplitAny(ReadOnlySpan<T> delimiters, int count)`
- `(ReadOnly-)Span<T>.SplitAny(ReadOnlySpan<T> delimiters, StringSplitOptions options)`
- `(ReadOnly-)Span<T>.SplitAny(ReadOnlySpan<T> delimiters, StringSplitOptions options, int count)`
- `(ReadOnly-)Span<T>.Remove(int startIndex)`
- `Span<T>.Replace(T oldT, T newT)`

#### Linq Methods made available for **`ReadonlySpan<T>`** and **`Span<T>`**:

- `(ReadOnly-)Span<T>.All(Predicate<T> predicate)`
- `(ReadOnly-)Span<T>.Any(Predicate<T> predicate)`
- `(ReadOnly-)Span<T>.Average()`
- `(ReadOnly-)Span<T>.Sum()`
- `(ReadOnly-)Span<T>.Skip(int count)`
- `(ReadOnly-)Span<T>.Take(int count)`
- `(ReadOnly-)Span<T>.SkipLast(int count)`
- `(ReadOnly-)Span<T>.Takelast(int count)`
- `(ReadOnly-)Span<T>.SkipWhile(Predicate<T> condition)`
- `(ReadOnly-)Span<T>.TakeWhile(Predicate<T> condition)`
- `(Readonly-)Span<T>.First()`
- `(Readonly-)Span<T>.First(Predicate<T> predicate)`
- `(Readonly-)Span<T>.FirstOrDefault()`
- `(Readonly-)Span<T>.FirstOrDefault(Predicate<T> predicate)`
- `(Readonly-)Span<T>.FirstOrDefault(T defaultValue)`
- `(Readonly-)Span<T>.FirstOrDefault(Predicate<T> predicate, T defaultValue)`
- `(Readonly-)Span<T>.Last()`
- `(Readonly-)Span<T>.Last(Predicate<T> predicate)`
- `(Readonly-)Span<T>.LastOrDefault()`
- `(Readonly-)Span<T>.LastOrDefault(Predicate<T> predicate)`
- `(Readonly-)Span<T>.LastOrDefault(T defaultValue)`
- `(Readonly-)Span<T>.LastOrDefault(Predicate<T> predicate, T defaultValue)`
- `(Readonly-)Span<T>.Single()`
- `(Readonly-)Span<T>.Single(Predicate<T> predicate)`
- `(Readonly-)Span<T>.SingleOrDefault()`
- `(Readonly-)Span<T>.SingleOrDefault(Predicate<T> predicate)`
- `(Readonly-)Span<T>.SingleOrDefault(T defaultValue)`
- `(Readonly-)Span<T>.SingleOrDefault(Predicate<T> predicate, T defaultValue)`
- `(Readonly-)Span<T>.ElementAt(int index)`
- `(Readonly-)Span<T>.ElementAt(Index index)`
- `(Readonly-)Span<T>.ElementAtOrDefault(int index)`
- `(Readonly-)Span<T>.ElementAtOrDefault(Index index)`
- `(Readonly-)Span<T>.ElementAtOrDefault(int index, T defaultValue)`
- `(Readonly-)Span<T>.ElementAtOrDefault(Index index, T defaultValue)`
- `(Readonly-)Span<T>.Min()`
- `(Readonly-)Span<T>.Min(Func<TSource, TResult> selector)`
- `(Readonly-)Span<T>.MinBy(Func<TSource, TKey> keySelector)`
- `(Readonly-)Span<T>.MinBy(Func<TSource, TKey> keySelector, IComparer<TKey> comparer)`
- `(Readonly-)Span<T>.Max()`
- `(Readonly-)Span<T>.Max(Func<TSource, TResult> selector)`
- `(Readonly-)Span<T>.MaxBy(Func<TSource, TKey> keySelector)`
- `(Readonly-)Span<T>.MaxBy(Func<TSource, TKey> keySelector, IComparer<TKey> comparer)`
**SpanExtensions.Net** aims to help developers use `ReadonlySpan<T>` and `Span<T>` more **productively**, **efficiently** and **safely** and write overall more **performant** Programs.

## Contributing

Thank you for your interest in contributing to this project - Please see [Contributing](CONTRIBUTING.md)!

## License

Copyright (c) draconware-dev. All rights reserved.
Copyright (c) draconware-dev. All rights reserved.

Licensed under the [MIT](../LICENSE) License.
2 changes: 1 addition & 1 deletion .github/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

## Reporting a Vulnerability

If you find a security vulnerability please message **draconware@gmail.com** about the vulnerability and do not, **under no circumstances**, open a public issue.
If you find a security vulnerability please message **draconware@gmail.com** about the vulnerability and do not, **under no circumstances**, open a public issue.
69 changes: 46 additions & 23 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,30 @@
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres not (yet) to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) from v2.0 onwards.

## [2.0.0] - 2025-9-28

### Fixed

- an empty array not being treated as whitespace by range-based Split methods (https://github.com/draconware-dev/SpanExtensions.Net/pull/27)
- the SearchValues-overload of range-based Split methods.

### Changed

- vectorized `Min()` and `Max()`.
- transitioned to semantic versioning.

## [1.5.1] - 2024-12-14

### Fixed

- incorrect ranges returned by the range-based Split method for versions prior to .Net 9.

### Changed

- moved MemoryExtensions containing range-based Split method for versions prior to .Net 9 from `System` to `SpanExtensions`.
- grammatical issues in some documentation comments.

## [1.5.1] - 2024-12-14

Expand All @@ -22,49 +45,49 @@ and this project adheres not (yet) to [Semantic Versioning](https://semver.org/s

- implementations of the newly introduced Span.Split methods from .Net 9 for any version prior to .Net 9 to maintain backwards-compatibility across .Net versions.

### Changed
### Changed

- Split extension methods to refer to new split implementations compatible to the ones in .Net 9 and made .Net 9 split methods the default from that version onwards. The original split methods are still accessible as static methods.
- original Split methods are no longer available without passing span as a parameter.

## [1.4.2] - 2024-10-29

### Added
### Added

- `(Readonly-)Span<T>.Count(...)` overloads to all versions before .Net 8 matching these introduced in .Net 8.

### Changed
### Changed

- blocked compilation on .Net 9 due to known incompatibilities, which are to be resolved in version 1.5.
- blocked compilation on .Net 9 due to known incompatibilities, which are to be resolved in version 1.5.

## [1.4.1] - 2024-9-9

### Fixed
### Fixed

- a collision between the `Span<T>.Replace` method provided by SpanExtensions and the one newly provided by .Net 8.

## [1.4] - 2024-9-3

### Added
### Added

- `(Readonly-)Span<T>.Count()`
- `(Readonly-)Span<T>.Count(Predicate<T> predicate)`

### Changed
### Changed

- `Split` to throw an `ArgumentException` instead of an `InvalidCountExceedingBehaviourException`

### Removed
### Removed

- `InvalidCountExceedingBehaviourException`

### Fixed
### Fixed

- various issues with `Split` (https://github.com/draconware-dev/SpanExtensions.Net/pull/11)
- various issues with `Split` (https://github.com/draconware-dev/SpanExtensions.Net/pull/11)

## [1.3] - 2024-3-19

### Added
### Added

- Compatibility with **.Net 8**
- `(Readonly-)Span<T>.First()`
Expand Down Expand Up @@ -102,42 +125,42 @@ and this project adheres not (yet) to [Semantic Versioning](https://semver.org/s
- nuget badge to README (https://github.com/draconware-dev/SpanExtensions.Net/pull/12)
- `CountExceedingBehaviour`, which is passed to Split, defining how to properly handle its remaining elements.

### Changed
### Changed

- documentation comments to better reflect the dotnet style (https://github.com/draconware-dev/SpanExtensions.Net/pull/8)
- swapped order of `count` and `stringSplitOptions arguments` in `Split` methods.
- renamed argument `span` in `Split` methods to `source`.

### Fixed
### Fixed

- empty spans being ignored if they are the last element to be returned from `Split` and are therefore not returned. (https://github.com/draconware-dev/SpanExtensions.Net/pull/10)

## [1.2.1] - 2024-1-25

### Fixed
### Fixed

- Ambiguous Extension Methods (https://github.com/draconware-dev/SpanExtensions.Net/issues/6)
- Correctness of some documentation comments
- Correctness of some documentation comments

## [1.2.0] - 2023-12-28

### Added
### Added

- Missing documentation comments

### Fixed
### Fixed

- Grammatical issues in some documentation comments

### Changed
### Changed

- moved custom Enumerators into `SpanExtensions.Enumerators`
- moved custom Enumerators into `SpanExtensions.Enumerators`
- declared every `GetEnumerator` method in a ref struct as `readonly`
- renamed the source ReadOnlySpan<T> in 10 out of 12 custom Enumerators from *span* to *source*
- renamed the source ReadOnlySpan<T> in 10 out of 12 custom Enumerators from _span_ to _source_

## [1.1.0] - 2023-11-4

### Added
### Added

- Compatibility with **.Net 6**
- Compatibility with **.Net 5**
Expand All @@ -149,7 +172,7 @@ and this project adheres not (yet) to [Semantic Versioning](https://semver.org/s
- Missing documentation comments
- Changelog

### Fixed
### Fixed

- Grammatical issues in some documentation comments
- Broken link to the repository on nuget ([#3](https://github.com/draconware-dev/SpanExtensions.Net/pull/3))
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2024 draconware-dev
Copyright (c) 2025 draconware-dev

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
8 changes: 4 additions & 4 deletions SpanExtensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Debug|Any CPU.Build.0 = Release|Any CPU
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75DE5AFD-663E-415D-9B95-6BC513BD4A07}.Release|Any CPU.Build.0 = Release|Any CPU
{B48A0293-A7FF-4E39-8F8D-57B6F824D70F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B48A0293-A7FF-4E39-8F8D-57B6F824D70F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B48A0293-A7FF-4E39-8F8D-57B6F824D70F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B48A0293-A7FF-4E39-8F8D-57B6F824D70F}.Release|Any CPU.Build.0 = Release|Any CPU
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Debug|Any CPU.Build.0 = Release|Any CPU
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE74F420-1038-4E51-AC31-00DA964CC4F5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
Expand Down
8 changes: 2 additions & 6 deletions src/Enumerators/System/SpanSplitEnumerator.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System;
using System.Buffers;
using System.Diagnostics;
using System.Runtime.CompilerServices;

#if !NET9_0_OR_GREATER

Expand Down Expand Up @@ -62,7 +60,7 @@ internal SpanSplitEnumerator(ReadOnlySpan<T> source, SearchValues<T> searchValue
Delimiter = default!;
SearchValues = searchValues;
DelimiterSpan = default;
mode = SpanSplitEnumeratorMode.Delimiter;
mode = SpanSplitEnumeratorMode.SearchValues;
currentStartIndex = 0;
currentEndIndex = 0;
nextStartIndex = 0;
Expand Down Expand Up @@ -118,19 +116,17 @@ public bool MoveNext()
}

currentStartIndex = nextStartIndex;

if(index < 0)
{
currentEndIndex = Span.Length;
nextStartIndex = Span.Length;

mode = (SpanSplitEnumeratorMode)(-1);
return true;
}

currentEndIndex = currentStartIndex + index;
nextStartIndex = currentEndIndex + length;

return true;
}
}
Expand Down
Loading