Enum.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. '_order' is of length "elms()*2" because it stores indexes sorted by name+id (2 in total per each element)
  6. /******************************************************************************/
  7. #define CC4_ENUM CC4('E','N','U','M')
  8. #define ENUM_CASE_SENSITIVE false
  9. /******************************************************************************/
  10. Cache<Enum> Enums("Enum");
  11. /******************************************************************************/
  12. Enum::Enum(C Enum &src) : Enum() {T=src;}
  13. Enum& Enum::del()
  14. {
  15. name[0]=0;
  16. Free(_order);
  17. _elms.del();
  18. return T;
  19. }
  20. /******************************************************************************/
  21. struct EnumElmPtr
  22. {
  23. C Enum::Elm *elm;
  24. UInt index;
  25. void set(C Enum::Elm &elm, UInt index) {T.elm=&elm; T.index=index;}
  26. static Int CompareName(C EnumElmPtr &ep0, C EnumElmPtr &ep1) {return Compare(ep0.elm->name, ep1.elm->name, ENUM_CASE_SENSITIVE);}
  27. static Int CompareID (C EnumElmPtr &ep0, C EnumElmPtr &ep1) {return Compare(ep0.elm->id , ep1.elm->id );}
  28. };
  29. void Enum::sort()
  30. {
  31. Mems<EnumElmPtr> elm_ptr; elm_ptr.setNum(elms().elms()); REPAO(elm_ptr).set(T[i], i);
  32. elm_ptr.sort(EnumElmPtr::CompareName); UInt *name_order=nameOrder(); REPA(T)name_order[i]=elm_ptr[i].index;
  33. elm_ptr.sort(EnumElmPtr::CompareID ); UInt * id_order= idOrder(); REPA(T) id_order[i]=elm_ptr[i].index;
  34. }
  35. Enum& Enum::create(C Str &name, C MemPtr<Elm> &elms)
  36. {
  37. del();
  38. Set(T.name, name);
  39. T._elms=elms;
  40. Alloc(_order, T.elms().elms()*2);
  41. sort();
  42. return T;
  43. }
  44. Enum& Enum::operator=(C Enum &src)
  45. {
  46. if(this!=&src)
  47. {
  48. Set(name, src.name);
  49. _elms=src._elms;
  50. CopyN(Alloc(Free(_order), elms().elms()*2), src._order, elms().elms()*2);
  51. }
  52. return T;
  53. }
  54. /******************************************************************************/
  55. Int Enum::find(CChar8 *name)C
  56. {
  57. if(Is(name))
  58. {
  59. #if 0
  60. REPA(T)if(Equal(T[i].name, name, ENUM_CASE_SENSITIVE))return i;
  61. #else
  62. UInt *name_order=nameOrder();
  63. for(Int l=0, r=elms().elms(); l<r; )
  64. {
  65. Int mid=UInt(l+r)/2,
  66. compare=Compare(name, T[name_order[mid]].name, ENUM_CASE_SENSITIVE);
  67. if(!compare )return name_order[mid];
  68. if( compare<0)r=mid;
  69. else l=mid+1;
  70. }
  71. #endif
  72. }
  73. return -1;
  74. }
  75. Int Enum::find(CChar *name)C
  76. {
  77. if(Is(name))
  78. {
  79. #if 0
  80. REPA(T)if(Equal(T[i].name, name, ENUM_CASE_SENSITIVE))return i;
  81. #else
  82. UInt *name_order=nameOrder();
  83. for(Int l=0, r=elms().elms(); l<r; )
  84. {
  85. Int mid=UInt(l+r)/2,
  86. compare=Compare(name, T[name_order[mid]].name, ENUM_CASE_SENSITIVE);
  87. if(!compare )return name_order[mid];
  88. if( compare<0)r=mid;
  89. else l=mid+1;
  90. }
  91. #endif
  92. }
  93. return -1;
  94. }
  95. Int Enum::find(C UID &id)C
  96. {
  97. if(id.valid())
  98. {
  99. UInt *id_order=idOrder();
  100. for(Int l=0, r=elms().elms(); l<r; )
  101. {
  102. Int mid=UInt(l+r)/2,
  103. compare=Compare(id, T[id_order[mid]].id);
  104. if(!compare )return id_order[mid];
  105. if( compare<0)r=mid;
  106. else l=mid+1;
  107. }
  108. }
  109. return -1;
  110. }
  111. Int Enum::findByIDUInt(UInt id)C
  112. {
  113. if(id)
  114. {
  115. UInt *id_order=idOrder();
  116. for(Int l=0, r=elms().elms(); l<r; )
  117. {
  118. Int mid=UInt(l+r)/2,
  119. compare=Compare(id, T[id_order[mid]].id.i[3]); // use 3rd UInt because UID's are sorted by most significant first
  120. if(!compare )return id_order[mid];
  121. if( compare<0)r=mid;
  122. else l=mid+1;
  123. }
  124. }
  125. return -1;
  126. }
  127. Int Enum::operator()(CChar8 *name)C {Int i=find(name); if(i<0)Exit(S+"Element \""+name +"\" not found in enum \""+Enums.name(this)+"\""); return i;}
  128. Int Enum::operator()(CChar *name)C {Int i=find(name); if(i<0)Exit(S+"Element \""+name +"\" not found in enum \""+Enums.name(this)+"\""); return i;}
  129. Int Enum::operator()(C UID &id )C {Int i=find(id ); if(i<0)Exit(S+"Element \""+id.asHex()+"\" not found in enum \""+Enums.name(this)+"\""); return i;}
  130. CChar8* Enum::elmName (Int i)C {return InRange(i, T) ? T[i].name : null ;}
  131. C UID & Enum::elmID (Int i)C {return InRange(i, T) ? T[i].id : UIDZero;}
  132. UInt Enum::elmIDUInt(Int i)C {return InRange(i, T) ? T[i].id.i[3] : 0 ;} // use 3rd UInt because UID's are sorted by most significant first
  133. /******************************************************************************/
  134. Bool Enum::save(File &f)C
  135. {
  136. f.putMulti(UInt(CC4_ENUM), Byte(3)); // version
  137. f.putStr (name);
  138. f.cmpUIntV(elms().elms()); FREPA(T){C Elm &elm=_elms[i]; f.putStr(elm.name)<<elm.id;}
  139. f.putN (_order, elms().elms()*2);
  140. return f.ok();
  141. }
  142. Bool Enum::load(File &f)
  143. {
  144. del();
  145. if(f.getUInt()==CC4_ENUM)switch(f.decUIntV()) // version
  146. {
  147. case 3:
  148. {
  149. f.getStr(name);
  150. _elms.setNum(f.decUIntV()); FREPA(T){Elm &elm=_elms[i]; f.getStr(elm.name)>>elm.id;}
  151. f.getN(Alloc(_order, elms().elms()*2), elms().elms()*2);
  152. if(f.ok())return true;
  153. }break;
  154. case 2:
  155. {
  156. f._getStr2(name);
  157. _elms.setNum(f.decUIntV()); FREPA(T){Elm &elm=_elms[i]; f._getStr2(elm.name)>>elm.id;}
  158. f.getN(Alloc(_order, elms().elms()*2), elms().elms()*2);
  159. if(f.ok())return true;
  160. }break;
  161. case 1:
  162. {
  163. Set(name, f._getStr());
  164. _elms.setNum(f.decUIntV()); FREPA(T){Elm &elm=_elms[i]; Set(elm.name, f._getStr()); f>>elm.id;}
  165. f.getN(Alloc(_order, elms().elms()*2), elms().elms()*2);
  166. if(f.ok())return true;
  167. }break;
  168. case 0:
  169. {
  170. f.getByte(); // old version byte
  171. f>>name;
  172. _elms.setNum(f.getInt()); FREPA(T){Elm &elm=_elms[i]; f>>elm.name; elm.id=MD5Mem(Str8(elm.name), Length(elm.name));}
  173. f.skip(SIZE(UInt)*elms().elms()); // skip old '_order'
  174. if(f.ok())
  175. {
  176. Alloc(_order, elms().elms()*2);
  177. sort();
  178. return true;
  179. }
  180. }break;
  181. }
  182. del(); return false;
  183. }
  184. /******************************************************************************/
  185. Bool Enum::save(C Str &name)C
  186. {
  187. File f; if(f.writeTry(name)){if(save(f) && f.flush())return true; f.del(); FDelFile(name);}
  188. return false;
  189. }
  190. Bool Enum::load(C Str &name)
  191. {
  192. File f; if(f.readTry(name))return load(f);
  193. del(); return false;
  194. }
  195. /******************************************************************************/
  196. Bool Enum::saveH(C Str &name)C
  197. {
  198. FileText f; if(f.write(name, UTF_8)) // use UTF-8 Encoding because file may get used on Mac XCode GCC which doesn't handle UTF-16 properly
  199. {
  200. f.putLine("/******************************************************************************/");
  201. f.putLine(S+"enum "+T.name);
  202. f.putLine('{').depth++;
  203. FREPA(T)f.putLine(S+T[i].name+",");
  204. f.depth--; f.putLine("};");
  205. f.putLine("/******************************************************************************/");
  206. return true;
  207. }
  208. return false;
  209. }
  210. /******************************************************************************/
  211. void Enum::operator=(C Str &name) {if(!load(name))Exit(S+"Can't load enum \""+name+"\"");}
  212. /******************************************************************************/
  213. // MAIN
  214. /******************************************************************************/
  215. void ShutEnum() {Enums.del();}
  216. /******************************************************************************/
  217. }
  218. /******************************************************************************/