Repository files navigation

SpanString

SpanString is an optimized string data structure built from Memory<char> and Span<char> added in .NET Standard 2.1+ and .NET Core 3.0+. It allows you to gather string segments from the memory of other strings to act as a single string. This can be useful for applications where millions of strings are parsed and used as keys for dictionaries or other data structures, and memory pressure and GC overhead are important concerns.

SpanString always uses ordinal string comparisons, and currently only handles ANSI for OrdinalIgnoreCase comparisons.

The release output of this repo generates the SpanString package on Nuget.org.

Usage

SpanStrings are exposed in the OptimizedStrings namespace.

SpanString

The SpanString class acts as a factory for various construction patterns, returning ISpanString instances. These instances are boxed versions of the SpanString1, 2, ... classes noted below.

SpanStringComparer

Provides various static helpers like Ordinal and OrdinalIgnoreCase for use as the comparers for SpanStrings used in hashmap-type collections.

SpanString1 struct

A SpanString1 wraps all or part of an underlying string object with a ReadOnlyMemory<char> to allow slicing out a subset of a string. The SpanString1 keeps a ref to the underlying string while letting you use it for a subset of string operations. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: One typical case for this is when parsing paths and you want to use one long path as the basis for multiple subpaths, all kept as references to parts of the long path string. SpanString1 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, ConcurrentDictionary, HashSet, or other hashmap-like collection, or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
var windowsRelativePaths = new Dictionary<SpanString1, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
string aPath = @"c:\windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.Services.dll";
// No need to do aPath.Substring(11) to create a
// new string after 'c:\windows\' - just slice it!
var ss = new SpanString1(aPath, 11);
windowsRelativePaths[ss] = new DirectoryInfo(aPath);

SpanString2 struct

A SpanString2 wraps two underlying strings and treats them as one for comparison, equality, hash code, and other calculations. It keeps two refs to the underlying strings' memory. The two strings can actually be from the same string. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: Creating a multi-part string key from two individual parts becomes more efficient when you don't need to allocate a third string that concatenates the two parts together. Instead use a SpanString2 to wrap both parts and use as a key in a Dictionary, ConcurrentDictionary, HashSet, and so on. SpanString2 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, HashSet, or other hashmap-like collection. Or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
class MyDatabaseRecord
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public SpanString2 ToKey()
{
return new SpanString2(FirstName, LastName);
}
}
var table = new Dictionary<SpanString2, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
foreach (MyDatabaseRecord record in database.GetRecords())
{
table[record.ToKey()] = record;
}

Release Notes

  • 0.2.1 Mar 2023: Add nullable annotations.
  • 0.2.0 Mar 2023: Retarget to .NET 6 only.
  • 0.1.0 Apr 2019: Initial release for testing performance and memory use versus strings in cases of reading and parsing millions of strings and creating substrings. Only contains SpanString1,2 allowing up to only 2 string segments to compose a SpanString.

About

String types that use snippets of memory from other strings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

SpanString

SpanString is an optimized string data structure built from Memory<char> and Span<char> added in .NET Standard 2.1+ and .NET Core 3.0+. It allows you to gather string segments from the memory of other strings to act as a single string. This can be useful for applications where millions of strings are parsed and used as keys for dictionaries or other data structures, and memory pressure and GC overhead are important concerns.

SpanString always uses ordinal string comparisons, and currently only handles ANSI for OrdinalIgnoreCase comparisons.

The release output of this repo generates the SpanString package on Nuget.org.

Usage

SpanStrings are exposed in the OptimizedStrings namespace.

SpanString

The SpanString class acts as a factory for various construction patterns, returning ISpanString instances. These instances are boxed versions of the SpanString1, 2, ... classes noted below.

SpanStringComparer

Provides various static helpers like Ordinal and OrdinalIgnoreCase for use as the comparers for SpanStrings used in hashmap-type collections.

SpanString1 struct

