Files
NetUnicodeInfo/UnicodeInformation/UnicodeDataBuilder.cs
T
GoldenCrystal 190597d317 Exported some of the data consolidation logic to a separate builder.
Improved enumerations by including a special ValueName attribute on the fields.
2014-11-02 21:56:24 +01:00

134 lines
3.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnicodeInformation
{
public class UnicodeDataBuilder
{
private readonly Version unicodeVersion;
private UnicodeCharacterDataBuilder[] characterDataBuilders = new UnicodeCharacterDataBuilder[10000];
private int characterCount;
public UnicodeDataBuilder(Version unicodeVersion)
{
this.unicodeVersion = unicodeVersion;
}
private int FindCodePoint(int codePoint)
{
if (characterCount == 0) return -1;
int minIndex = 0;
int maxIndex = characterCount - 1;
do
{
int index = (minIndex + maxIndex) >> 1;
int Δ = characterDataBuilders[index].CodePointRange.CompareCodePoint(codePoint);
if (Δ == 0) return index;
else if (Δ < 0) maxIndex = index - 1;
else minIndex = index + 1;
} while (minIndex <= maxIndex);
return -1;
}
private int FindInsertionPoint(int startCodePoint, int endCodePoint)
{
int minIndex;
int maxIndex;
if (characterCount == 0 || characterDataBuilders[maxIndex = characterCount - 1].CodePointRange.LastCodePoint < startCodePoint) return characterCount;
else if (endCodePoint < characterDataBuilders[minIndex = 0].CodePointRange.FirstCodePoint) return 0;
else if (characterCount == 1) return -1;
do
{
int index = (minIndex + maxIndex) >> 1;
int Δ = characterDataBuilders[index].CodePointRange.CompareCodePoint(startCodePoint);
if (Δ == 0) return -1;
else if (Δ < 0) maxIndex = index;
else minIndex = index;
} while (maxIndex - minIndex > 1);
if (characterDataBuilders[maxIndex].CodePointRange.FirstCodePoint < endCodePoint) return -1;
else return maxIndex;
}
public void Insert(UnicodeCharacterDataBuilder data)
{
int insertionPoint = FindInsertionPoint(data.CodePointRange.FirstCodePoint, data.CodePointRange.LastCodePoint);
if (insertionPoint < 0) throw new InvalidOperationException("The specified range overlaps with pre-existing ranges.");
if (insertionPoint >= characterDataBuilders.Length)
{
Array.Resize(ref characterDataBuilders, characterDataBuilders.Length << 1);
}
if (insertionPoint < characterCount)
{
Array.Copy(characterDataBuilders, insertionPoint, characterDataBuilders, insertionPoint + 1, characterCount - insertionPoint);
}
characterDataBuilders[insertionPoint] = data;
++characterCount;
}
public UnicodeCharacterDataBuilder Get(int codePoint)
{
int index = FindCodePoint(codePoint);
return index >= 0 ? characterDataBuilders[index] : null;
}
public void SetProperties(ContributoryProperties property, UnicodeCharacterRange codePointRange)
{
int firstIndex = FindCodePoint(codePointRange.FirstCodePoint);
int lastIndex = FindCodePoint(codePointRange.LastCodePoint);
if (firstIndex < 0 && lastIndex < 0)
{
Insert(new UnicodeCharacterDataBuilder(codePointRange) { ContributoryProperties = property });
return;
}
if (firstIndex < 0
|| lastIndex < 0
|| characterDataBuilders[firstIndex].CodePointRange.FirstCodePoint < codePointRange.FirstCodePoint
|| characterDataBuilders[lastIndex].CodePointRange.LastCodePoint > codePointRange.LastCodePoint)
{
throw new InvalidOperationException();
}
int i = firstIndex;
while (true)
{
characterDataBuilders[i].ContributoryProperties |= property;
if (i == lastIndex) break;
++i;
}
}
public UnicodeData ToUnicodeData()
{
var finalData = new UnicodeCharacterData[characterCount];
for (int i = 0; i < finalData.Length; ++i)
finalData[i] = characterDataBuilders[i].ToCharacterData();
return new UnicodeData(unicodeVersion, finalData);
}
}
}