') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); Optimize the implementation of LINQ partitioning APIs · Issue #48631 · dotnet/runtime · GitHub
Skip to content

Optimize the implementation of LINQ partitioning APIs #48631

Description

@Dixin

My PR #48559 "Add LINQ APIs for Index and Range" was just merged, and this is a following up. @eiriktsarpalis@stephentoub

Background:

  • LINQ internally use IPartition<T> to optimize the implementation of partitioning operators, like Take, Skip, ElementAt
  • Later, more partitioning operators are added for LINQ, like TakeLast, SkipLast, Take(System.Range), ElementAt(System.Index). These new APIs are implemented by yield return.

Proposal

It is best to have an unified implementation of all the partitioning and element operators based on IPartition<T>.

Internal API changes

Current IPartition<T>:

interfaceIPartition<TSource>{TSource?TryGetElementAt(intindex,outboolfound);IPartition<TSource>Take(intcount);IPartition<TSource>Skip(intcount);// Other members ...}
  1. Update IPartition<T> to support indexes from start or end:
interfaceIPartition<TSource>{// New members.boolTryGetElementAt(intindex,boolisIndexFromEnd,[MaybeNullWhen(false)]outTSourceelement);IPartition<TSource>Take(intstartIndexInclusive,intendIndexExclusive,boolisStartIndexFromEnd,boolisEndIndexFromEnd);// Original members.TSource?TryGetElementAt(intindex,outboolfound){found=TryGetElementAt(index,false,outTSource?element);returnelement;}IPartition<TSource>Take(intcount)=>Take(0,count,false,false);;IPartition<TSource>Skip(intcount)=>Take(count,0,false,true);// Other members ...}
  1. Update all types that implement IPartition<T>. All optimization code should be in these types, not in the LINQ operators.
    • EmptyPartition<TElement>
    • ListPartition<TSource>
    • EnumerablePartition<TSource>
    • RangeIterator
    • RepeatIterator<TResult>
    • SelectArrayIterator<TSource, TResult>
    • SelectRangeIterator<TResult>
    • SelectListIterator<TSource, TResult>
    • SelectIListIterator<TSource, TResult>
    • SelectIPartitionIterator<TSource, TResult>
    • SelectListPartitionIterator<TSource, TResult>
    • OrderedPartition<TElement>
    • OrderedEnumerable<TElement, TKey>
  2. Implement Enumerable.TakeIterator based on IPartition<T>, then use Enumerable.TakeIterator to implement Take, Skip, TakeLast, SkipLast, Take(System.Range).
  3. Update ElementAt(System.Index) to utilize IPartition<T>TryGetElementAt

Then all partition and element APIs should be consolidated, optimized, consistent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions