Use ref returns to access character data, which should reduce memory consumption a bit.

Reduced some parts of the code by leveraging C# 6 and C# 7 features.
Preliminary work for adding emoji properties to characters.
This commit is contained in:
GoldenCrystal
2017-06-25 02:36:38 +02:00
parent b9d732f561
commit f9976c7a03
9 changed files with 213 additions and 263 deletions
@@ -1,129 +1,44 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode.Builder namespace System.Unicode.Builder
{ {
public sealed class UnicodeCharacterDataBuilder public sealed class UnicodeCharacterDataBuilder
{ {
private readonly UnicodeCodePointRange codePointRange;
private string name;
private UnicodeCategory category = UnicodeCategory.OtherNotAssigned; private UnicodeCategory category = UnicodeCategory.OtherNotAssigned;
private CanonicalCombiningClass canonicalCombiningClass;
private BidirectionalClass bidirectionalClass;
private CharacterDecompositionMapping characterDecompositionMapping;
private UnicodeNumericType numericType;
private UnicodeRationalNumber numericValue;
private bool bidirectionalMirrored;
private string oldName;
private string simpleUpperCaseMapping;
private string simpleLowerCaseMapping;
private string simpleTitleCaseMapping;
private ContributoryProperties contributoryProperties;
private CoreProperties coreProperties;
private readonly List<UnicodeNameAlias> nameAliases = new List<UnicodeNameAlias>(); private readonly List<UnicodeNameAlias> nameAliases = new List<UnicodeNameAlias>();
private readonly List<int> crossRerefences = new List<int>(); private readonly List<int> crossRerefences = new List<int>();
public UnicodeCodePointRange CodePointRange { get { return codePointRange; } } public UnicodeCodePointRange CodePointRange { get; }
public string Name public string Name { get; set; }
{
get { return name; }
set { name = value; }
}
public IList<UnicodeNameAlias> NameAliases { get { return nameAliases; } } public IList<UnicodeNameAlias> NameAliases { get { return nameAliases; } }
public UnicodeCategory Category public UnicodeCategory Category
{ {
get { return category; } get => category;
set set => category = Enum.IsDefined(typeof(UnicodeCategory), value) ?
{ value :
if (!Enum.IsDefined(typeof(UnicodeCategory), value)) throw new ArgumentOutOfRangeException(nameof(value));
{
throw new ArgumentOutOfRangeException(nameof(value));
}
category = value;
}
}
public CanonicalCombiningClass CanonicalCombiningClass
{
get { return canonicalCombiningClass; }
set { canonicalCombiningClass = value; } // Even values not defined in the enum are allowed here.
}
public BidirectionalClass BidirectionalClass
{
get { return bidirectionalClass; }
set { bidirectionalClass = value; }
}
public CharacterDecompositionMapping CharacterDecompositionMapping
{
get { return characterDecompositionMapping; }
set { characterDecompositionMapping = value; }
}
public UnicodeNumericType NumericType
{
get { return numericType; }
set { numericType = value; }
}
public UnicodeRationalNumber NumericValue
{
get { return numericValue; }
set { numericValue = value; }
}
public string OldName
{
get { return oldName; }
set { oldName = value; }
}
public bool BidirectionalMirrored
{
get { return bidirectionalMirrored; }
set { bidirectionalMirrored = value; }
}
public string SimpleUpperCaseMapping
{
get { return simpleUpperCaseMapping; }
set { simpleUpperCaseMapping = value; }
}
public string SimpleLowerCaseMapping
{
get { return simpleLowerCaseMapping; }
set { simpleLowerCaseMapping = value; }
}
public string SimpleTitleCaseMapping
{
get { return simpleTitleCaseMapping; }
set { simpleTitleCaseMapping = value; }
}
public ContributoryProperties ContributoryProperties
{
get { return contributoryProperties; }
set { contributoryProperties = value; }
}
public CoreProperties CoreProperties
{
get { return coreProperties; }
set { coreProperties = value; }
} }
public CanonicalCombiningClass CanonicalCombiningClass { get; set; } // Even values not defined in the enum are allowed here.
public BidirectionalClass BidirectionalClass { get; set; }
public CharacterDecompositionMapping CharacterDecompositionMapping { get; set; }
public UnicodeNumericType NumericType { get; set; }
public UnicodeRationalNumber NumericValue { get; set; }
public string OldName { get; set; }
public bool BidirectionalMirrored { get; set; }
public string SimpleUpperCaseMapping { get; set; }
public string SimpleLowerCaseMapping { get; set; }
public string SimpleTitleCaseMapping { get; set; }
public ContributoryProperties ContributoryProperties { get; set; }
public CoreProperties CoreProperties { get; set; }
public EmojiProperties EmojiProperties { get; set; }
public IList<int> CrossRerefences { get { return crossRerefences; } } public IList<int> CrossRerefences { get { return crossRerefences; } }
public UnicodeCharacterDataBuilder(int codePoint) public UnicodeCharacterDataBuilder(int codePoint)
@@ -133,7 +48,7 @@ namespace System.Unicode.Builder
public UnicodeCharacterDataBuilder(UnicodeCodePointRange codePointRange) public UnicodeCharacterDataBuilder(UnicodeCodePointRange codePointRange)
{ {
this.codePointRange = codePointRange; CodePointRange = codePointRange;
this.category = UnicodeCategory.OtherNotAssigned; this.category = UnicodeCategory.OtherNotAssigned;
} }
@@ -143,7 +58,7 @@ namespace System.Unicode.Builder
( (
CodePointRange, CodePointRange,
Name, Name,
NameAliases.Count > 0 ? NameAliases.ToArray() : UnicodeNameAlias.EmptyArray, nameAliases.Count > 0 ? nameAliases.ToArray() : UnicodeNameAlias.EmptyArray,
Category, Category,
CanonicalCombiningClass, CanonicalCombiningClass,
BidirectionalClass, BidirectionalClass,
@@ -157,7 +72,7 @@ namespace System.Unicode.Builder
SimpleLowerCaseMapping, SimpleLowerCaseMapping,
SimpleTitleCaseMapping, SimpleTitleCaseMapping,
ContributoryProperties, ContributoryProperties,
CoreProperties, (int)CoreProperties | (int)EmojiProperties << 20,
CrossRerefences.Count > 0 ? CrossRerefences.ToArray() : null CrossRerefences.Count > 0 ? CrossRerefences.ToArray() : null
); );
} }
@@ -168,27 +83,27 @@ namespace System.Unicode.Builder
UcdFields fields = default(UcdFields); UcdFields fields = default(UcdFields);
if (!codePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange; if (!CodePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange;
if (name != null || nameAliases.Count > 0) fields |= UcdFields.Name; // This field combines name and alias. if (Name != null || nameAliases.Count > 0) fields |= UcdFields.Name; // This field combines name and alias.
if (category != UnicodeCategory.OtherNotAssigned) fields |= UcdFields.Category; if (category != UnicodeCategory.OtherNotAssigned) fields |= UcdFields.Category;
if (canonicalCombiningClass != CanonicalCombiningClass.NotReordered) fields |= UcdFields.CanonicalCombiningClass; if (CanonicalCombiningClass != CanonicalCombiningClass.NotReordered) fields |= UcdFields.CanonicalCombiningClass;
/*if (bidirectionalClass != 0)*/ /*if (bidirectionalClass != 0)*/
fields |= UcdFields.BidirectionalClass; fields |= UcdFields.BidirectionalClass;
if (characterDecompositionMapping.DecompositionMapping != null) fields |= UcdFields.DecompositionMapping; if (CharacterDecompositionMapping.DecompositionMapping != null) fields |= UcdFields.DecompositionMapping;
fields |= (UcdFields)((int)numericType << 6); fields |= (UcdFields)((int)NumericType << 6);
if (bidirectionalMirrored) fields |= UcdFields.BidirectionalMirrored; if (BidirectionalMirrored) fields |= UcdFields.BidirectionalMirrored;
if (oldName != null) fields |= UcdFields.OldName; if (OldName != null) fields |= UcdFields.OldName;
if (simpleUpperCaseMapping != null) fields |= UcdFields.SimpleUpperCaseMapping; if (SimpleUpperCaseMapping != null) fields |= UcdFields.SimpleUpperCaseMapping;
if (simpleLowerCaseMapping != null) fields |= UcdFields.SimpleLowerCaseMapping; if (SimpleLowerCaseMapping != null) fields |= UcdFields.SimpleLowerCaseMapping;
if (simpleTitleCaseMapping != null) fields |= UcdFields.SimpleTitleCaseMapping; if (SimpleTitleCaseMapping != null) fields |= UcdFields.SimpleTitleCaseMapping;
if (contributoryProperties != 0) fields |= UcdFields.ContributoryProperties; if (ContributoryProperties != 0) fields |= UcdFields.ContributoryProperties;
if (coreProperties != 0) fields |= UcdFields.CoreProperties; if (CoreProperties != 0 || EmojiProperties != 0) fields |= UcdFields.CorePropertiesAndEmojiProperties;
if (crossRerefences.Count > 0) fields |= UcdFields.CrossRerefences; if (crossRerefences.Count > 0) fields |= UcdFields.CrossRerefences;
writer.Write((ushort)fields); writer.Write((ushort)fields);
writer.WriteCodePoint(codePointRange.FirstCodePoint); writer.WriteCodePoint(CodePointRange.FirstCodePoint);
if ((fields & UcdFields.CodePointRange) != 0) writer.WriteCodePoint(CodePointRange.LastCodePoint); if ((fields & UcdFields.CodePointRange) != 0) writer.WriteCodePoint(CodePointRange.LastCodePoint);
if ((fields & UcdFields.Name) != 0) if ((fields & UcdFields.Name) != 0)
@@ -200,38 +115,38 @@ namespace System.Unicode.Builder
if (nameAliases.Count > 0) if (nameAliases.Count > 0)
{ {
writer.WritePackedLength((byte)(name != null ? 3 : 2), nameAliases.Count); writer.WritePackedLength((byte)(Name != null ? 3 : 2), nameAliases.Count);
if (name != null) if (Name != null)
writer.WriteNamePropertyToFile(name); writer.WriteNamePropertyToFile(Name);
foreach (var nameAlias in nameAliases) foreach (var nameAlias in nameAliases)
writer.WriteNameAliasToFile(nameAlias); writer.WriteNameAliasToFile(nameAlias);
} }
else else
{ {
writer.WriteNamePropertyToFile(name); writer.WriteNamePropertyToFile(Name);
} }
} }
if ((fields & UcdFields.Category) != 0) writer.Write((byte)category); if ((fields & UcdFields.Category) != 0) writer.Write((byte)category);
if ((fields & UcdFields.CanonicalCombiningClass) != 0) writer.Write((byte)canonicalCombiningClass); if ((fields & UcdFields.CanonicalCombiningClass) != 0) writer.Write((byte)CanonicalCombiningClass);
if ((fields & UcdFields.BidirectionalClass) != 0) writer.Write((byte)bidirectionalClass); if ((fields & UcdFields.BidirectionalClass) != 0) writer.Write((byte)BidirectionalClass);
if ((fields & UcdFields.DecompositionMapping) != 0) if ((fields & UcdFields.DecompositionMapping) != 0)
{ {
writer.Write((byte)characterDecompositionMapping.DecompositionType); writer.Write((byte)CharacterDecompositionMapping.DecompositionType);
writer.Write(characterDecompositionMapping.DecompositionMapping); writer.Write(CharacterDecompositionMapping.DecompositionMapping);
} }
if ((fields & UcdFields.NumericNumeric) != 0) if ((fields & UcdFields.NumericNumeric) != 0)
{ {
writer.Write(numericValue.Numerator); writer.Write(NumericValue.Numerator);
writer.Write(numericValue.Denominator); writer.Write(NumericValue.Denominator);
} }
if ((fields & UcdFields.OldName) != 0) writer.Write(oldName); if ((fields & UcdFields.OldName) != 0) writer.Write(OldName);
if ((fields & UcdFields.SimpleUpperCaseMapping) != 0) writer.Write(simpleUpperCaseMapping); if ((fields & UcdFields.SimpleUpperCaseMapping) != 0) writer.Write(SimpleUpperCaseMapping);
if ((fields & UcdFields.SimpleLowerCaseMapping) != 0) writer.Write(simpleLowerCaseMapping); if ((fields & UcdFields.SimpleLowerCaseMapping) != 0) writer.Write(SimpleLowerCaseMapping);
if ((fields & UcdFields.SimpleTitleCaseMapping) != 0) writer.Write(simpleTitleCaseMapping); if ((fields & UcdFields.SimpleTitleCaseMapping) != 0) writer.Write(SimpleTitleCaseMapping);
if ((fields & UcdFields.ContributoryProperties) != 0) writer.Write((int)contributoryProperties); if ((fields & UcdFields.ContributoryProperties) != 0) writer.Write((int)ContributoryProperties);
if ((fields & UcdFields.CoreProperties) != 0) writer.WriteUInt24((int)coreProperties); if ((fields & UcdFields.CorePropertiesAndEmojiProperties) != 0) writer.WriteUInt24((int)CoreProperties | (int)EmojiProperties << 20);
if ((fields & UcdFields.CrossRerefences) != 0) if ((fields & UcdFields.CrossRerefences) != 0)
{ {
writer.Write(checked((byte)(crossRerefences.Count - 1))); writer.Write(checked((byte)(crossRerefences.Count - 1)));
@@ -51,6 +51,7 @@ namespace UnicodeInformation.Tests
[InlineData(0x0D5D, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "3/20", "MALAYALAM FRACTION THREE TWENTIETHS", "Malayalam")] [InlineData(0x0D5D, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "3/20", "MALAYALAM FRACTION THREE TWENTIETHS", "Malayalam")]
[InlineData(0x0D59, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "1/40", "MALAYALAM FRACTION ONE FORTIETH", "Malayalam")] [InlineData(0x0D59, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "1/40", "MALAYALAM FRACTION ONE FORTIETH", "Malayalam")]
[InlineData(0x1F953, UnicodeCategory.OtherSymbol, UnicodeNumericType.None, null, "BACON", "Supplemental Symbols and Pictographs")] [InlineData(0x1F953, UnicodeCategory.OtherSymbol, UnicodeNumericType.None, null, "BACON", "Supplemental Symbols and Pictographs")]
[InlineData(0x1F966, UnicodeCategory.OtherSymbol, UnicodeNumericType.None, null, "BROCCOLI", "Supplemental Symbols and Pictographs")]
public void CharacterInfoShouldHaveExpectedResults(int codePoint, UnicodeCategory expectedCategory, UnicodeNumericType expectedNumericType, string expectedNumericValue, string expectedName, string expectedBlock) public void CharacterInfoShouldHaveExpectedResults(int codePoint, UnicodeCategory expectedCategory, UnicodeNumericType expectedNumericType, string expectedNumericValue, string expectedName, string expectedBlock)
{ {
var info = UnicodeInfo.GetCharInfo(codePoint); var info = UnicodeInfo.GetCharInfo(codePoint);
+2
View File
@@ -12,6 +12,8 @@ namespace System.Unicode
[Flags] [Flags]
public enum CoreProperties : int public enum CoreProperties : int
{ {
// NB: Be careful when adding new properties to the enum, as EmojiProperties will be stored in the 4 upper bits out of 24.
/// <summary>Represents the Lowercase property.</summary> /// <summary>Represents the Lowercase property.</summary>
[ValueName("Lowercase"), ValueName("Lower"), Display(Name = "Lowercase")] [ValueName("Lowercase"), ValueName("Lower"), Display(Name = "Lowercase")]
Lowercase = 0x00000001, Lowercase = 0x00000001,
+29
View File
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace System.Unicode
{
/// <summary>A bitmask of the various available emoji properties.</summary>
/// <remarks>Emoji properties are not formally part of UCD, but .</remarks>
[Flags]
public enum EmojiProperties : byte
{
// NB: These values will be stored in as the most significant bits of CoreProperties.
// CoreProperties are stored using 18 bits out of 24 available bits, leaving at most 6 bits to use. 4 of those will be used by emoji properties.
/// <summary>Represents the Emoji property.</summary>
[ValueName("Emoji"), Display(Name = "Emoji")]
Emoji = 0x1,
/// <summary>Represents the Emoji property.</summary>
[ValueName("Emoji_Presentation"), Display(Name = "Emoji_Presentation")]
EmojiPresentation = 0x2,
/// <summary>Represents the Emoji property.</summary>
[ValueName("Emoji_Modifier_Base"), Display(Name = "Emoji_Modifier_Base")]
EmojiModifierBase = 0x4,
/// <summary>Represents the Emoji property.</summary>
[ValueName("Emoji_Component"), Display(Name = "Emoji_Component")]
EmojiComponent = 0x8,
}
}
+1 -1
View File
@@ -34,7 +34,7 @@ namespace System.Unicode
SimpleTitleCaseMapping = 4096, SimpleTitleCaseMapping = 4096,
ContributoryProperties = 8192, ContributoryProperties = 8192,
CoreProperties = 16384, CorePropertiesAndEmojiProperties = 16384,
CrossRerefences = 32768, CrossRerefences = 32768,
} }
+56 -37
View File
@@ -14,46 +14,49 @@ namespace System.Unicode
private readonly int codePoint; private readonly int codePoint;
/// <summary>The name of the code point.</summary> /// <summary>The name of the code point.</summary>
private readonly string name; private readonly string name;
private readonly UnicodeCharacterData unicodeCharacterData; private readonly int unicodeCharacterDataIndex;
private readonly UnihanCharacterData unihanCharacterData; private readonly int unihanCharacterDataIndex;
private readonly string block; private readonly string block;
private ref UnicodeCharacterData UnicodeCharacterData => ref UnicodeInfo.GetUnicodeCharacterData(unicodeCharacterDataIndex);
private ref UnihanCharacterData UnihanCharacterData => ref UnicodeInfo.GetUnihanCharacterData(unihanCharacterDataIndex);
/// <summary>Gets the code point as an UTF-32 value.</summary> /// <summary>Gets the code point as an UTF-32 value.</summary>
public int CodePoint { get { return codePoint; } } public int CodePoint => codePoint;
/// <summary>Gets the code point name.</summary> /// <summary>Gets the code point name.</summary>
/// <remarks>This is the Name Unicode property.</remarks> /// <remarks>This is the Name Unicode property.</remarks>
[ValueName("Name"), ValueName("na")] [ValueName("Name"), ValueName("na")]
public string Name { get { return name; } } public string Name => name;
/// <summary>Gets the name aliases defined for the code point.</summary> /// <summary>Gets the name aliases defined for the code point.</summary>
/// <remarks>This is the Name_Alias Unicode property.</remarks> /// <remarks>This is the Name_Alias Unicode property.</remarks>
[ValueName("Name_Alias")] [ValueName("Name_Alias")]
public UnicodeNameAliasCollection NameAliases { get { return new UnicodeNameAliasCollection(unicodeCharacterData?.NameAliases); } } public UnicodeNameAliasCollection NameAliases => new UnicodeNameAliasCollection(UnicodeCharacterData.NameAliases);
/// <summary>Gets the category defined for the code point.</summary> /// <summary>Gets the category defined for the code point.</summary>
/// <remarks>This is the General_Category Unicode property.</remarks> /// <remarks>This is the General_Category Unicode property.</remarks>
[ValueName("General_Category"), ValueName("gc")] [ValueName("General_Category"), ValueName("gc")]
public UnicodeCategory Category { get { return unicodeCharacterData?.Category ?? UnicodeCategory.OtherNotAssigned; } } public UnicodeCategory Category => UnicodeCharacterData.Category;
/// <summary>Gets the name of the block where the code point is located.</summary> /// <summary>Gets the name of the block where the code point is located.</summary>
/// <remarks>This is the Block Unicode property.</remarks> /// <remarks>This is the Block Unicode property.</remarks>
[ValueName("Block"), ValueName("blk")] [ValueName("Block"), ValueName("blk")]
public string Block { get { return block ?? UnicodeInfo.DefaultBlock; } } public string Block => block ?? UnicodeInfo.DefaultBlock;
/// <summary>Gets the canonical combining class defined for the code point.</summary> /// <summary>Gets the canonical combining class defined for the code point.</summary>
/// <remarks>This is the Canonical_Combining_Class Unicode property.</remarks> /// <remarks>This is the Canonical_Combining_Class Unicode property.</remarks>
[ValueName("Canonical_Combining_Class"), ValueName("ccc")] [ValueName("Canonical_Combining_Class"), ValueName("ccc")]
public CanonicalCombiningClass CanonicalCombiningClass { get { return unicodeCharacterData?.CanonicalCombiningClass ?? CanonicalCombiningClass.NotReordered; } } public CanonicalCombiningClass CanonicalCombiningClass => UnicodeCharacterData.CanonicalCombiningClass;
/// <summary>Gets the bidirectional class defined for the code point.</summary> /// <summary>Gets the bidirectional class defined for the code point.</summary>
/// <remarks>This is the Bidi_Class Unicode property.</remarks> /// <remarks>This is the Bidi_Class Unicode property.</remarks>
[ValueName("Bidi_Class"), ValueName("bc")] [ValueName("Bidi_Class"), ValueName("bc")]
public BidirectionalClass BidirectionalClass { get { return unicodeCharacterData?.BidirectionalClass ?? BidirectionalClass.LeftToRight; } } public BidirectionalClass BidirectionalClass => UnicodeCharacterData.BidirectionalClass;
/// <summary>Gets the decomposition type defined for the code point.</summary> /// <summary>Gets the decomposition type defined for the code point.</summary>
/// <remarks>This is the Decomposition_Type Unicode property.</remarks> /// <remarks>This is the Decomposition_Type Unicode property.</remarks>
[ValueName("Decomposition_Type"), ValueName("dt")] [ValueName("Decomposition_Type"), ValueName("dt")]
public CompatibilityFormattingTag DecompositionType { get { return unicodeCharacterData?.DecompositionType ?? CompatibilityFormattingTag.Canonical; } } public CompatibilityFormattingTag DecompositionType => UnicodeCharacterData.DecompositionType;
/// <summary>Gets the decomposition mapping defined for the code point.</summary> /// <summary>Gets the decomposition mapping defined for the code point.</summary>
/// <remarks>This is the Decomposition_Mapping Unicode property.</remarks> /// <remarks>This is the Decomposition_Mapping Unicode property.</remarks>
[ValueName("Decomposition_Mapping"), ValueName("dm")] [ValueName("Decomposition_Mapping"), ValueName("dm")]
public string DecompositionMapping { get { return unicodeCharacterData?.DecompositionMapping; } } public string DecompositionMapping => UnicodeCharacterData.DecompositionMapping;
/// <summary>Gets the numeric type defined for the code point.</summary> /// <summary>Gets the numeric type defined for the code point.</summary>
/// <remarks> /// <remarks>
/// This is the Numeric_Type Unicode property. /// This is the Numeric_Type Unicode property.
@@ -62,10 +65,10 @@ namespace System.Unicode
/// In this case, the property <see cref="UnihanNumericType"/> will indicate the origin of the numeric value in Unihan data. /// In this case, the property <see cref="UnihanNumericType"/> will indicate the origin of the numeric value in Unihan data.
/// </remarks> /// </remarks>
[ValueName("Numeric_Type"), ValueName("nt")] [ValueName("Numeric_Type"), ValueName("nt")]
public UnicodeNumericType NumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType != UnihanNumericType.None ? UnicodeNumericType.Numeric : UnicodeNumericType.None : unicodeCharacterData?.NumericType ?? UnicodeNumericType.None; } } public UnicodeNumericType NumericType => unihanCharacterDataIndex >= 0 ? UnihanCharacterData.NumericType != UnihanNumericType.None ? UnicodeNumericType.Numeric : UnicodeNumericType.None : UnicodeCharacterData.NumericType;
/// <summary>Gets the Unihan numeric type defined for the code point.</summary> /// <summary>Gets the Unihan numeric type defined for the code point.</summary>
/// <remarks>The value of this property indicates which of the kPrimaryNumeric, kAccountingNumeric, or kOtherNumeric Unihan property is set, if any.</remarks> /// <remarks>The value of this property indicates which of the kPrimaryNumeric, kAccountingNumeric, or kOtherNumeric Unihan property is set, if any.</remarks>
public UnihanNumericType UnihanNumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType : UnihanNumericType.None; } } public UnihanNumericType UnihanNumericType => unihanCharacterDataIndex >= 0 ? UnihanCharacterData.NumericType : UnihanNumericType.None;
/// <summary>Gets the numeric value defined for the code point.</summary> /// <summary>Gets the numeric value defined for the code point.</summary>
/// <remarks> /// <remarks>
/// This is the Numeric_Value Unicode property. /// This is the Numeric_Value Unicode property.
@@ -73,47 +76,63 @@ namespace System.Unicode
/// When this property set, the <see cref="NumericType"/> and <see cref="UnihanNumericType"/> indicates the nature of the numeric value. /// When this property set, the <see cref="NumericType"/> and <see cref="UnihanNumericType"/> indicates the nature of the numeric value.
/// </remarks> /// </remarks>
[ValueName("Numeric_Value"), ValueName("nv")] [ValueName("Numeric_Value"), ValueName("nv")]
public UnicodeRationalNumber? NumericValue { get { return unihanCharacterData != null && unihanCharacterData.NumericType != UnihanNumericType.None ? new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1) : unicodeCharacterData?.NumericValue; } } public UnicodeRationalNumber? NumericValue
{
get
{
if (unihanCharacterDataIndex >= 0)
{
ref var unihanCharacterData = ref UnihanCharacterData;
if (unihanCharacterData.NumericType != UnihanNumericType.None)
{
return new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1);
}
}
return UnicodeCharacterData.NumericValue;
}
}
/// <summary>Gets a value indicating whether the character is mirrored in bidirectional text.</summary> /// <summary>Gets a value indicating whether the character is mirrored in bidirectional text.</summary>
/// <remarks>This is the Bidi_Mirrored Unicode property.</remarks> /// <remarks>This is the Bidi_Mirrored Unicode property.</remarks>
[ValueName("Bidi_Mirrored")] [ValueName("Bidi_Mirrored")]
public bool BidirectionalMirrored { get { return unicodeCharacterData?.BidirectionalMirrored ?? false; } } public bool BidirectionalMirrored => UnicodeCharacterData.BidirectionalMirrored;
/// <summary>Gets the Unicode 1 name of the code point.</summary> /// <summary>Gets the Unicode 1 name of the code point.</summary>
/// <remarks>This is the Unicode_1_Name Unicode property.</remarks> /// <remarks>This is the Unicode_1_Name Unicode property.</remarks>
[ValueName("Unicode_1_Name"), ValueName("na1")] [ValueName("Unicode_1_Name"), ValueName("na1")]
public string OldName { get { return unicodeCharacterData?.OldName; } } public string OldName => UnicodeCharacterData.OldName;
/// <summary>Gets the simple uppercase mapping defined for the code point.</summary> /// <summary>Gets the simple uppercase mapping defined for the code point.</summary>
/// <remarks>This is the Simple_Uppercase_Mapping Unicode property.</remarks> /// <remarks>This is the Simple_Uppercase_Mapping Unicode property.</remarks>
[ValueName("Simple_Uppercase_Mapping"), ValueName("suc")] [ValueName("Simple_Uppercase_Mapping"), ValueName("suc")]
public string SimpleUpperCaseMapping { get { return unicodeCharacterData?.SimpleUpperCaseMapping; } } public string SimpleUpperCaseMapping => UnicodeCharacterData.SimpleUpperCaseMapping;
/// <summary>Gets the simple lowercase mapping defined for the code point.</summary> /// <summary>Gets the simple lowercase mapping defined for the code point.</summary>
/// <remarks>This is the Simple_Lowercase_Mapping Unicode property.</remarks> /// <remarks>This is the Simple_Lowercase_Mapping Unicode property.</remarks>
[ValueName("Simple_Lowercase_Mapping"), ValueName("slc")] [ValueName("Simple_Lowercase_Mapping"), ValueName("slc")]
public string SimpleLowerCaseMapping { get { return unicodeCharacterData?.SimpleLowerCaseMapping; } } public string SimpleLowerCaseMapping => UnicodeCharacterData.SimpleLowerCaseMapping;
/// <summary>Gets the simple titlecase mapping defined for the code point.</summary> /// <summary>Gets the simple titlecase mapping defined for the code point.</summary>
/// <remarks>This is the Simple_Titlecase_Mapping Unicode property.</remarks> /// <remarks>This is the Simple_Titlecase_Mapping Unicode property.</remarks>
[ValueName("Simple_Titlecase_Mapping"), ValueName("stc")] [ValueName("Simple_Titlecase_Mapping"), ValueName("stc")]
public string SimpleTitleCaseMapping { get { return unicodeCharacterData?.SimpleTitleCaseMapping; } } public string SimpleTitleCaseMapping => UnicodeCharacterData.SimpleTitleCaseMapping;
/// <summary>Gets a value indicating which of the boolean contributory properties are defined for the code point.</summary> /// <summary>Gets a value indicating which of the boolean contributory properties are defined for the code point.</summary>
/// <remarks> /// <remarks>
/// The Unicode standard indicates contributory properties as neither normative nor informational. /// The Unicode standard indicates contributory properties as neither normative nor informational.
/// However, contributory properties are used by Unicode to define the code properties. /// However, contributory properties are used by Unicode to define the code properties.
/// The corresponding core properties may be accessed from the <see cref="CoreProperties"/> member. /// The corresponding core properties may be accessed from the <see cref="CoreProperties"/> member.
/// </remarks> /// </remarks>
public ContributoryProperties ContributoryProperties { get { return unicodeCharacterData?.ContributoryProperties ?? 0; } } public ContributoryProperties ContributoryProperties => UnicodeCharacterData.ContributoryProperties;
/// <summary>Gets a value indicating which of the boolean core properties are defined for the code point.</summary> /// <summary>Gets a value indicating which of the boolean core properties are defined for the code point.</summary>
/// <remarks>The core properties are computed by combining various character information together with contributory properties.</remarks> /// <remarks>The core properties are computed by combining various character information together with contributory properties.</remarks>
public CoreProperties CoreProperties { get { return unicodeCharacterData?.CoreProperties ?? 0; } } public CoreProperties CoreProperties => UnicodeCharacterData.CoreProperties;
/// <summary>Gets a collection of cross references associated with the code point.</summary> /// <summary>Gets a collection of cross references associated with the code point.</summary>
/// <remarks>The cross references have been extracted from Unicode data but are not normative.</remarks> /// <remarks>The cross references have been extracted from Unicode data but are not normative.</remarks>
public UnicodeCrossReferenceCollection CrossRerefences { get { return new UnicodeCrossReferenceCollection(unicodeCharacterData?.CrossRerefences); } } public UnicodeCrossReferenceCollection CrossRerefences => new UnicodeCrossReferenceCollection(UnicodeCharacterData.CrossRerefences);
/// <summary>Gets the radical and stroke count for the code point.</summary> /// <summary>Gets the radical and stroke count for the code point.</summary>
/// <remarks> /// <remarks>
/// This is the Unicode_Radical_Stroke Unicode property, defined as kRSUnicode in Unihan data. /// This is the Unicode_Radical_Stroke Unicode property, defined as kRSUnicode in Unihan data.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kRSUnicode"), ValueName("cjkRSUnicode"), ValueName("Unicode_Radical_Stroke"), ValueName("URS")] [ValueName("kRSUnicode"), ValueName("cjkRSUnicode"), ValueName("Unicode_Radical_Stroke"), ValueName("URS")]
public UnicodeRadicalStrokeCountCollection UnicodeRadicalStrokeCounts { get { return new UnicodeRadicalStrokeCountCollection(unihanCharacterData?.UnicodeRadicalStrokeCounts); } } public UnicodeRadicalStrokeCountCollection UnicodeRadicalStrokeCounts => new UnicodeRadicalStrokeCountCollection(UnihanCharacterData.UnicodeRadicalStrokeCounts);
/// <summary>Gets the definition of the character from the Unihan data.</summary> /// <summary>Gets the definition of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
@@ -121,56 +140,56 @@ namespace System.Unicode
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kDefinition")] [ValueName("kDefinition")]
public string Definition { get { return unihanCharacterData?.Definition; } } public string Definition => UnihanCharacterData.Definition;
/// <summary>Gets the Mandarin reading of the character from the Unihan data.</summary> /// <summary>Gets the Mandarin reading of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
/// This is the kMandarin Unicode property. /// This is the kMandarin Unicode property.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kMandarin")] [ValueName("kMandarin")]
public string MandarinReading { get { return unihanCharacterData?.MandarinReading; } } public string MandarinReading => UnihanCharacterData.MandarinReading;
/// <summary>Gets the Cantonese reading of the character from the Unihan data.</summary> /// <summary>Gets the Cantonese reading of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
/// This is the kCantonese Unicode property. /// This is the kCantonese Unicode property.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kCantonese")] [ValueName("kCantonese")]
public string CantoneseReading { get { return unihanCharacterData?.CantoneseReading; } } public string CantoneseReading => UnihanCharacterData.CantoneseReading;
/// <summary>Gets the Japanese Kun reading of the character from the Unihan data.</summary> /// <summary>Gets the Japanese Kun reading of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
/// This is the kJapaneseKun Unicode property. /// This is the kJapaneseKun Unicode property.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kJapaneseKun")] [ValueName("kJapaneseKun")]
public string JapaneseKunReading { get { return unihanCharacterData?.JapaneseKunReading; } } public string JapaneseKunReading => UnihanCharacterData.JapaneseKunReading;
/// <summary>Gets the Japanese On reading of the character from the Unihan data.</summary> /// <summary>Gets the Japanese On reading of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
/// This is the kJapaneseOn Unicode property. /// This is the kJapaneseOn Unicode property.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kJapaneseOn")] [ValueName("kJapaneseOn")]
public string JapaneseOnReading { get { return unihanCharacterData?.JapaneseOnReading; } } public string JapaneseOnReading => UnihanCharacterData.JapaneseOnReading;
/// <summary>Gets the Korean reading of the character from the Unihan data.</summary> /// <summary>Gets the Korean reading of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
/// This is the kKorean Unicode property. /// This is the kKorean Unicode property.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kKorean")] [ValueName("kKorean")]
public string KoreanReading { get { return unihanCharacterData?.KoreanReading; } } public string KoreanReading => UnihanCharacterData.KoreanReading;
/// <summary>Gets the Hangul reading of the character from the Unihan data.</summary> /// <summary>Gets the Hangul reading of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
/// This is the kHangul Unicode property. /// This is the kHangul Unicode property.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kHangul")] [ValueName("kHangul")]
public string HangulReading { get { return unihanCharacterData?.HangulReading; } } public string HangulReading => UnihanCharacterData.HangulReading;
/// <summary>Gets the Vietnamese reading of the character from the Unihan data.</summary> /// <summary>Gets the Vietnamese reading of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
/// This is the kVietnamese Unicode property. /// This is the kVietnamese Unicode property.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kVietnamese")] [ValueName("kVietnamese")]
public string VietnameseReading { get { return unihanCharacterData?.VietnameseReading; } } public string VietnameseReading => UnihanCharacterData.VietnameseReading;
/// <summary>Gets the simplified variant of the character from the Unihan data.</summary> /// <summary>Gets the simplified variant of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
@@ -178,21 +197,21 @@ namespace System.Unicode
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kSimplifiedVariant")] [ValueName("kSimplifiedVariant")]
public string SimplifiedVariant { get { return unihanCharacterData?.SimplifiedVariant; } } public string SimplifiedVariant => UnihanCharacterData.SimplifiedVariant;
/// <summary>Gets the traditional variant of the character from the Unihan data.</summary> /// <summary>Gets the traditional variant of the character from the Unihan data.</summary>
/// <remarks> /// <remarks>
/// This is the kTraditionalVariant Unicode property. /// This is the kTraditionalVariant Unicode property.
/// This property is only ever useful when the character is a CJK ideograph. /// This property is only ever useful when the character is a CJK ideograph.
/// </remarks> /// </remarks>
[ValueName("kTraditionalVariant")] [ValueName("kTraditionalVariant")]
public string TraditionalVariant { get { return unihanCharacterData?.TraditionalVariant; } } public string TraditionalVariant => UnihanCharacterData.TraditionalVariant;
internal UnicodeCharInfo(int codePoint, UnicodeCharacterData unicodeCharacterData, UnihanCharacterData unihanCharacterData, string block) internal UnicodeCharInfo(int codePoint, int unicodeCharacterDataIndex, int unihanCharacterDataIndex, string block)
{ {
this.codePoint = codePoint; this.codePoint = codePoint;
this.name = unicodeCharacterData != null ? UnicodeInfo.GetName(codePoint, unicodeCharacterData) : null; this.name = unicodeCharacterDataIndex >= 0 ? UnicodeInfo.GetName(codePoint, ref UnicodeInfo.GetUnicodeCharacterData(unicodeCharacterDataIndex)) : null;
this.unicodeCharacterData = unicodeCharacterData; this.unicodeCharacterDataIndex = unicodeCharacterDataIndex;
this.unihanCharacterData = unihanCharacterData; this.unihanCharacterDataIndex = unihanCharacterDataIndex;
this.block = block; this.block = block;
} }
} }
+8 -11
View File
@@ -1,13 +1,8 @@
using System; using System.Globalization;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode namespace System.Unicode
{ {
internal sealed class UnicodeCharacterData internal struct UnicodeCharacterData
{ {
public readonly UnicodeCodePointRange CodePointRange; public readonly UnicodeCodePointRange CodePointRange;
public readonly string Name; public readonly string Name;
@@ -25,7 +20,9 @@ namespace System.Unicode
public readonly string SimpleLowerCaseMapping; public readonly string SimpleLowerCaseMapping;
public readonly string SimpleTitleCaseMapping; public readonly string SimpleTitleCaseMapping;
public readonly ContributoryProperties ContributoryProperties; public readonly ContributoryProperties ContributoryProperties;
public readonly CoreProperties CoreProperties; private readonly int corePropertiesAndEmojiProperties;
public CoreProperties CoreProperties => (CoreProperties)(corePropertiesAndEmojiProperties & 0x000FFFFF);
public EmojiProperties EmojiProperties => (EmojiProperties)(corePropertiesAndEmojiProperties >> 20);
public readonly int[] CrossRerefences; // NB: It seems that parsing NamesList is required in order to provide data for this field ? public readonly int[] CrossRerefences; // NB: It seems that parsing NamesList is required in order to provide data for this field ?
@@ -47,7 +44,7 @@ namespace System.Unicode
string simpleLowerCaseMapping, string simpleLowerCaseMapping,
string simpleTitleCaseMapping, string simpleTitleCaseMapping,
ContributoryProperties contributoryProperties, ContributoryProperties contributoryProperties,
CoreProperties coreProperties, int corePropertiesAndEmojiProperties,
int[] crossRerefences int[] crossRerefences
) )
{ {
@@ -67,10 +64,10 @@ namespace System.Unicode
this.SimpleLowerCaseMapping = simpleLowerCaseMapping; this.SimpleLowerCaseMapping = simpleLowerCaseMapping;
this.SimpleTitleCaseMapping = simpleTitleCaseMapping; this.SimpleTitleCaseMapping = simpleTitleCaseMapping;
this.ContributoryProperties = contributoryProperties; this.ContributoryProperties = contributoryProperties;
this.CoreProperties = coreProperties; this.corePropertiesAndEmojiProperties = corePropertiesAndEmojiProperties;
this.CrossRerefences = crossRerefences; this.CrossRerefences = crossRerefences;
} }
public UnicodeRationalNumber? NumericValue { get { return NumericType != UnicodeNumericType.None ? numericValue : null as UnicodeRationalNumber?; } } public UnicodeRationalNumber? NumericValue => NumericType != UnicodeNumericType.None ? numericValue : null as UnicodeRationalNumber?;
} }
} }
+62 -69
View File
@@ -13,6 +13,11 @@ namespace System.Unicode
/// <summary>Provides access to unicode information.</summary> /// <summary>Provides access to unicode information.</summary>
public static class UnicodeInfo public static class UnicodeInfo
{ {
// NB: These fields will be used as a default value for UnicodeCharacterData and UnihanCharacterData, and passed by reference.
// They should be considered as being redonly, even if they aren't explicitely.
private static /*readonly*/ UnicodeCharacterData DefaultUnicodeCharacterData = new UnicodeCharacterData(default(UnicodeCodePointRange), null, null, UnicodeCategory.OtherNotAssigned, 0, 0, 0, null, 0, default(UnicodeRationalNumber), false, null, null, null, null, 0, 0, null);
private static /*readonly*/ UnihanCharacterData DefaultUnihanCharacterData = default(UnihanCharacterData);
/// <summary>The block name returned when no block is assigned to a specific code point.</summary> /// <summary>The block name returned when no block is assigned to a specific code point.</summary>
public const string DefaultBlock = "No_Block"; public const string DefaultBlock = "No_Block";
@@ -47,14 +52,18 @@ namespace System.Unicode
if (formatVersion != 2) throw new InvalidDataException(); if (formatVersion != 2) throw new InvalidDataException();
var fileUnicodeVersion = new Version(reader.ReadUInt16(), reader.ReadByte(), reader.ReadByte()); var fileUnicodeVersion = new Version(reader.ReadUInt16(), reader.ReadByte(), reader.ReadByte());
var unicodeCharacterDataEntries = new UnicodeCharacterData[ReadCodePoint(reader)]; var unicodeCharacterDataEntries = new UnicodeCharacterData[ReadCodePoint(reader)]; // Allocate one extra entry to act as a dummy entry.
byte[] nameBuffer = new byte[128]; byte[] nameBuffer = new byte[128];
int mci = 0; int mci = 0;
for (i = 0; i < unicodeCharacterDataEntries.Length; ++i) for (i = 0; i < unicodeCharacterDataEntries.Length; ++i)
{ {
if ((unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader, nameBuffer)).CodePointRange.Contains(i)) mci = i; ReadUnicodeCharacterDataEntry(reader, nameBuffer, out unicodeCharacterDataEntries[i]);
if (unicodeCharacterDataEntries[i].CodePointRange.Contains(i))
{
mci = i;
}
else else
{ {
++i; ++i;
@@ -66,7 +75,7 @@ namespace System.Unicode
for (; i < unicodeCharacterDataEntries.Length; ++i) for (; i < unicodeCharacterDataEntries.Length; ++i)
{ {
unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader, nameBuffer); ReadUnicodeCharacterDataEntry(reader, nameBuffer, out unicodeCharacterDataEntries[i]);
} }
var blockEntries = new UnicodeBlock[reader.ReadUInt16()]; var blockEntries = new UnicodeBlock[reader.ReadUInt16()];
@@ -87,7 +96,7 @@ namespace System.Unicode
for (i = 0; i < unihanCharacterDataEntries.Length; ++i) for (i = 0; i < unihanCharacterDataEntries.Length; ++i)
{ {
unihanCharacterDataEntries[i] = ReadUnihanCharacterDataEntry(reader); ReadUnihanCharacterDataEntry(reader, out unihanCharacterDataEntries[i]);
} }
unicodeVersion = fileUnicodeVersion; unicodeVersion = fileUnicodeVersion;
@@ -98,7 +107,7 @@ namespace System.Unicode
} }
} }
private static UnicodeCharacterData ReadUnicodeCharacterDataEntry(BinaryReader reader, byte[] nameBuffer) private static void ReadUnicodeCharacterDataEntry(BinaryReader reader, byte[] nameBuffer, out UnicodeCharacterData value)
{ {
var fields = (UcdFields)reader.ReadUInt16(); var fields = (UcdFields)reader.ReadUInt16();
@@ -153,7 +162,7 @@ namespace System.Unicode
string simpleLowerCaseMapping = (fields & UcdFields.SimpleLowerCaseMapping) != 0 ? reader.ReadString() : null; string simpleLowerCaseMapping = (fields & UcdFields.SimpleLowerCaseMapping) != 0 ? reader.ReadString() : null;
string simpleTitleCaseMapping = (fields & UcdFields.SimpleTitleCaseMapping) != 0 ? reader.ReadString() : null; string simpleTitleCaseMapping = (fields & UcdFields.SimpleTitleCaseMapping) != 0 ? reader.ReadString() : null;
ContributoryProperties contributoryProperties = (fields & UcdFields.ContributoryProperties) != 0 ? (ContributoryProperties)reader.ReadInt32() : 0; ContributoryProperties contributoryProperties = (fields & UcdFields.ContributoryProperties) != 0 ? (ContributoryProperties)reader.ReadInt32() : 0;
CoreProperties coreProperties = (fields & UcdFields.CoreProperties) != 0 ? (CoreProperties)ReadInt24(reader) : 0; int corePropertiesAndEmojiProperties = (fields & UcdFields.CorePropertiesAndEmojiProperties) != 0 ? ReadInt24(reader) : 0;
int[] crossReferences = (fields & UcdFields.CrossRerefences) != 0 ? new int[reader.ReadByte() + 1] : null; int[] crossReferences = (fields & UcdFields.CrossRerefences) != 0 ? new int[reader.ReadByte() + 1] : null;
if (crossReferences != null) if (crossReferences != null)
@@ -162,7 +171,7 @@ namespace System.Unicode
crossReferences[i] = ReadCodePoint(reader); crossReferences[i] = ReadCodePoint(reader);
} }
return new UnicodeCharacterData value = new UnicodeCharacterData
( (
codePointRange, codePointRange,
name, name,
@@ -180,12 +189,12 @@ namespace System.Unicode
simpleLowerCaseMapping, simpleLowerCaseMapping,
simpleTitleCaseMapping, simpleTitleCaseMapping,
contributoryProperties, contributoryProperties,
coreProperties, corePropertiesAndEmojiProperties,
crossReferences crossReferences
); );
} }
private static UnihanCharacterData ReadUnihanCharacterDataEntry(BinaryReader reader) private static void ReadUnihanCharacterDataEntry(BinaryReader reader, out UnihanCharacterData value)
{ {
var fields = (UnihanFields)reader.ReadUInt16(); var fields = (UnihanFields)reader.ReadUInt16();
@@ -219,7 +228,7 @@ namespace System.Unicode
string simplifiedVariant = (fields & UnihanFields.SimplifiedVariant) != 0 ? reader.ReadString() : null; string simplifiedVariant = (fields & UnihanFields.SimplifiedVariant) != 0 ? reader.ReadString() : null;
string traditionalVariant = (fields & UnihanFields.TraditionalVariant) != 0 ? reader.ReadString() : null; string traditionalVariant = (fields & UnihanFields.TraditionalVariant) != 0 ? reader.ReadString() : null;
return new UnihanCharacterData value = new UnihanCharacterData
( (
codePoint, codePoint,
numericType, numericType,
@@ -250,14 +259,9 @@ namespace System.Unicode
} }
private static UnicodeBlock ReadBlockEntry(BinaryReader reader) private static UnicodeBlock ReadBlockEntry(BinaryReader reader)
{ => new UnicodeBlock(new UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString());
return new UnicodeBlock(new UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString());
}
private static int ReadInt24(BinaryReader reader) private static int ReadInt24(BinaryReader reader) => reader.ReadByte() | ((reader.ReadByte() | (reader.ReadByte() << 8)) << 8);
{
return reader.ReadByte() | ((reader.ReadByte() | (reader.ReadByte() << 8)) << 8);
}
#if DEBUG #if DEBUG
internal static int ReadCodePoint(BinaryReader reader) internal static int ReadCodePoint(BinaryReader reader)
@@ -285,21 +289,12 @@ namespace System.Unicode
/// <summary>Gets the version of the Unicode standard supported by the class.</summary> /// <summary>Gets the version of the Unicode standard supported by the class.</summary>
public static Version UnicodeVersion { get { return unicodeVersion; } } public static Version UnicodeVersion { get { return unicodeVersion; } }
private static UnicodeCharacterData FindUnicodeCodePoint(int codePoint) private static int FindUnicodeCodePointIndex(int codePoint)
{ => codePoint <= maxContiguousIndex ?
// For the first code points (this includes all of ASCII, and quite a bit more), the index in the table will be the code point itself. codePoint : // For the first code points (this includes all of ASCII, and quite a bit more), the index in the table will be the code point itself.
if (codePoint <= maxContiguousIndex) BinarySearchUnicodeCodePointIndex(codePoint); // For other code points, we will use a classic binary search with adjusted search indexes.
{
return unicodeCharacterData[codePoint];
}
else
{
// For other code points, we will use a classic binary search with adjusted search indexes.
return BinarySearchUnicodeCodePoint(codePoint);
}
}
private static UnicodeCharacterData BinarySearchUnicodeCodePoint(int codePoint) private static int BinarySearchUnicodeCodePointIndex(int codePoint)
{ {
// NB: Due to the strictly ordered nature of the table, we know that a code point can never happen after the index which is the code point itself. // NB: Due to the strictly ordered nature of the table, we know that a code point can never happen after the index which is the code point itself.
// This will greatly reduce the range to scan for characters close to maxContiguousIndex, and will have a lesser impact on other characters. // This will greatly reduce the range to scan for characters close to maxContiguousIndex, and will have a lesser impact on other characters.
@@ -312,22 +307,22 @@ namespace System.Unicode
int Δ = unicodeCharacterData[index].CodePointRange.CompareCodePoint(codePoint); int Δ = unicodeCharacterData[index].CodePointRange.CompareCodePoint(codePoint);
if (Δ == 0) return unicodeCharacterData[index]; if (Δ == 0) return index;
else if (Δ < 0) maxIndex = index - 1; else if (Δ < 0) maxIndex = index - 1;
else minIndex = index + 1; else minIndex = index + 1;
} while (minIndex <= maxIndex); } while (minIndex <= maxIndex);
return null; return -1;
} }
private static UnihanCharacterData FindUnihanCodePoint(int codePoint) private static int FindUnihanCodePointIndex(int codePoint)
{ {
int minIndex; int minIndex;
int maxIndex; int maxIndex;
if (unihanCharacterData.Length == 0 || codePoint < unihanCharacterData[minIndex = 0].CodePoint || codePoint > unihanCharacterData[maxIndex = unihanCharacterData.Length - 1].CodePoint) if (unihanCharacterData.Length == 0 || codePoint < unihanCharacterData[minIndex = 0].CodePoint || codePoint > unihanCharacterData[maxIndex = unihanCharacterData.Length - 1].CodePoint)
{ {
return null; return -1;
} }
do do
@@ -336,12 +331,12 @@ namespace System.Unicode
int Δ = codePoint - unihanCharacterData[index].CodePoint; int Δ = codePoint - unihanCharacterData[index].CodePoint;
if (Δ == 0) return unihanCharacterData[index]; if (Δ == 0) return index;
else if (Δ < 0) maxIndex = index - 1; else if (Δ < 0) maxIndex = index - 1;
else minIndex = index + 1; else minIndex = index + 1;
} while (minIndex <= maxIndex); } while (minIndex <= maxIndex);
return null; return -1;
} }
private static int FindBlockIndex(int codePoint) private static int FindBlockIndex(int codePoint)
@@ -363,16 +358,26 @@ namespace System.Unicode
return -1; return -1;
} }
internal static ref UnicodeCharacterData GetUnicodeCharacterData(int index)
{
if (index >= 0) return ref unicodeCharacterData[index];
return ref DefaultUnicodeCharacterData;
}
internal static ref UnihanCharacterData GetUnihanCharacterData(int index)
{
if (index >= 0) return ref unihanCharacterData[index];
return ref DefaultUnihanCharacterData;
}
/// <summary>Gets the name of the Unicode block containing the character.</summary> /// <summary>Gets the name of the Unicode block containing the character.</summary>
/// <remarks>If the character has not been assigned to a block, the value of <see cref="DefaultBlock"/> will be returned.</remarks> /// <remarks>If the character has not been assigned to a block, the value of <see cref="DefaultBlock"/> will be returned.</remarks>
/// <param name="codePoint">The Unicode code point whose block should be retrieved.</param> /// <param name="codePoint">The Unicode code point whose block should be retrieved.</param>
/// <returns>The name of the block the code point was assigned to.</returns> /// <returns>The name of the block the code point was assigned to.</returns>
public static string GetBlockName(int codePoint) public static string GetBlockName(int codePoint)
{ => FindBlockIndex(codePoint) is int i && i >= 0 ?
int i = FindBlockIndex(codePoint); blocks[i].Name :
DefaultBlock;
return i >= 0 ? blocks[i].Name : DefaultBlock;
}
/// <summary>Gets Unicode information on the specified code point.</summary> /// <summary>Gets Unicode information on the specified code point.</summary>
/// <remarks> /// <remarks>
@@ -400,9 +405,7 @@ namespace System.Unicode
/// <param name="codePoint">The Unicode code point for which the data must be retrieved.</param> /// <param name="codePoint">The Unicode code point for which the data must be retrieved.</param>
/// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns> /// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns>
public static UnicodeCharInfo GetCharInfo(int codePoint) public static UnicodeCharInfo GetCharInfo(int codePoint)
{ => new UnicodeCharInfo(codePoint, FindUnicodeCodePointIndex(codePoint), FindUnihanCodePointIndex(codePoint), GetBlockName(codePoint));
return new UnicodeCharInfo(codePoint, FindUnicodeCodePoint(codePoint), FindUnihanCodePoint(codePoint), GetBlockName(codePoint));
}
/// <summary>Gets the category of the specified code point.</summary> /// <summary>Gets the category of the specified code point.</summary>
/// <remarks> /// <remarks>
@@ -412,11 +415,9 @@ namespace System.Unicode
/// <param name="codePoint">The Unicode code point for which the category must be retrieved.</param> /// <param name="codePoint">The Unicode code point for which the category must be retrieved.</param>
/// <returns>The category of the code point.</returns> /// <returns>The category of the code point.</returns>
public static UnicodeCategory GetCategory(int codePoint) public static UnicodeCategory GetCategory(int codePoint)
{ => FindUnicodeCodePointIndex(codePoint) is int unicodeCharacterDataIndex && unicodeCharacterDataIndex >= 0 ?
var charData = FindUnicodeCodePoint(codePoint); GetUnicodeCharacterData(unicodeCharacterDataIndex).Category :
UnicodeCategory.OtherNotAssigned;
return charData != null ? charData.Category : UnicodeCategory.OtherNotAssigned;
}
/// <summary>Gets a display text for the specified code point.</summary> /// <summary>Gets a display text for the specified code point.</summary>
/// <param name="charInfo">The information for the code point.</param> /// <param name="charInfo">The information for the code point.</param>
@@ -448,19 +449,16 @@ namespace System.Unicode
/// <param name="codePoint">The Unicode code point for which the name must be retrieved.</param> /// <param name="codePoint">The Unicode code point for which the name must be retrieved.</param>
/// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns> /// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns>
public static string GetName(int codePoint) public static string GetName(int codePoint)
{ => HangulInfo.IsHangul(codePoint) ?
if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint); HangulInfo.GetHangulName((char)codePoint) :
else return GetNameInternal(codePoint); GetNameInternal(codePoint);
}
private static string GetNameInternal(int codePoint) private static string GetNameInternal(int codePoint)
{ => FindUnicodeCodePointIndex(codePoint) is int codePointInfoIndex && codePointInfoIndex >= 0 ?
var codePointInfo = FindUnicodeCodePoint(codePoint); GetName(codePoint, ref GetUnicodeCharacterData(codePointInfoIndex)) :
null;
return codePointInfo != null ? GetName(codePoint, codePointInfo) : null; internal static string GetName(int codePoint, ref UnicodeCharacterData characterData)
}
internal static string GetName(int codePoint, UnicodeCharacterData characterData)
{ {
if (characterData.CodePointRange.IsSingleCodePoint) return characterData.Name; if (characterData.CodePointRange.IsSingleCodePoint) return characterData.Name;
else if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint); else if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint);
@@ -473,20 +471,15 @@ namespace System.Unicode
/// <returns>Information on the specified radical.</returns> /// <returns>Information on the specified radical.</returns>
/// <exception cref="IndexOutOfRangeException">The <paramref name="radicalIndex"/> parameter is out of range.</exception> /// <exception cref="IndexOutOfRangeException">The <paramref name="radicalIndex"/> parameter is out of range.</exception>
public static CjkRadicalInfo GetCjkRadicalInfo(int radicalIndex) public static CjkRadicalInfo GetCjkRadicalInfo(int radicalIndex)
{ => new CjkRadicalInfo(checked((byte)radicalIndex), radicals[radicalIndex - 1]);
return new CjkRadicalInfo(checked((byte)radicalIndex), radicals[radicalIndex - 1]);
}
/// <summary>Returns the number of CJK radicals in the Unicode data.</summary> /// <summary>Returns the number of CJK radicals in the Unicode data.</summary>
/// <remarks>This value will be 214 for the foreseeable future.</remarks> /// <remarks>This value will be 214 for the foreseeable future.</remarks>
public static int CjkRadicalCount { get { return radicals.Length; } } public static int CjkRadicalCount => radicals.Length;
/// <summary>Gets all the blocks defined in the Unicode data.</summary> /// <summary>Gets all the blocks defined in the Unicode data.</summary>
/// <remarks><see cref="DefaultBlock"/> is not the name of a block, but only a value indicating the abscence of block information for a given code point.</remarks> /// <remarks><see cref="DefaultBlock"/> is not the name of a block, but only a value indicating the abscence of block information for a given code point.</remarks>
/// <returns>An array containing an entry for every block defined in the Unicode data.</returns> /// <returns>An array containing an entry for every block defined in the Unicode data.</returns>
public static UnicodeBlock[] GetBlocks() public static UnicodeBlock[] GetBlocks() => (UnicodeBlock[])blocks.Clone();
{
return (UnicodeBlock[])blocks.Clone();
}
} }
} }
+2 -8
View File
@@ -1,12 +1,6 @@
using System; namespace System.Unicode
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{ {
internal sealed class UnihanCharacterData internal struct UnihanCharacterData
{ {
public readonly int CodePoint; public readonly int CodePoint;
public readonly UnihanNumericType NumericType; public readonly UnihanNumericType NumericType;