A SpanString1 wraps all or part of an underlying string object with a ReadOnlyMemory<char> to allow slicing out a subset of a string. The SpanString1 keeps a ref to the underlying string while letting you use it for a subset of string operations. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: One typical case for this is when parsing paths and you want to use one long path as the basis for multiple subpaths, all kept as references to parts of the long path string. SpanString1 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, ConcurrentDictionary, HashSet, or other hashmap-like collection, or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
var windowsRelativePaths = new Dictionary<SpanString1, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
string aPath = @"c:\windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.Services.dll";
// No need to do aPath.Substring(11) to create a
// new string after 'c:\windows\' - just slice it!
var ss = new SpanString1(aPath, 11);
windowsRelativePaths[ss] = new DirectoryInfo(aPath);

SpanString2 struct

A SpanString2 wraps two underlying strings and treats them as one for comparison, equality, hash code, and other calculations. It keeps two refs to the underlying strings' memory. The two strings can actually be from the same string. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: Creating a multi-part string key from two individual parts becomes more efficient when you don't need to allocate a third string that concatenates the two parts together. Instead use a SpanString2 to wrap both parts and use as a key in a Dictionary, ConcurrentDictionary, HashSet, and so on. SpanString2 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, HashSet, or other hashmap-like collection. Or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
class MyDatabaseRecord
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public SpanString2 ToKey()
{
return new SpanString2(FirstName, LastName);
}
}
var table = new Dictionary<SpanString2, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
foreach (MyDatabaseRecord record in database.GetRecords())
{
table[record.ToKey()] = record;
}

Release Notes

  • 0.2.1 Mar 2023: Add nullable annotations.
  • 0.2.0 Mar 2023: Retarget to .NET 6 only.
  • 0.1.0 Apr 2019: Initial release for testing performance and memory use versus strings in cases of reading and parsing millions of strings and creating substrings. Only contains SpanString1,2 allowing up to only 2 string segments to compose a SpanString.

About

String types that use snippets of memory from other strings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SpanString

SpanString is an optimized string data structure built from Memory<char> and Span<char> added in .NET Standard 2.1+ and .NET Core 3.0+. It allows you to gather string segments from the memory of other strings to act as a single string. This can be useful for applications where millions of strings are parsed and used as keys for dictionaries or other data structures, and memory pressure and GC overhead are important concerns.

SpanString always uses ordinal string comparisons, and currently only handles ANSI for OrdinalIgnoreCase comparisons.

The release output of this repo generates the SpanString package on Nuget.org.

Usage

SpanStrings are exposed in the OptimizedStrings namespace.

SpanString

The SpanString class acts as a factory for various construction patterns, returning ISpanString instances. These instances are boxed versions of the SpanString1, 2, ... classes noted below.

SpanStringComparer

Provides various static helpers like Ordinal and OrdinalIgnoreCase for use as the comparers for SpanStrings used in hashmap-type collections.

SpanString1 struct

A SpanString1 wraps all or part of an underlying string object with a ReadOnlyMemory<char> to allow slicing out a subset of a string. The SpanString1 keeps a ref to the underlying string while letting you use it for a subset of string operations. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: One typical case for this is when parsing paths and you want to use one long path as the basis for multiple subpaths, all kept as references to parts of the long path string. SpanString1 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, ConcurrentDictionary, HashSet, or other hashmap-like collection, or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
var windowsRelativePaths = new Dictionary<SpanString1, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
string aPath = @"c:\windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.Services.dll";
// No need to do aPath.Substring(11) to create a
// new string after 'c:\windows\' - just slice it!
var ss = new SpanString1(aPath, 11);
windowsRelativePaths[ss] = new DirectoryInfo(aPath);

SpanString2 struct

