< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Dispatcher.QueryBuffer<T>
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/QueryUtil.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 86
Coverable lines: 86
Total lines: 596
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 52
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
.ctor(...)0%220%
Add(...)0%440%
Add(...)0%440%
Clear()100%110%
CopyFrom(...)0%880%
CopyTo(...)100%110%
Grow(...)0%220%
IndexOf(...)0%660%
IndexOf(...)0%660%
IsValidIndex(...)0%220%
Reserve(...)0%220%
ReserveAt(...)0%880%
Remove(...)0%220%
RemoveAt(...)0%220%
Sort(...)100%110%
TrimToCount()0%440%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/QueryUtil.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using CoreWCF.Runtime;
 7
 8namespace CoreWCF.Dispatcher
 9{
 10    //
 11    // Generic struct representing ranges within buffers
 12    //
 13    internal struct QueryRange
 14    {
 15        private int _end;       // INCLUSIVE - the end of the range
 16        private int _start;     // INCLUSIVE - the start of the range
 17        internal QueryRange(int start, int end)
 18        {
 19            _start = start;
 20            _end = end;
 21        }
 22
 23        internal int Count
 24        {
 25            get
 26            {
 27                return _end - _start + 1;
 28            }
 29        }
 30        internal bool IsInRange(int point)
 31        {
 32            return (_start <= point && point <= _end);
 33        }
 34        internal void Shift(int offset)
 35        {
 36            _start += offset;
 37            _end += offset;
 38        }
 39    }
 40
 41    /// <summary>
 42    /// Our own buffer management
 43    /// There are a few reasons why we don't reuse something in System.Collections.Generic
 44    ///  1. We want Clear() to NOT reallocate the internal array. We want it to simply set the Count = 0
 45    ///     This allows us to reuse buffers with impunity.
 46    ///  2. We want to be able to replace the internal buffer in a collection with a different one. Again,
 47    ///     this is to help with pooling
 48    ///  3. We want to be able to control how fast buffers grow.
 49    ///  4. Does absolutely no bounds or null checking. As fast as we can make it. All checking should be done
 50    ///  by whoever wraps this. Checking is unnecessary for many internal uses where we need optimal perf.
 51    ///  5. Does more precise trimming
 52    ///  6. AND this is a struct
 53    ///
 54    /// </summary>
 55    internal struct QueryBuffer<T>
 56    {
 57        internal T[] buffer;    // buffer of T. Frequently larger than count
 58        internal int count;     // Actual # of items
 059        internal static T[] EmptyBuffer = Array.Empty<T>();
 60
 61        /// <summary>
 62        /// Construct a new buffer
 63        /// </summary>
 64        /// <param name="capacity"></param>
 65        internal QueryBuffer(int capacity)
 66        {
 067            if (0 == capacity)
 68            {
 069                buffer = EmptyBuffer;
 70            }
 71            else
 72            {
 073                buffer = new T[capacity];
 74            }
 075            count = 0;
 076        }
 77        /// <summary>
 78        /// # of items
 79        /// </summary>
 80        internal int Count
 81        {
 82            get
 83            {
 084                return count;
 85            }
 86        }
 87
 88
 89        internal T this[int index]
 90        {
 91            get
 92            {
 093                return buffer[index];
 94            }
 95            set
 96            {
 097                buffer[index] = value;
 098            }
 99        }
 100
 101
 102        /// <summary>
 103        /// Add an element to the buffer
 104        /// </summary>
 105        internal void Add(T t)
 106        {
 0107            if (count == buffer.Length)
 108            {
 0109                Array.Resize<T>(ref buffer, count > 0 ? count * 2 : 16);
 110            }
 0111            buffer[count++] = t;
 0112        }
 113
 114
 115        /// <summary>
 116        /// Add all the elements in the given buffer to this one
 117        /// We can do this very efficiently using an Array Copy
 118        /// </summary>
 119        internal void Add(ref QueryBuffer<T> addBuffer)
 120        {
 0121            if (1 == addBuffer.count)
 122            {
 0123                Add(addBuffer.buffer[0]);
 0124                return;
 125            }
 126
 0127            int newCount = count + addBuffer.count;
 0128            if (newCount >= buffer.Length)
 129            {
 0130                Grow(newCount);
 131            }
 132            // Copy all the new elements in
 0133            Array.Copy(addBuffer.buffer, 0, buffer, count, addBuffer.count);
 0134            count = newCount;
 0135        }
 136
 137
 138        /// <summary>
 139        /// Set the count to zero but do NOT get rid of the actual buffer
 140        /// </summary>
 141        internal void Clear()
 142        {
 0143            count = 0;
 0144        }
 145
 146
 147        internal void CopyFrom(ref QueryBuffer<T> addBuffer)
 148        {
 0149            int addCount = addBuffer.count;
 150            switch (addCount)
 151            {
 152                default:
 0153                    if (addCount > buffer.Length)
 154                    {
 0155                        buffer = new T[addCount];
 156                    }
 157                    // Copy all the new elements in
 0158                    Array.Copy(addBuffer.buffer, 0, buffer, 0, addCount);
 0159                    count = addCount;
 0160                    break;
 161
 162                case 0:
 0163                    count = 0;
 0164                    break;
 165
 166                case 1:
 0167                    if (buffer.Length == 0)
 168                    {
 0169                        buffer = new T[1];
 170                    }
 0171                    buffer[0] = addBuffer.buffer[0];
 0172                    count = 1;
 173                    break;
 174            }
 0175        }
 176
 177        internal void CopyTo(T[] dest)
 178        {
 0179            Array.Copy(buffer, dest, count);
 0180        }
 181
 182        private void Grow(int capacity)
 183        {
 0184            int newCapacity = buffer.Length * 2;
 0185            Array.Resize<T>(ref buffer, capacity > newCapacity ? capacity : newCapacity);
 0186        }
 187
 188        internal int IndexOf(T t)
 189        {
 0190            for (int i = 0; i < count; ++i)
 191            {
 0192                if (t.Equals(buffer[i]))
 193                {
 0194                    return i;
 195                }
 196            }
 0197            return -1;
 198        }
 199
 200        internal int IndexOf(T t, int startAt)
 201        {
 0202            for (int i = startAt; i < count; ++i)
 203            {
 0204                if (t.Equals(buffer[i]))
 205                {
 0206                    return i;
 207                }
 208            }
 0209            return -1;
 210        }
 211        internal bool IsValidIndex(int index)
 212        {
 0213            return (index >= 0 && index < count);
 214        }
 215
 216        /// <summary>
 217        /// Reserve enough space for count elements
 218        /// </summary>
 219        internal void Reserve(int reserveCount)
 220        {
 0221            int newCount = count + reserveCount;
 0222            if (newCount >= buffer.Length)
 223            {
 0224                Grow(newCount);
 225            }
 0226            count = newCount;
 0227        }
 228
 229        internal void ReserveAt(int index, int reserveCount)
 230        {
 0231            if (index == count)
 232            {
 0233                Reserve(reserveCount);
 0234                return;
 235            }
 236
 237            int newCount;
 0238            if (index > count)
 239            {
 240                // We want to reserve starting at a location past what is current committed.
 241                // No shifting needed
 0242                newCount = index + reserveCount + 1;
 0243                if (newCount >= buffer.Length)
 244                {
 0245                    Grow(newCount);
 246                }
 247            }
 248            else
 249            {
 250                // reserving space within an already allocated portion of the buffer
 251                // we'll ensure that the buffer can fit 'newCount' items, then shift by reserveCount starting at index
 0252                newCount = count + reserveCount;
 0253                if (newCount >= buffer.Length)
 254                {
 0255                    Grow(newCount);
 256                }
 257                // Move to make room
 0258                Array.Copy(buffer, index, buffer, index + reserveCount, count - index);
 259            }
 0260            count = newCount;
 0261        }
 262
 263        internal void Remove(T t)
 264        {
 0265            int index = IndexOf(t);
 0266            if (index >= 0)
 267            {
 0268                RemoveAt(index);
 269            }
 0270        }
 271
 272        internal void RemoveAt(int index)
 273        {
 0274            if (index < count - 1)
 275            {
 0276                Array.Copy(buffer, index + 1, buffer, index, count - index - 1);
 277            }
 0278            count--;
 0279        }
 280
 281        internal void Sort(IComparer<T> comparer)
 282        {
 0283            Array.Sort<T>(buffer, 0, count, comparer);
 0284        }
 285
 286        /// <summary>
 287        /// Reduce the buffer capacity so that its size is exactly == to the element count
 288        /// </summary>
 289        internal void TrimToCount()
 290        {
 0291            if (count < buffer.Length)
 292            {
 0293                if (0 == count)
 294                {
 0295                    buffer = EmptyBuffer;
 296                }
 297                else
 298                {
 0299                    T[] newBuffer = new T[count];
 0300                    Array.Copy(buffer, newBuffer, count);
 301                }
 302            }
 0303        }
 304    }
 305
 306    internal struct SortedBuffer<T, C>
 307            where C : IComparer<T>
 308    {
 309        private T[] _buffer;
 310        private static DefaultComparer s_comparer;
 311
 312        internal SortedBuffer(C comparerInstance)
 313        {
 314            Count = 0;
 315            _buffer = null;
 316
 317            if (s_comparer == null)
 318            {
 319                s_comparer = new DefaultComparer(comparerInstance);
 320            }
 321            else
 322            {
 323                Fx.Assert(ReferenceEquals(DefaultComparer.Comparer, comparerInstance), "The SortedBuffer type has alread
 324            }
 325        }
 326
 327        internal T this[int index]
 328        {
 329            get
 330            {
 331                return GetAt(index);
 332            }
 333        }
 334
 335        internal int Capacity
 336        {
 337            set
 338            {
 339                if (_buffer != null)
 340                {
 341                    if (value != _buffer.Length)
 342                    {
 343                        Fx.Assert(value >= Count, "New capacity must be >= size");
 344                        if (value > 0)
 345                        {
 346                            Array.Resize(ref _buffer, value);
 347                        }
 348                        else
 349                        {
 350                            _buffer = null;
 351                        }
 352                    }
 353                }
 354                else
 355                {
 356                    _buffer = new T[value];
 357                }
 358            }
 359        }
 360
 361        internal int Count { get; private set; }
 362
 363        internal int Add(T item)
 364        {
 365            int i = Search(item);
 366
 367            if (i < 0)
 368            {
 369                i = ~i;
 370                InsertAt(i, item);
 371            }
 372
 373            return i;
 374        }
 375
 376        internal void Clear()
 377        {
 378            Count = 0;
 379        }
 380        internal void Exchange(T old, T replace)
 381        {
 382            if (s_comparer.Compare(old, replace) == 0)
 383            {
 384                int i = IndexOf(old);
 385                if (i >= 0)
 386                {
 387                    _buffer[i] = replace;
 388                }
 389                else
 390                {
 391                    Insert(replace);
 392                }
 393            }
 394            else
 395            {
 396                // PERF, astern, can this be made more efficient?  Does it need to be?
 397                Remove(old);
 398                Insert(replace);
 399            }
 400        }
 401
 402        internal T GetAt(int index)
 403        {
 404            Fx.Assert(index < Count, "Index is greater than size");
 405            return _buffer[index];
 406        }
 407
 408        internal int IndexOf(T item)
 409        {
 410            return Search(item);
 411        }
 412
 413        internal int IndexOfKey<K>(K key, IItemComparer<K, T> itemComp)
 414        {
 415            return Search(key, itemComp);
 416        }
 417
 418        internal int Insert(T item)
 419        {
 420            int i = Search(item);
 421
 422            if (i >= 0)
 423            {
 424                throw DiagnosticUtility.ExceptionUtility.ThrowHelperCritical(new ArgumentException(SR.QueryItemAlreadyEx
 425            }
 426
 427            // If an item is not found, Search returns the bitwise negation of
 428            // the index an item should inserted at;
 429            InsertAt(~i, item);
 430            return ~i;
 431        }
 432
 433        private void InsertAt(int index, T item)
 434        {
 435            Fx.Assert(index >= 0 && index <= Count, "");
 436
 437            if (_buffer == null)
 438            {
 439                _buffer = new T[1];
 440            }
 441            else if (_buffer.Length == Count)
 442            {
 443                // PERF, astern, how should we choose a new size?
 444                T[] tmp = new T[Count + 1];
 445
 446                if (index == 0)
 447                {
 448                    Array.Copy(_buffer, 0, tmp, 1, Count);
 449                }
 450                else if (index == Count)
 451                {
 452                    Array.Copy(_buffer, 0, tmp, 0, Count);
 453                }
 454                else
 455                {
 456                    Array.Copy(_buffer, 0, tmp, 0, index);
 457                    Array.Copy(_buffer, index, tmp, index + 1, Count - index);
 458                }
 459
 460                _buffer = tmp;
 461            }
 462            else
 463            {
 464                Array.Copy(_buffer, index, _buffer, index + 1, Count - index);
 465            }
 466
 467            _buffer[index] = item;
 468            ++Count;
 469        }
 470
 471        internal bool Remove(T item)
 472        {
 473            int i = IndexOf(item);
 474
 475            if (i >= 0)
 476            {
 477                RemoveAt(i);
 478                return true;
 479            }
 480
 481            return false;
 482        }
 483
 484        internal void RemoveAt(int index)
 485        {
 486            Fx.Assert(index >= 0 && index < Count, "");
 487
 488            if (index < Count - 1)
 489            {
 490                Array.Copy(_buffer, index + 1, _buffer, index, Count - index - 1);
 491            }
 492
 493            _buffer[--Count] = default;
 494        }
 495
 496        private int Search(T item)
 497        {
 498            if (Count == 0)
 499            {
 500                return ~0;
 501            }
 502
 503            return Search(item, s_comparer);
 504        }
 505
 506        private int Search<K>(K key, IItemComparer<K, T> comparer)
 507        {
 508            if (Count <= 8)
 509            {
 510                return LinearSearch<K>(key, comparer, 0, Count);
 511            }
 512            else
 513            {
 514                return BinarySearch(key, comparer);
 515            }
 516        }
 517
 518        private int BinarySearch<K>(K key, IItemComparer<K, T> comparer)
 519        {
 520            // [low, high)
 521            int low = 0;
 522            int high = Count;
 523            int mid, result;
 524
 525            // Binary search is implemented here so we could look for a type that is different from the
 526            // buffer type.  Also, the search switches to linear for 8 or fewer elements.
 527            while (high - low > 8)
 528            {
 529                mid = (high + low) / 2;
 530                result = comparer.Compare(key, _buffer[mid]);
 531                if (result < 0)
 532                {
 533                    high = mid;
 534                }
 535                else if (result > 0)
 536                {
 537                    low = mid + 1;
 538                }
 539                else
 540                {
 541                    return mid;
 542                }
 543            }
 544
 545            return LinearSearch<K>(key, comparer, low, high);
 546        }
 547
 548        // [start, bound)
 549        private int LinearSearch<K>(K key, IItemComparer<K, T> comparer, int start, int bound)
 550        {
 551            int result;
 552
 553            for (int i = start; i < bound; ++i)
 554            {
 555                result = comparer.Compare(key, _buffer[i]);
 556                if (result == 0)
 557                {
 558                    return i;
 559                }
 560
 561                if (result < 0)
 562                {
 563                    // Return the bitwise negation of the insertion index
 564                    return ~i;
 565                }
 566            }
 567
 568            // Return the bitwise negation of the insertion index
 569            return ~bound;
 570        }
 571        internal void Trim()
 572        {
 573            Capacity = Count;
 574        }
 575
 576        internal class DefaultComparer : IItemComparer<T, T>
 577        {
 578            public static IComparer<T> Comparer;
 579
 580            public DefaultComparer(C comparer)
 581            {
 582                Comparer = comparer;
 583            }
 584
 585            public int Compare(T item1, T item2)
 586            {
 587                return Comparer.Compare(item1, item2);
 588            }
 589        }
 590    }
 591
 592    internal interface IItemComparer<K, V>
 593    {
 594        int Compare(K key, V value);
 595    }
 596}