2016-08-03 10:59:49 +00:00
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Runtime ;
#if NO
internal interface IQueryBufferPool
{
// Clear all pools
void Reset ( ) ;
// Trim pools
void Trim ( ) ;
}
#endif
//
// Generic struct representing ranges within buffers
//
internal struct QueryRange
{
internal int end ; // INCLUSIVE - the end of the range
internal int start ; // INCLUSIVE - the start of the range
#if NO
internal QueryRange ( int offset , QueryRange range )
{
this . start = range . start + offset ;
this . end = range . end + offset ;
}
#endif
internal QueryRange ( int start , int end )
{
this . start = start ;
this . end = end ;
}
internal int Count
{
get
{
return this . end - this . start + 1 ;
}
}
#if NO
internal int this [ int offset ]
{
get
{
return this . start + offset ;
}
}
internal bool IsNotEmpty
{
get
{
return ( this . end > = this . start ) ;
}
}
internal void Clear ( )
{
this . end = this . start - 1 ;
}
internal void Grow ( int offset )
{
this . end + = offset ;
}
#endif
internal bool IsInRange ( int point )
{
return ( this . start < = point & & point < = this . end ) ;
}
#if NO
internal void Set ( int start , int end )
{
this . start = start ;
this . end = end ;
}
#endif
internal void Shift ( int offset )
{
this . start + = offset ;
this . end + = offset ;
}
}
/// <summary>
/// Our own buffer management
/// There are a few reasons why we don't reuse something in System.Collections.Generic
/// 1. We want Clear() to NOT reallocate the internal array. We want it to simply set the Count = 0
/// This allows us to reuse buffers with impunity.
/// 2. We want to be able to replace the internal buffer in a collection with a different one. Again,
/// this is to help with pooling
/// 3. We want to be able to control how fast buffers grow.
/// 4. Does absolutely no bounds or null checking. As fast as we can make it. All checking should be done
/// by whoever wraps this. Checking is unnecessary for many internal uses where we need optimal perf.
/// 5. Does more precise trimming
/// 6. AND this is a struct
///
/// </summary>
internal struct QueryBuffer < T >
{
internal T [ ] buffer ; // buffer of T. Frequently larger than count
internal int count ; // Actual # of items
internal static T [ ] EmptyBuffer = new T [ 0 ] ;
/// <summary>
/// Construct a new buffer
/// </summary>
/// <param name="capacity"></param>
internal QueryBuffer ( int capacity )
{
if ( 0 = = capacity )
{
this . buffer = QueryBuffer < T > . EmptyBuffer ;
}
else
{
this . buffer = new T [ capacity ] ;
}
this . count = 0 ;
}
#if NO
internal QueryBuffer ( QueryBuffer < T > buffer )
{
this . buffer = ( T [ ] ) buffer . buffer . Clone ( ) ;
this . count = buffer . count ;
}
internal QueryBuffer ( T [ ] buffer )
{
Fx . Assert ( null ! = buffer , "" ) ;
this . buffer = buffer ;
this . count = 0 ;
}
/// <summary>
/// Get and set the internal buffer
/// If you set the buffer, the count will automatically be set to 0
/// </summary>
internal T [ ] Buffer
{
get
{
return this . buffer ;
}
set
{
Fx . Assert ( null ! = value , "" ) ;
this . buffer = value ;
this . count = 0 ;
}
}
#endif
/// <summary>
/// # of items
/// </summary>
internal int Count
{
get
{
return this . count ;
}
#if NO
set
{
Fx . Assert ( value > = 0 & & value < = this . buffer . Length , "" ) ;
this . count = value ;
}
#endif
}
#if NO
/// <summary>
/// How much can it hold
/// </summary>
internal int Capacity
{
get
{
return this . buffer . Length ;
}
set
{
Fx . Assert ( value > = this . count , "" ) ;
if ( value > this . buffer . Length )
{
Array . Resize < T > ( ref this . buffer , value ) ;
}
}
}
#endif
internal T this [ int index ]
{
get
{
return this . buffer [ index ] ;
}
set
{
this . buffer [ index ] = value ;
}
}
#if NO
internal void Add ( )
{
if ( this . count = = this . buffer . Length )
{
Array . Resize < T > ( ref this . buffer , this . count > 0 ? this . count * 2 : 16 ) ;
}
this . count + + ;
}
#endif
/// <summary>
/// Add an element to the buffer
/// </summary>
internal void Add ( T t )
{
if ( this . count = = this . buffer . Length )
{
Array . Resize < T > ( ref this . buffer , this . count > 0 ? this . count * 2 : 16 ) ;
}
this . buffer [ this . count + + ] = t ;
}
#if NO
/// <summary>
/// Useful when this is a buffer of structs
/// </summary>
internal void AddReference ( ref T t )
{
if ( this . count = = this . buffer . Length )
{
Array . Resize < T > ( ref this . buffer , this . count > 0 ? this . count * 2 : 16 ) ;
}
this . buffer [ this . count + + ] = t ;
}
#endif
/// <summary>
/// Add all the elements in the given buffer to this one
/// We can do this very efficiently using an Array Copy
/// </summary>
internal void Add ( ref QueryBuffer < T > addBuffer )
{
if ( 1 = = addBuffer . count )
{
this . Add ( addBuffer . buffer [ 0 ] ) ;
return ;
}
int newCount = this . count + addBuffer . count ;
if ( newCount > = this . buffer . Length )
{
this . Grow ( newCount ) ;
}
// Copy all the new elements in
Array . Copy ( addBuffer . buffer , 0 , this . buffer , this . count , addBuffer . count ) ;
this . count = newCount ;
}
#if NO
internal void Add ( T [ ] addBuffer , int startAt , int addCount )
{
int newCount = this . count + addCount ;
if ( newCount > = this . buffer . Length )
{
this . Grow ( newCount ) ;
}
// Copy all the new elements in
Array . Copy ( addBuffer , startAt , this . buffer , this . count , addCount ) ;
this . count = newCount ;
}
/// <summary>
/// Add without attempting to grow the buffer. Faster, but must be used with care.
/// Caller must ensure that the buffer is large enough.
/// </summary>
internal void AddOnly ( T t )
{
this . buffer [ this . count + + ] = t ;
}
#endif
/// <summary>
/// Set the count to zero but do NOT get rid of the actual buffer
/// </summary>
internal void Clear ( )
{
this . count = 0 ;
}
#if NO
//
// Copy from one location in the buffer to another
//
internal void Copy ( int from , int to )
{
this . buffer [ to ] = this . buffer [ from ] ;
}
internal void Copy ( int from , int to , int count )
{
Array . Copy ( this . buffer , from , this . buffer , to , count ) ;
}
#endif
internal void CopyFrom ( ref QueryBuffer < T > addBuffer )
{
int addCount = addBuffer . count ;
switch ( addCount )
{
default :
if ( addCount > this . buffer . Length )
{
this . buffer = new T [ addCount ] ;
}
// Copy all the new elements in
Array . Copy ( addBuffer . buffer , 0 , this . buffer , 0 , addCount ) ;
this . count = addCount ;
break ;
case 0 :
this . count = 0 ;
break ;
case 1 :
if ( this . buffer . Length = = 0 )
{
this . buffer = new T [ 1 ] ;
}
this . buffer [ 0 ] = addBuffer . buffer [ 0 ] ;
this . count = 1 ;
break ;
}
}
internal void CopyTo ( T [ ] dest )
{
Array . Copy ( this . buffer , dest , this . count ) ;
}
#if NO
/// <summary>
/// Ensure that the internal buffer has adequate capacity
/// </summary>
internal void EnsureCapacity ( int capacity )
{
if ( capacity > this . buffer . Length )
{
this . Grow ( capacity ) ;
}
}
internal void Erase ( )
{
Array . Clear ( this . buffer , 0 , this . count ) ;
this . count = 0 ;
}
#endif
void Grow ( int capacity )
{
int newCapacity = this . buffer . Length * 2 ;
Array . Resize < T > ( ref this . buffer , capacity > newCapacity ? capacity : newCapacity ) ;
}
internal int IndexOf ( T t )
{
for ( int i = 0 ; i < this . count ; + + i )
{
if ( t . Equals ( this . buffer [ i ] ) )
{
return i ;
}
}
return - 1 ;
}
internal int IndexOf ( T t , int startAt )
{
for ( int i = startAt ; i < this . count ; + + i )
{
if ( t . Equals ( this . buffer [ i ] ) )
{
return i ;
}
}
return - 1 ;
}
#if NO
internal void InsertAt ( T t , int at )
{
this . ReserveAt ( at , 1 ) ;
this . buffer [ at ] = t ;
}
#endif
internal bool IsValidIndex ( int index )
{
return ( index > = 0 & & index < this . count ) ;
}
#if NO
internal T Pop ( )
{
Fx . Assert ( this . count > 0 , "" ) ;
return this . buffer [ - - this . count ] ;
}
internal void Push ( T t )
{
this . Add ( t ) ;
}
#endif
/// <summary>
/// Reserve enough space for count elements
/// </summary>
internal void Reserve ( int reserveCount )
{
int newCount = this . count + reserveCount ;
if ( newCount > = this . buffer . Length )
{
this . Grow ( newCount ) ;
}
this . count = newCount ;
}
internal void ReserveAt ( int index , int reserveCount )
{
if ( index = = this . count )
{
this . Reserve ( reserveCount ) ;
return ;
}
int newCount ;
if ( index > this . count )
{
// We want to reserve starting at a location past what is current committed.
// No shifting needed
newCount = index + reserveCount + 1 ;
if ( newCount > = this . buffer . Length )
{
this . Grow ( newCount ) ;
}
}
else
{
// reserving space within an already allocated portion of the buffer
// we'll ensure that the buffer can fit 'newCount' items, then shift by reserveCount starting at index
newCount = this . count + reserveCount ;
if ( newCount > = this . buffer . Length )
{
this . Grow ( newCount ) ;
}
// Move to make room
Array . Copy ( this . buffer , index , this . buffer , index + reserveCount , this . count - index ) ;
}
this . count = newCount ;
}
internal void Remove ( T t )
{
int index = this . IndexOf ( t ) ;
if ( index > = 0 )
{
this . RemoveAt ( index ) ;
}
}
internal void RemoveAt ( int index )
{
if ( index < this . count - 1 )
{
Array . Copy ( this . buffer , index + 1 , this . buffer , index , this . count - index - 1 ) ;
}
this . count - - ;
}
internal void Sort ( IComparer < T > comparer )
{
Array . Sort < T > ( this . buffer , 0 , this . count , comparer ) ;
}
#if NO
/// <summary>
/// Reduce the buffer capacity so that it is no greater than twice the element count
/// </summary>
internal void Trim ( )
{
int maxSize = this . count * 2 ;
if ( maxSize < this . buffer . Length / 2 )
{
if ( 0 = = maxSize )
{
this . buffer = QueryBuffer < T > . EmptyBuffer ;
}
else
{
T [ ] newBuffer = new T [ maxSize ] ;
Array . Copy ( this . buffer , newBuffer , maxSize ) ;
}
}
}
#endif
/// <summary>
/// Reduce the buffer capacity so that its size is exactly == to the element count
/// </summary>
internal void TrimToCount ( )
{
if ( this . count < this . buffer . Length )
{
if ( 0 = = this . count )
{
this . buffer = QueryBuffer < T > . EmptyBuffer ;
}
else
{
T [ ] newBuffer = new T [ this . count ] ;
Array . Copy ( this . buffer , newBuffer , this . count ) ;
}
}
}
}
internal struct SortedBuffer < T , C >
where C : IComparer < T >
{
int size ;
T [ ] buffer ;
static DefaultComparer Comparer ;
internal SortedBuffer ( C comparerInstance )
{
this . size = 0 ;
this . buffer = null ;
if ( Comparer = = null )
{
Comparer = new DefaultComparer ( comparerInstance ) ;
}
else
{
Fx . Assert ( object . ReferenceEquals ( DefaultComparer . Comparer , comparerInstance ) , "The SortedBuffer type has already been initialized with a different comparer instance." ) ;
}
}
internal T this [ int index ]
{
get
{
return GetAt ( index ) ;
}
}
internal int Capacity
{
#if NO
get
{
return this . buffer = = null ? 0 : this . buffer . Length ;
}
#endif
set
{
if ( this . buffer ! = null )
{
if ( value ! = this . buffer . Length )
{
Fx . Assert ( value > = this . size , "New capacity must be >= size" ) ;
if ( value > 0 )
{
Array . Resize ( ref this . buffer , value ) ;
}
else
{
this . buffer = null ;
}
}
}
else
{
this . buffer = new T [ value ] ;
}
}
}
internal int Count
{
get
{
return this . size ;
}
}
internal int Add ( T item )
{
int i = Search ( item ) ;
if ( i < 0 )
{
i = ~ i ;
InsertAt ( i , item ) ;
}
return i ;
}
#if NO
internal void CopyTo ( T [ ] array )
{
CopyTo ( array , 0 , this . size ) ;
}
internal void CopyTo ( T [ ] array , int start , int length )
{
Fx . Assert ( array ! = null , "" ) ;
Fx . Assert ( start > = 0 , "" ) ;
Fx . Assert ( length > = 0 , "" ) ;
Fx . Assert ( start + length < this . size , "" ) ;
Array . Copy ( this . buffer , 0 , array , start , length ) ;
}
#endif
internal void Clear ( )
{
this . size = 0 ;
}
#if NO
internal bool Contains ( T item )
{
return IndexOf ( item ) > = 0 ;
}
#endif
internal void Exchange ( T old , T replace )
{
if ( Comparer . Compare ( old , replace ) = = 0 )
{
int i = IndexOf ( old ) ;
if ( i > = 0 )
{
this . buffer [ i ] = replace ;
}
else
{
Insert ( replace ) ;
}
}
else
{
2017-08-21 15:34:15 +00:00
// PERF, Microsoft, can this be made more efficient? Does it need to be?
2016-08-03 10:59:49 +00:00
Remove ( old ) ;
Insert ( replace ) ;
}
}
internal T GetAt ( int index )
{
Fx . Assert ( index < this . size , "Index is greater than size" ) ;
return this . buffer [ index ] ;
}
internal int IndexOf ( T item )
{
return Search ( item ) ;
}
internal int IndexOfKey < K > ( K key , IItemComparer < K , T > itemComp )
{
return Search ( key , itemComp ) ;
}
internal int Insert ( T item )
{
int i = Search ( item ) ;
if ( i > = 0 )
{
throw DiagnosticUtility . ExceptionUtility . ThrowHelperCritical ( new ArgumentException ( SR . GetString ( SR . QueryItemAlreadyExists ) ) ) ;
}
// If an item is not found, Search returns the bitwise negation of
// the index an item should inserted at;
InsertAt ( ~ i , item ) ;
return ~ i ;
}
void InsertAt ( int index , T item )
{
Fx . Assert ( index > = 0 & & index < = this . size , "" ) ;
if ( this . buffer = = null )
{
this . buffer = new T [ 1 ] ;
}
else if ( this . buffer . Length = = this . size )
{
2017-08-21 15:34:15 +00:00
// PERF, Microsoft, how should we choose a new size?
2016-08-03 10:59:49 +00:00
T [ ] tmp = new T [ this . size + 1 ] ;
if ( index = = 0 )
{
Array . Copy ( this . buffer , 0 , tmp , 1 , this . size ) ;
}
else if ( index = = this . size )
{
Array . Copy ( this . buffer , 0 , tmp , 0 , this . size ) ;
}
else
{
Array . Copy ( this . buffer , 0 , tmp , 0 , index ) ;
Array . Copy ( this . buffer , index , tmp , index + 1 , this . size - index ) ;
}
this . buffer = tmp ;
}
else
{
Array . Copy ( this . buffer , index , this . buffer , index + 1 , this . size - index ) ;
}
this . buffer [ index ] = item ;
+ + this . size ;
}
internal bool Remove ( T item )
{
int i = IndexOf ( item ) ;
if ( i > = 0 )
{
RemoveAt ( i ) ;
return true ;
}
return false ;
}
internal void RemoveAt ( int index )
{
Fx . Assert ( index > = 0 & & index < this . size , "" ) ;
if ( index < this . size - 1 )
{
Array . Copy ( this . buffer , index + 1 , this . buffer , index , this . size - index - 1 ) ;
}
this . buffer [ - - this . size ] = default ( T ) ;
}
int Search ( T item )
{
if ( size = = 0 )
return ~ 0 ;
return Search ( item , Comparer ) ;
}
int Search < K > ( K key , IItemComparer < K , T > comparer )
{
if ( this . size < = 8 )
{
return LinearSearch < K > ( key , comparer , 0 , this . size ) ;
}
else
{
return BinarySearch ( key , comparer ) ;
}
}
int BinarySearch < K > ( K key , IItemComparer < K , T > comparer )
{
// [low, high)
int low = 0 ;
int high = this . size ;
int mid , result ;
// Binary search is implemented here so we could look for a type that is different from the
// buffer type. Also, the search switches to linear for 8 or fewer elements.
while ( high - low > 8 )
{
mid = ( high + low ) / 2 ;
result = comparer . Compare ( key , this . buffer [ mid ] ) ;
if ( result < 0 )
{
high = mid ;
}
else if ( result > 0 )
{
low = mid + 1 ;
}
else
{
return mid ;
}
}
return LinearSearch < K > ( key , comparer , low , high ) ;
}
// [start, bound)
int LinearSearch < K > ( K key , IItemComparer < K , T > comparer , int start , int bound )
{
int result ;
for ( int i = start ; i < bound ; + + i )
{
result = comparer . Compare ( key , this . buffer [ i ] ) ;
if ( result = = 0 )
{
return i ;
}
if ( result < 0 )
{
// Return the bitwise negation of the insertion index
return ~ i ;
}
}
// Return the bitwise negation of the insertion index
return ~ bound ;
}
#if NO
internal T [ ] ToArray ( )
{
T [ ] tmp = new T [ this . size ] ;
Array . Copy ( this . buffer , 0 , tmp , 0 , this . size ) ;
return tmp ;
}
#endif
internal void Trim ( )
{
this . Capacity = this . size ;
}
internal class DefaultComparer : IItemComparer < T , T >
{
public static IComparer < T > Comparer ;
public DefaultComparer ( C comparer )
{
Comparer = comparer ;
}
public int Compare ( T item1 , T item2 )
{
return Comparer . Compare ( item1 , item2 ) ;
}
}
}
internal interface IItemComparer < K , V >
{
int Compare ( K key , V value ) ;
}
}