Partition.C 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: Partition.C /main/1 1996/07/29 17:01:30 cde-hp $ */
  24. // Copyright (c) 1994 James Clark
  25. // See the file COPYING for copying permission.
  26. #ifdef __GNUG__
  27. #pragma implementation
  28. #endif
  29. #include "splib.h"
  30. #include "Partition.h"
  31. #include "ISet.h"
  32. #include "ISetIter.h"
  33. #include "SubstTable.h"
  34. #include "Link.h"
  35. #include "IList.h"
  36. #include "IListIter.h"
  37. #include "Owner.h"
  38. #include "macros.h"
  39. #include "EquivClass.h"
  40. #include "constant.h"
  41. #include "StringC.h"
  42. #ifdef SP_NAMESPACE
  43. namespace SP_NAMESPACE {
  44. #endif
  45. static void refineByChar(IList<EquivClass> *, Char);
  46. static void refineBySet(IList<EquivClass> *, const ISet<Char> &, unsigned);
  47. #if _MSC_VER == 900
  48. // Work around MSVC 2.0 bug.
  49. typedef SubstTable<Char> _msvc_dummy;
  50. #endif
  51. Partition::Partition(const ISet<Char> &chars,
  52. const ISet<Char> **sets,
  53. int nSets,
  54. const SubstTable<Char> &subst)
  55. : map_(0) // eE gets code 0
  56. {
  57. IList<EquivClass> classes;
  58. classes.insert(new EquivClass);
  59. classes.head()->set.addRange(0, charMax);
  60. {
  61. ISetIter<Char> iter(chars);
  62. Char min, max;
  63. while (iter.next(min, max)) {
  64. do {
  65. refineByChar(&classes, subst[min]);
  66. } while (min++ != max);
  67. }
  68. }
  69. int i;
  70. for (i = 0; i < nSets; i++)
  71. refineBySet(&classes, *sets[i], (1 << i));
  72. maxCode_ = 0;
  73. setCodes_.resize(nSets);
  74. for (IListIter<EquivClass> listIter(classes);
  75. !listIter.done();
  76. listIter.next()) {
  77. ++maxCode_;
  78. ASSERT(maxCode_ != 0);
  79. EquivClass *p = listIter.cur();
  80. for (i = 0; i < nSets; i++)
  81. if ((1 << i) & p->inSets)
  82. setCodes_[i] += maxCode_;
  83. ISetIter<Char> setIter(p->set);
  84. Char min, max;
  85. while (setIter.next(min, max))
  86. map_.setRange(min, max, maxCode_);
  87. }
  88. {
  89. ISetIter<Char> iter(chars);
  90. Char min, max;
  91. while (iter.next(min, max)) {
  92. do {
  93. StringC str(subst.inverse(min));
  94. EquivCode code = map_[min];
  95. for (size_t i = 0; i < str.size(); i++)
  96. map_.setChar(str[i], code);
  97. } while (min++ != max);
  98. }
  99. }
  100. }
  101. static
  102. void refineByChar(IList<EquivClass> *classes, Char c)
  103. {
  104. // Avoid modifying *classes, while there's an active iter on it.
  105. EquivClass *found = 0;
  106. {
  107. for (IListIter<EquivClass> iter(*classes); !iter.done(); iter.next()) {
  108. if (iter.cur()->set.contains(c)) {
  109. found = iter.cur();
  110. break;
  111. }
  112. }
  113. }
  114. if (found && !found->set.isSingleton()) {
  115. found->set.remove(c);
  116. classes->insert(new EquivClass(found->inSets));
  117. classes->head()->set.add(c);
  118. }
  119. }
  120. static
  121. void addUpTo(ISet<Char> *to, Char limit, const ISet<Char> &from)
  122. {
  123. ISetIter<Char> iter(from);
  124. Char min, max;
  125. while (iter.next(min, max) && min < limit)
  126. to->addRange(min, max >= limit ? limit - 1 : max);
  127. }
  128. enum RefineResult { allIn, allOut, someInSomeOut };
  129. static
  130. RefineResult refine(const ISet<Char> &set, const ISet<Char> &refiner,
  131. ISet<Char> *inp, ISet<Char> *outp)
  132. {
  133. Char setMin, setMax, refMin, refMax;
  134. ISetIter<Char> refIter(refiner);
  135. ISetIter<Char> setIter(set);
  136. Boolean oneIn = 0;
  137. Boolean oneOut = 0;
  138. if (!refIter.next(refMin, refMax))
  139. return allOut;
  140. while (setIter.next(setMin, setMax)) {
  141. while (setMin <= setMax) {
  142. while (refMax < setMin && refIter.next(refMin, refMax))
  143. ;
  144. if (refMax < setMin || setMin < refMin) {
  145. if (!oneOut) {
  146. if (oneIn)
  147. addUpTo(inp, setMin, set);
  148. oneOut = 1;
  149. }
  150. if (refMax < setMin || refMin > setMax) {
  151. if (oneIn)
  152. outp->addRange(setMin, setMax);
  153. break;
  154. }
  155. else {
  156. if (oneIn)
  157. outp->addRange(setMin, refMin - 1);
  158. setMin = refMin;
  159. }
  160. }
  161. else {
  162. if (!oneIn) {
  163. if (oneOut)
  164. addUpTo(outp, setMin, set);
  165. oneIn = 1;
  166. }
  167. if (setMax <= refMax) {
  168. if (oneOut)
  169. inp->addRange(setMin, setMax);
  170. break;
  171. }
  172. else {
  173. // refMax < setMax
  174. if (oneOut)
  175. inp->addRange(setMin, refMax);
  176. // avoid wrapping round
  177. if (refMax == charMax)
  178. break;
  179. setMin = refMax + 1;
  180. }
  181. }
  182. }
  183. }
  184. if (oneIn)
  185. return oneOut ? someInSomeOut : allIn;
  186. else
  187. return allOut;
  188. }
  189. static
  190. void refineBySet(IList<EquivClass> *classes, const ISet<Char> &set,
  191. unsigned setFlag)
  192. {
  193. Owner<EquivClass> in(new EquivClass), out(new EquivClass);
  194. IList<EquivClass> newClasses;
  195. for (;;) {
  196. EquivClass *p = classes->head();
  197. if (!p)
  198. break;
  199. if (!out)
  200. out = new EquivClass;
  201. switch (refine(p->set, set, &in->set, &out->set)) {
  202. case someInSomeOut:
  203. in->inSets = p->inSets | setFlag;
  204. newClasses.insert(in.extract());
  205. out->inSets = p->inSets;
  206. newClasses.insert(out.extract());
  207. in = classes->get();
  208. in->set.clear();
  209. in->inSets = 0;
  210. break;
  211. case allIn:
  212. p->inSets |= setFlag;
  213. newClasses.insert(classes->get());
  214. break;
  215. case allOut:
  216. newClasses.insert(classes->get());
  217. break;
  218. }
  219. }
  220. classes->swap(newClasses);
  221. }
  222. #ifdef SP_NAMESPACE
  223. }
  224. #endif