A SpanString2 wraps two underlying strings and treats them as one for comparison, equality, hash code, and other calculations. It keeps two refs to the underlying strings' memory. The two strings can actually be from the same string. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: Creating a multi-part string key from two individual parts becomes more efficient when you don't need to allocate a third string that concatenates the two parts together. Instead use a SpanString2 to wrap both parts and use as a key in a Dictionary, ConcurrentDictionary, HashSet, and so on. SpanString2 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, HashSet, or other hashmap-like collection. Or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
class MyDatabaseRecord
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public SpanString2 ToKey()
{
return new SpanString2(FirstName, LastName);
}
}
var table = new Dictionary<SpanString2, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
foreach (MyDatabaseRecord record in database.GetRecords())
{
table[record.ToKey()] = record;
}

Release Notes

  • 0.2.1 Mar 2023: Add nullable annotations.
  • 0.2.0 Mar 2023: Retarget to .NET 6 only.
  • 0.1.0 Apr 2019: Initial release for testing performance and memory use versus strings in cases of reading and parsing millions of strings and creating substrings. Only contains SpanString1,2 allowing up to only 2 string segments to compose a SpanString.

About

String types that use snippets of memory from other strings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SpanString

SpanString is an optimized string data structure built from Memory<char> and Span<char> added in .NET Standard 2.1+ and .NET Core 3.0+. It allows you to gather string segments from the memory of other strings to act as a single string. This can be useful for applications where millions of strings are parsed and used as keys for dictionaries or other data structures, and memory pressure and GC overhead are important concerns.

SpanString always uses ordinal string comparisons, and currently only handles ANSI for OrdinalIgnoreCase comparisons.

The release output of this repo generates the SpanString package on Nuget.org.

Usage

SpanStrings are exposed in the OptimizedStrings namespace.

SpanString

The SpanString class acts as a factory for various construction patterns, returning ISpanString instances. These instances are boxed versions of the SpanString1, 2, ... classes noted below.

SpanStringComparer

Provides various static helpers like Ordinal and OrdinalIgnoreCase for use as the comparers for SpanStrings used in hashmap-type collections.

SpanString1 struct

A SpanString1 wraps all or part of an underlying string object with a ReadOnlyMemory<char> to allow slicing out a subset of a string. The SpanString1 keeps a ref to the underlying string while letting you use it for a subset of string operations. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: One typical case for this is when parsing paths and you want to use one long path as the basis for multiple subpaths, all kept as references to parts of the long path string. SpanString1 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, ConcurrentDictionary, HashSet, or other hashmap-like collection, or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
var windowsRelativePaths = new Dictionary<SpanString1, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
string aPath = @"c:\windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.Services.dll";
// No need to do aPath.Substring(11) to create a
// new string after 'c:\windows\' - just slice it!
var ss = new SpanString1(aPath, 11);
windowsRelativePaths[ss] = new DirectoryInfo(aPath);

SpanString2 struct

A SpanString2 wraps two underlying strings and treats them as one for comparison, equality, hash code, and other calculations. It keeps two refs to the underlying strings' memory. The two strings can actually be from the same string. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: Creating a multi-part string key from two individual parts becomes more efficient when you don't need to allocate a third string that concatenates the two parts together. Instead use a SpanString2 to wrap both parts and use as a key in a Dictionary, ConcurrentDictionary, HashSet, and so on. SpanString2 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, HashSet, or other hashmap-like collection. Or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
class MyDatabaseRecord
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public SpanString2 ToKey()
{
return new SpanString2(FirstName, LastName);
}
}
var table = new Dictionary<SpanString2, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
foreach (MyDatabaseRecord record in database.GetRecords())
{
table[record.ToKey()] = record;
}

Release Notes

  • 0.2.1 Mar 2023: Add nullable annotations.
  • 0.2.0 Mar 2023: Retarget to .NET 6 only.
  • 0.1.0 Apr 2019: Initial release for testing performance and memory use versus strings in cases of reading and parsing millions of strings and creating substrings. Only contains SpanString1,2 allowing up to only 2 string segments to compose a SpanString.

About

String types that use snippets of memory from other strings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

SpanString

SpanString is an optimized string data structure built from Memory<char> and Span<char> added in .NET Standard 2.1+ and .NET Core 3.0+. It allows you to gather string segments from the memory of other strings to act as a single string. This can be useful for applications where millions of strings are parsed and used as keys for dictionaries or other data structures, and memory pressure and GC overhead are important concerns.

