2017-09-07 23:10:17 +02:00
using System.Collections ;
2014-11-01 02:26:07 +01:00
using System.Collections.Generic ;
2014-11-01 14:09:56 +01:00
using System.Globalization ;
2014-11-01 02:26:07 +01:00
2014-11-03 00:05:54 +01:00
namespace System.Unicode
2014-11-01 02:26:07 +01:00
{
2014-12-16 02:32:00 +01:00
/// <summary>Represents a range of Unicode code points.</summary>
2014-11-24 21:47:06 +01:00
public struct UnicodeCodePointRange : IEnumerable < int >
2014-11-01 02:26:07 +01:00
{
2014-12-16 02:32:00 +01:00
/// <summary>Represents an enumerator which enumerated through all the code points in the <see cref="UnicodeCodePointRange"/>.</summary>
2014-11-02 21:56:24 +01:00
public struct Enumerator : IEnumerator < int >
{
private readonly int start ;
private readonly int end ;
private int index ;
2014-12-16 02:32:00 +01:00
/// <summary>Initializes a new instance of the <see cref="Enumerator"/> struct.</summary>
/// <param name="start">The start of the range.</param>
/// <param name="end">The end of the range.</param>
2014-11-02 21:56:24 +01:00
internal Enumerator ( int start , int end )
{
this . start = start ;
this . end = end ;
this . index = start - 1 ;
}
2014-12-16 02:32:00 +01:00
/// <summary>Does nothing.</summary>
public void Dispose () { }
/// <summary>Gets the element in the collection at the current position of the enumerator..</summary>
/// <value>The element in the collection at the current position of the enumerator.</value>
2014-11-02 21:56:24 +01:00
public int Current { get { return index ; } }
object IEnumerator . Current { get { return index ; } }
2014-12-16 02:32:00 +01:00
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.</returns>
2014-11-02 21:56:24 +01:00
public bool MoveNext () { return index < end && ++ index == index ; }
void IEnumerator . Reset () { index = start - 1 ; }
}
2014-12-16 02:32:00 +01:00
/// <summary>The first code point in the range.</summary>
2014-11-01 02:26:07 +01:00
public readonly int FirstCodePoint ;
2014-12-16 02:32:00 +01:00
/// <summary>The last code point in the range.</summary>
2014-11-01 02:26:07 +01:00
public readonly int LastCodePoint ;
2014-12-16 02:32:00 +01:00
/// <summary>Gets a value indicating whether this value represents a single code point.</summary>
/// <value><see langword="true" /> if this value represents a single code point; otherwise, <see langword="false" />.</value>
2014-11-02 22:29:56 +01:00
public bool IsSingleCodePoint { get { return FirstCodePoint == LastCodePoint ; } }
2014-12-16 02:32:00 +01:00
/// <summary>Initializes a new instance of the <see cref="UnicodeCodePointRange"/> struct for a single code point.</summary>
/// <param name="codePoint">The code point.</param>
/// <exception cref="System.ArgumentOutOfRangeException"></exception>
2014-11-24 21:47:06 +01:00
public UnicodeCodePointRange ( int codePoint )
2014-11-01 02:26:07 +01:00
{
2014-11-21 16:25:57 +01:00
if ( codePoint < 0 || codePoint > 0x10FFFF ) throw new ArgumentOutOfRangeException ( nameof ( codePoint ));
2014-11-01 14:09:56 +01:00
2014-11-01 02:26:07 +01:00
FirstCodePoint = codePoint ;
LastCodePoint = codePoint ;
}
2014-12-16 02:32:00 +01:00
/// <summary>Initializes a new instance of the <see cref="UnicodeCodePointRange"/> struct with specified bounds.</summary>
/// <param name="firstCodePoint">The first code point in the range.</param>
/// <param name="lastCodePoint">The last code point in the range.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="firstCodePoint"/> is less than 0 or greated than 0x10FFFF,
/// or <paramref name="lastCodePoint"/> is less than <paramref name="firstCodePoint"/> or greated than 0x10FFFF.
/// </exception>
2014-11-24 21:47:06 +01:00
public UnicodeCodePointRange ( int firstCodePoint , int lastCodePoint )
2014-11-01 02:26:07 +01:00
{
2014-11-21 16:25:57 +01:00
if ( firstCodePoint < 0 || firstCodePoint > 0x10FFFF ) throw new ArgumentOutOfRangeException ( nameof ( firstCodePoint ));
if ( lastCodePoint < firstCodePoint || lastCodePoint > 0x10FFFF ) throw new ArgumentOutOfRangeException ( nameof ( lastCodePoint ));
2014-11-01 14:09:56 +01:00
2014-11-16 21:27:57 +01:00
FirstCodePoint = firstCodePoint ;
2014-11-01 02:26:07 +01:00
LastCodePoint = lastCodePoint ;
}
2014-11-01 14:09:56 +01:00
2014-12-16 02:32:00 +01:00
/// <summary>Determines whether the range contains the specific code point.</summary>
/// <remarks>This method does not validate its inputs, but will always return <see langword="false"/> for any invalid code point.</remarks>
/// <param name="i">The integer to check against the range.</param>
/// <returns><see langword="true"/> if the range contains the specified code point; otherwise, <see langword="false"/>.</returns>
2014-11-02 21:56:24 +01:00
public bool Contains ( int i )
{
2014-12-16 02:32:00 +01:00
// Since the first and last code points have been checked or are at their default value of zero, the method will always exlcude invalid code points.
2014-11-02 21:56:24 +01:00
return i >= FirstCodePoint & i <= LastCodePoint ;
}
internal int CompareCodePoint ( int codePoint )
{
return FirstCodePoint <= codePoint ? LastCodePoint < codePoint ? 1 : 0 : - 1 ;
}
2014-12-16 02:32:00 +01:00
/// <summary>Returns a <see cref="System.String" /> that represents this instance.</summary>
/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
2014-11-01 14:09:56 +01:00
public override string ToString ()
{
return FirstCodePoint == LastCodePoint ? FirstCodePoint . ToString ( "X4" ) : FirstCodePoint . ToString ( "X4" ) + ".." + LastCodePoint . ToString ( "X4" );
}
2014-12-16 02:32:00 +01:00
/// <summary>Parses the specified into a <see cref="UnicodeCodePointRange"/>.</summary>
/// <remarks>Code point ranges are encoded as one unprefixed hexadecimal number for single code points, or a pair of unprefixed hexadecimal numbers separated by the characters "..".</remarks>
/// <param name="s">The text to parse.</param>
/// <returns>The parsed <see cref="UnicodeCodePointRange"/> value.</returns>
/// <exception cref="System.FormatException">The parameter <paramref name="s"/> was not in an allowed format.</exception>
2014-11-24 21:47:06 +01:00
public static UnicodeCodePointRange Parse ( string s )
2014-11-01 14:09:56 +01:00
{
int start , end ;
var rangeSeparatorOffset = s . IndexOf ( ".." );
if ( rangeSeparatorOffset == 0 ) throw new FormatException ();
else if ( rangeSeparatorOffset < 0 )
{
start = end = int . Parse ( s , NumberStyles . HexNumber );
}
else
{
start = int . Parse ( s . Substring ( 0 , rangeSeparatorOffset ), NumberStyles . HexNumber );
end = int . Parse ( s . Substring ( rangeSeparatorOffset + 2 ), NumberStyles . HexNumber );
2014-11-16 21:27:57 +01:00
}
2014-11-01 14:09:56 +01:00
2014-11-24 21:47:06 +01:00
return new UnicodeCodePointRange ( start , end );
2014-11-01 14:09:56 +01:00
}
2014-11-02 21:56:24 +01:00
2014-12-16 02:32:00 +01:00
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>A <see cref="Enumerator"/> that can be used to iterate through the collection.</returns>
2014-11-02 21:56:24 +01:00
public Enumerator GetEnumerator () { return new Enumerator ( FirstCodePoint , LastCodePoint ); }
IEnumerator < int > IEnumerable < int >. GetEnumerator () { return GetEnumerator (); }
IEnumerator IEnumerable . GetEnumerator () { return GetEnumerator (); }
2014-11-01 02:26:07 +01:00
}
}