New test.
[mono.git] / mcs / class / corlib / Mono.Globalization.Unicode / CodePointIndexer.cs
1 //
2 // CodePointIndexer.cs : indexing table optimizer
3 //
4 // Author:
5 //      Atsushi Enomoto  <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Globalization;
30 using System.Text;
31
32 namespace Mono.Globalization.Unicode
33 {
34         internal class CodePointIndexer
35         {
36                 public static Array CompressArray (
37                         Array source, Type type, CodePointIndexer indexer)
38                 {
39                         int totalCount = 0;
40                         for (int i = 0; i < indexer.ranges.Length; i++)
41                                 totalCount += indexer.ranges [i].Count;
42
43                         Array ret = Array.CreateInstance (type, totalCount);
44                         for (int i = 0; i < indexer.ranges.Length; i++)
45                                 Array.Copy (
46                                         source,
47                                         indexer.ranges [i].Start,
48                                         ret,
49                                         indexer.ranges [i].IndexStart,
50                                         indexer.ranges [i].Count);
51                         return ret;
52                 }
53
54                 // This class is used to compactize indexes to limited areas so that
55                 // we can save extraneous 0,0,0,0,0... in the tables.
56                 internal class TableRange
57                 {
58                         public TableRange (int start, int end, int indexStart)
59                         {
60                                 Start = start;
61                                 End = end;
62                                 Count = End - Start;
63                                 IndexStart = indexStart;
64                                 IndexEnd = IndexStart + Count;
65                         }
66
67                         public readonly int Start;
68                         public readonly int End;
69                         public readonly int Count;
70                         public readonly int IndexStart;
71                         public readonly int IndexEnd;
72                 }
73
74                 readonly TableRange [] ranges;
75
76                 public readonly int TotalCount;
77
78                 int defaultIndex;
79                 int defaultCP;
80
81                 public CodePointIndexer (int [] starts, int [] ends, int defaultIndex, int defaultCP)
82                 {
83                         this.defaultIndex = defaultIndex;
84                         this.defaultCP = defaultCP;
85                         ranges = new TableRange [starts.Length];
86                         for (int i = 0; i < ranges.Length; i++)
87                                 ranges [i] = new TableRange (starts [i],
88                                         ends [i], i == 0 ? 0 :
89                                         ranges [i - 1].IndexStart +
90                                         ranges [i - 1].Count);
91                         for (int i = 0; i < ranges.Length; i++)
92                                 TotalCount += ranges [i].Count;
93
94 //                      for (int i = 0; i < ranges.Length; i++)
95 //                              Console.Error.WriteLine ("RANGES [{0}] : {1:x} to {2:x} index {3:x} to {4:x}. total {5:x}", i, ranges [i].Start, ranges [i].End, ranges [i].IndexStart, ranges [i].IndexEnd, ranges [i].Count);
96 //                      Console.Error.WriteLine ("Total items: {0:X} ({1})", TotalCount, TotalCount);
97                 }
98
99                 public int ToIndex (int cp)
100                 {
101                         for (int t = 0; t < ranges.Length; t++) {
102                                 if (cp < ranges [t].Start)
103                                         return defaultIndex;
104                                 else if (cp < ranges [t].End)
105                                         return cp - ranges [t].Start + ranges [t].IndexStart;
106                         }
107                         return defaultIndex;
108 //                      throw new SystemException (String.Format ("Should not happen: no map definition for cp {0:x}({1})", cp, (char) cp));
109                 }
110
111                 public int ToCodePoint (int i)
112                 {
113                         for (int t = 0; t < ranges.Length; t++) {
114 /*
115                                 if (t > 0 && i < ranges [t - 1].IndexEnd)
116                                         return defaultCP; // unexpected out of range
117                                 if (ranges [t].IndexStart <= i &&
118                                         i < ranges [t].IndexEnd)
119                                         return i - ranges [t].IndexStart
120                                                 + ranges [t].Start;
121 */
122                                 if (i < ranges [t].IndexStart)
123                                         return defaultCP;
124                                 if (i < ranges [t].IndexEnd)
125                                         return i - ranges [t].IndexStart
126                                                 + ranges [t].Start;
127                         }
128                         return defaultCP;
129 //                      throw new SystemException (String.Format ("Should not happen: no map definition for index {0:x}({1})", i, i));
130                 }
131         }
132 }