SpanString always uses ordinal string comparisons, and currently only handles ANSI for OrdinalIgnoreCase comparisons.

The release output of this repo generates the SpanString package on Nuget.org.

Usage

SpanStrings are exposed in the OptimizedStrings namespace.

SpanString

The SpanString class acts as a factory for various construction patterns, returning ISpanString instances. These instances are boxed versions of the SpanString1, 2, ... classes noted below.

SpanStringComparer

Provides various static helpers like Ordinal and OrdinalIgnoreCase for use as the comparers for SpanStrings used in hashmap-type collections.

SpanString1 struct

A SpanString1 wraps all or part of an underlying string object with a ReadOnlyMemory<char> to allow slicing out a subset of a string. The SpanString1 keeps a ref to the underlying string while letting you use it for a subset of string operations. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: One typical case for this is when parsing paths and you want to use one long path as the basis for multiple subpaths, all kept as references to parts of the long path string. SpanString1 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, ConcurrentDictionary, HashSet, or other hashmap-like collection, or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
var windowsRelativePaths = new Dictionary<SpanString1, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
string aPath = @"c:\windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.Services.dll";
// No need to do aPath.Substring(11) to create a
// new string after 'c:\windows\' - just slice it!
var ss = new SpanString1(aPath, 11);
windowsRelativePaths[ss] = new DirectoryInfo(aPath);

SpanString2 struct

A SpanString2 wraps two underlying strings and treats them as one for comparison, equality, hash code, and other calculations. It keeps two refs to the underlying strings' memory. The two strings can actually be from the same string. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: Creating a multi-part string key from two individual parts becomes more efficient when you don't need to allocate a third string that concatenates the two parts together. Instead use a SpanString2 to wrap both parts and use as a key in a Dictionary, ConcurrentDictionary, HashSet, and so on. SpanString2 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, HashSet, or other hashmap-like collection. Or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
class MyDatabaseRecord
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public SpanString2 ToKey()
{
return new SpanString2(FirstName, LastName);
}
}
var table = new Dictionary<SpanString2, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
foreach (MyDatabaseRecord record in database.GetRecords())
{
table[record.ToKey()] = record;
}

Release Notes

  • 0.2.1 Mar 2023: Add nullable annotations.
  • 0.2.0 Mar 2023: Retarget to .NET 6 only.
  • 0.1.0 Apr 2019: Initial release for testing performance and memory use versus strings in cases of reading and parsing millions of strings and creating substrings. Only contains SpanString1,2 allowing up to only 2 string segments to compose a SpanString.

About

String types that use snippets of memory from other strings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SpanString

SpanString is an optimized string data structure built from Memory<char> and Span<char> added in .NET Standard 2.1+ and .NET Core 3.0+. It allows you to gather string segments from the memory of other strings to act as a single string. This can be useful for applications where millions of strings are parsed and used as keys for dictionaries or other data structures, and memory pressure and GC overhead are important concerns.

SpanString always uses ordinal string comparisons, and currently only handles ANSI for OrdinalIgnoreCase comparisons.

The release output of this repo generates the SpanString package on Nuget.org.

Usage

SpanStrings are exposed in the OptimizedStrings namespace.

SpanString

The SpanString class acts as a factory for various construction patterns, returning ISpanString instances. These instances are boxed versions of the SpanString1, 2, ... classes noted below.

SpanStringComparer

Provides various static helpers like Ordinal and OrdinalIgnoreCase for use as the comparers for SpanStrings used in hashmap-type collections.

SpanString1 struct

A SpanString1 wraps all or part of an underlying string object with a ReadOnlyMemory<char> to allow slicing out a subset of a string. The SpanString1 keeps a ref to the underlying string while letting you use it for a subset of string operations. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: One typical case for this is when parsing paths and you want to use one long path as the basis for multiple subpaths, all kept as references to parts of the long path string. SpanString1 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, ConcurrentDictionary, HashSet, or other hashmap-like collection, or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
var windowsRelativePaths = new Dictionary<SpanString1, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
string aPath = @"c:\windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.Services.dll";
// No need to do aPath.Substring(11) to create a
// new string after 'c:\windows\' - just slice it!
var ss = new SpanString1(aPath, 11);
windowsRelativePaths[ss] = new DirectoryInfo(aPath);

SpanString2 struct

A SpanString2 wraps two underlying strings and treats them as one for comparison, equality, hash code, and other calculations. It keeps two refs to the underlying strings' memory. The two strings can actually be from the same string. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: Creating a multi-part string key from two individual parts becomes more efficient when you don't need to allocate a third string that concatenates the two parts together. Instead use a SpanString2 to wrap both parts and use as a key in a Dictionary, ConcurrentDictionary, HashSet, and so on. SpanString2 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, HashSet, or other hashmap-like collection. Or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
class MyDatabaseRecord
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public SpanString2 ToKey()
{
return new SpanString2(FirstName, LastName);
}
}
var table = new Dictionary<SpanString2, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
foreach (MyDatabaseRecord record in database.GetRecords())
{
table[record.ToKey()] = record;
}

Release Notes

  • 0.2.1 Mar 2023: Add nullable annotations.
  • 0.2.0 Mar 2023: Retarget to .NET 6 only.
  • 0.1.0 Apr 2019: Initial release for testing performance and memory use versus strings in cases of reading and parsing millions of strings and creating substrings. Only contains SpanString1,2 allowing up to only 2 string segments to compose a SpanString.

About

String types that use snippets of memory from other strings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

SpanString

SpanString is an optimized string data structure built from Memory<char> and Span<char> added in .NET Standard 2.1+ and .NET Core 3.0+. It allows you to gather string segments from the memory of other strings to act as a single string. This can be useful for applications where millions of strings are parsed and used as keys for dictionaries or other data structures, and memory pressure and GC overhead are important concerns.

SpanString always uses ordinal string comparisons, and currently only handles ANSI for OrdinalIgnoreCase comparisons.

The release output of this repo generates the SpanString package on Nuget.org.

Usage

SpanStrings are exposed in the OptimizedStrings namespace.

SpanString

The SpanString class acts as a factory for various construction patterns, returning ISpanString instances. These instances are boxed versions of the SpanString1, 2, ... classes noted below.

SpanStringComparer

Provides various static helpers like Ordinal and OrdinalIgnoreCase for use as the comparers for SpanStrings used in hashmap-type collections.

SpanString1 struct

A SpanString1 wraps all or part of an underlying string object with a ReadOnlyMemory<char> to allow slicing out a subset of a string. The SpanString1 keeps a ref to the underlying string while letting you use it for a subset of string operations. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: One typical case for this is when parsing paths and you want to use one long path as the basis for multiple subpaths, all kept as references to parts of the long path string. SpanString1 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, ConcurrentDictionary, HashSet, or other hashmap-like collection, or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
var windowsRelativePaths = new Dictionary<SpanString1, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
string aPath = @"c:\windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.Services.dll";
// No need to do aPath.Substring(11) to create a
// new string after 'c:\windows\' - just slice it!
var ss = new SpanString1(aPath, 11);
windowsRelativePaths[ss] = new DirectoryInfo(aPath);

SpanString2 struct

A SpanString2 wraps two underlying strings and treats them as one for comparison, equality, hash code, and other calculations. It keeps two refs to the underlying strings' memory. The two strings can actually be from the same string. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: Creating a multi-part string key from two individual parts becomes more efficient when you don't need to allocate a third string that concatenates the two parts together. Instead use a SpanString2 to wrap both parts and use as a key in a Dictionary, ConcurrentDictionary, HashSet, and so on. SpanString2 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, HashSet, or other hashmap-like collection. Or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
class MyDatabaseRecord
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public SpanString2 ToKey()
{
return new SpanString2(FirstName, LastName);
}
}
var table = new Dictionary<SpanString2, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
foreach (MyDatabaseRecord record in database.GetRecords())
{
table[record.ToKey()] = record;
}

Release Notes

  • 0.2.1 Mar 2023: Add nullable annotations.
  • 0.2.0 Mar 2023: Retarget to .NET 6 only.
  • 0.1.0 Apr 2019: Initial release for testing performance and memory use versus strings in cases of reading and parsing millions of strings and creating substrings. Only contains SpanString1,2 allowing up to only 2 string segments to compose a SpanString.

About

String types that use snippets of memory from other strings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

SpanString

SpanString is an optimized string data structure built from Memory<char> and Span<char> added in .NET Standard 2.1+ and .NET Core 3.0+. It allows you to gather string segments from the memory of other strings to act as a single string. This can be useful for applications where millions of strings are parsed and used as keys for dictionaries or other data structures, and memory pressure and GC overhead are important concerns.

SpanString always uses ordinal string comparisons, and currently only handles ANSI for OrdinalIgnoreCase comparisons.

The release output of this repo generates the SpanString package on Nuget.org.

Usage

SpanStrings are exposed in the OptimizedStrings namespace.

SpanString

The SpanString class acts as a factory for various construction patterns, returning ISpanString instances. These instances are boxed versions of the SpanString1, 2, ... classes noted below.

SpanStringComparer

Provides various static helpers like Ordinal and OrdinalIgnoreCase for use as the comparers for SpanStrings used in hashmap-type collections.

SpanString1 struct

A SpanString1 wraps all or part of an underlying string object with a ReadOnlyMemory<char> to allow slicing out a subset of a string. The SpanString1 keeps a ref to the underlying string while letting you use it for a subset of string operations. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: One typical case for this is when parsing paths and you want to use one long path as the basis for multiple subpaths, all kept as references to parts of the long path string. SpanString1 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, ConcurrentDictionary, HashSet, or other hashmap-like collection, or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
var windowsRelativePaths = new Dictionary<SpanString1, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
string aPath = @"c:\windows\Microsoft.NET\Framework64\v4.0.30319\System.Web.Services.dll";
// No need to do aPath.Substring(11) to create a
// new string after 'c:\windows\' - just slice it!
var ss = new SpanString1(aPath, 11);
windowsRelativePaths[ss] = new DirectoryInfo(aPath);

SpanString2 struct

A SpanString2 wraps two underlying strings and treats them as one for comparison, equality, hash code, and other calculations. It keeps two refs to the underlying strings' memory. The two strings can actually be from the same string. It is a struct to let you control memory placement and avoid heap allocation overhead; if you want a boxed version allocated on the heap, use SpanString.Create to get an ISpanString that boxes this struct.

Use cases: Creating a multi-part string key from two individual parts becomes more efficient when you don't need to allocate a third string that concatenates the two parts together. Instead use a SpanString2 to wrap both parts and use as a key in a Dictionary, ConcurrentDictionary, HashSet, and so on. SpanString2 implements IEquatable and can act as its own default ordinally-compared key in a Dictionary, HashSet, or other hashmap-like collection. Or use SpanStringComparer.OrdinalIgnoreCase as the comparer to get case-insensitive keys.

using OptimizedStrings;
class MyDatabaseRecord
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public SpanString2 ToKey()
{
return new SpanString2(FirstName, LastName);
}
}
var table = new Dictionary<SpanString2, DirectoryInfo>(SpanStringComparer.OrdinalIgnoreCase);
foreach (MyDatabaseRecord record in database.GetRecords())
{
table[record.ToKey()] = record;
}

Release Notes

  • 0.2.1 Mar 2023: Add nullable annotations.
  • 0.2.0 Mar 2023: Retarget to .NET 6 only.
  • 0.1.0 Apr 2019: Initial release for testing performance and memory use versus strings in cases of reading and parsing millions of strings and creating substrings. Only contains SpanString1,2 allowing up to only 2 string segments to compose a SpanString.

About

String types that use snippets of memory from other strings

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages