Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

337 lines
8.1 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1998
  6. //
  7. // File: model.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. //
  11. // MODEL.CPP
  12. //
  13. #include <basetsd.h>
  14. #include <string.h>
  15. #include "basics.h"
  16. #include "algos.h"
  17. #include "gmprop.h"
  18. #include "model.h"
  19. #include "gmobj.h"
  20. struct EC_STR
  21. {
  22. ECGM _ec;
  23. SZC _szc;
  24. };
  25. static EC_STR vEcToStr [] =
  26. {
  27. #define GMERRORSTR
  28. #include "errordef.h"
  29. { EC_OK, "no error" }
  30. };
  31. SZC MODEL :: SzcFromEc ( ECGM ec )
  32. {
  33. int cEc = UBOUND(vEcToStr);
  34. for ( int i = 0; i < cEc; i++ )
  35. {
  36. if ( ec == vEcToStr[i]._ec )
  37. return vEcToStr[i]._szc;
  38. }
  39. return NULL;
  40. }
  41. // Iterator class for MODELs
  42. MODEL::ITER::ITER(MODEL& model, GOBJMBN::EBNOBJ eType)
  43. : _eType(eType),
  44. _model(model)
  45. {
  46. Reset();
  47. }
  48. MODEL::ITER::ITER(MODEL& model) : _model(model)
  49. {
  50. }
  51. void MODEL::ITER::CreateNodeIterator()
  52. {
  53. _eType = GOBJMBN::EBNO_NODE;
  54. Reset();
  55. }
  56. void MODEL::ITER :: Reset ()
  57. {
  58. _pCurrent = NULL;
  59. _itsym = _model.Mpsymtbl().begin();
  60. BNext();
  61. }
  62. bool MODEL::ITER :: BNext ()
  63. {
  64. while ( _itsym != _model.Mpsymtbl().end() )
  65. {
  66. _pCurrent = (*_itsym).second.Pobj();
  67. _zsrCurrent = (*_itsym).first;
  68. _itsym++;
  69. if ( _pCurrent->EType() == _eType )
  70. return true;
  71. }
  72. _pCurrent = NULL;
  73. return false;
  74. }
  75. ///////////////////////////////////////////////////////////////////////////
  76. // MODEL naming commentary.
  77. //
  78. // Symbolic names in a belief network come in two types: names which users
  79. // can enter (or edit into a DSC file) and those which they cannot.
  80. //
  81. // The basic (user-definable) symbolic name follows exactly the rules of
  82. // standard 'C', except that periods ('.') are allowed inside a name.
  83. //
  84. // There is a need for generation of names which are clearly distinguishable
  85. // from user-definable names; these are called "internal" names. The only
  86. // difference is that the legal character set is extended to include the '$'
  87. // (dollar sign) character as an alphabetic character (i.e., it can be the
  88. // first character in a name).
  89. //
  90. ///////////////////////////////////////////////////////////////////////////
  91. // Return true if the character is legal in a name
  92. bool MODEL :: BChLegal ( char ch, ECHNAME echnm, bool bInternal )
  93. {
  94. bool bOther = bInternal && ch == ChInternal();
  95. bool bOkForC = echnm == ECHNM_First
  96. ? __iscsymf(ch)
  97. : __iscsym(ch) || (echnm == ECHNM_Middle && ch == '.');
  98. return bOther || bOkForC;
  99. }
  100. // Return true if the name is legal
  101. bool MODEL :: BSzLegal ( SZC szcName, bool bInternal )
  102. {
  103. for ( int i = 0; szcName[i]; i++ )
  104. {
  105. ECHNAME echnm = i == 0
  106. ? ECHNM_First
  107. : (szcName[i+1] ? ECHNM_Middle : ECHNM_Last);
  108. if ( ! BChLegal( szcName[i], echnm, bInternal ) )
  109. return false;
  110. }
  111. return true;
  112. }
  113. MODEL :: MODEL ()
  114. : _pgrph(NULL),
  115. _rVersion(-1.0)
  116. {
  117. // Allocate the GRPH graph object
  118. SetPgraph(new GRPH);
  119. assert( _pgrph );
  120. //
  121. // Define the table of known (early-defined) bit flags in this scope
  122. //
  123. #define MBN_GEN_BFLAGS_TABLE szcBitFlagNames
  124. // Include the header to generate the strings
  125. #include "mbnflags.h"
  126. // Define the table of known bit flags.
  127. for ( int i = 0; szcBitFlagNames[i]; i++ )
  128. {
  129. // Note: this automatically interns the names into the symbol table
  130. IBFLAG ibf = Mpsymtbl().IAddBitFlag( szcBitFlagNames[i] );
  131. }
  132. }
  133. MODEL :: ~ MODEL ()
  134. {
  135. // We must clear the graph and symbol table at this point, because their
  136. // elements interreference via the names (ZSREFs) and pointers (REFPOBJs).
  137. // The symbol table is cleared first, so that no stray references to GOBJMBNs
  138. // exist when the graph object is nuked. Then the graph is cleared, so
  139. // that embedded references to strings interned in the symbol table's string
  140. // table will be removed.
  141. Mpsymtbl().clear();
  142. // Delete the graph
  143. SetPgraph(NULL);
  144. }
  145. void MODEL :: SetPgraph ( GRPH * pgrph )
  146. {
  147. delete _pgrph;
  148. _pgrph = pgrph;
  149. }
  150. // Add an unnamed element to the graph
  151. void MODEL :: AddElem ( GELEMLNK * pgelm )
  152. {
  153. ASSERT_THROW( pgelm, EC_NULLP, "null ptr passed to MODEL::AddElem()" );
  154. Pgraph()->AddElem( *pgelm );
  155. }
  156. // Test the name for duplicate; add if not, otherwise return false
  157. bool MODEL :: BAddElem ( SZC szcName, GOBJMBN * pgobj )
  158. {
  159. if ( ::strlen( szcName ) == 0 )
  160. return false; // Name missing
  161. if ( Mpsymtbl().find( szcName ) )
  162. return false; // duplicate name
  163. AddElem( szcName, pgobj );
  164. return true;
  165. }
  166. // Add a (possibly) named object to the graph and symbol table
  167. void MODEL :: AddElem ( SZC szcName, GOBJMBN * pgelm )
  168. {
  169. if ( szcName != NULL && ::strlen(szcName) != 0 )
  170. {
  171. if ( Mpsymtbl().find( szcName ) )
  172. throw GMException( EC_DUPLICATE_NAME, "attempt to add duplicate name to MBNET" );
  173. Mpsymtbl().add( szcName, pgelm );
  174. }
  175. AddElem( pgelm );
  176. }
  177. void MODEL :: DeleteElem ( GOBJMBN * pgobj )
  178. {
  179. if ( pgobj->ZsrefName().Zstr().length() > 0 )
  180. Mpsymtbl().remove( pgobj->ZsrefName() );
  181. else
  182. DeleteElem( (GELEMLNK *) pgobj );
  183. }
  184. void MODEL :: DeleteElem ( GELEMLNK * pgelem )
  185. {
  186. delete pgelem;
  187. }
  188. void MODEL :: Clone ( MODEL & model )
  189. {
  190. ASSERT_THROW( _pgrph->ChnColl().PgelemNext() == NULL,
  191. EC_INVALID_CLONE,
  192. "cannot clone into non-empty structure" );
  193. // Clone the descriptive information
  194. _rVersion = model._rVersion;
  195. _zsFormat = model._zsFormat;
  196. _zsCreator = model._zsCreator;
  197. _zsNetworkID = model._zsNetworkID;
  198. // Clone the symbol table
  199. _mpsymtbl.Clone( model._mpsymtbl );
  200. // Copy the network bit flags array
  201. _vFlags = model._vFlags;
  202. //
  203. // Clone the actual contents of the network, object by object
  204. //
  205. {
  206. // Create a map to correlate old object pointers to new object pointers
  207. typedef map<GOBJMBN *, GOBJMBN *, less<GOBJMBN *> > MPPOBJPOBJ;
  208. MPPOBJPOBJ mppobjpobj;
  209. // Add the property types first, then all the node-like things
  210. GELEMLNK * pgelm;
  211. MODELENUM mdlenumNode( model );
  212. for ( int icycle = 0; icycle < 2; icycle++ )
  213. {
  214. mdlenumNode.Reset(model.Grph());
  215. while ( pgelm = mdlenumNode.PlnkelNext() )
  216. {
  217. // Check that it's a node (not an edge)
  218. if ( ! pgelm->BIsEType( GELEM::EGELM_NODE ) )
  219. continue;
  220. GOBJMBN * pgobjmbn;
  221. GOBJMBN * pgobjmbnNew = NULL;
  222. DynCastThrow( pgelm, pgobjmbn );
  223. // Clone property types on the first pass, all other nodeish things
  224. // on the second.
  225. if ( (icycle == 0) ^ (pgelm->EType() == GOBJMBN::EBNO_PROP_TYPE) )
  226. continue;
  227. pgobjmbnNew = pgobjmbn->CloneNew( model, self );
  228. // If the object was cloned or allowed itself to be cloned,
  229. // add it
  230. if ( pgobjmbnNew )
  231. {
  232. assert( pgobjmbnNew->EType() == pgobjmbn->EType() );
  233. mppobjpobj[ pgobjmbn ] = pgobjmbnNew;
  234. // Add the object as named or unnamed
  235. AddElem( pgobjmbnNew->ZsrefName(), pgobjmbnNew );
  236. }
  237. }
  238. }
  239. // Add all the edge-like things
  240. MODELENUM mdlenumEdge( model );
  241. while ( pgelm = mdlenumEdge.PlnkelNext() )
  242. {
  243. // Check that it's a edge (not a node)
  244. if ( ! pgelm->BIsEType( GELEM::EGELM_EDGE ) )
  245. continue;
  246. GEDGEMBN * pgedge;
  247. DynCastThrow( pgelm, pgedge );
  248. GOBJMBN * pgobjmbnSource = pgedge->PobjSource();
  249. GOBJMBN * pgobjmbnSink = pgedge->PobjSink();
  250. assert( pgobjmbnSource && pgobjmbnSink );
  251. GOBJMBN * pgobjmbnSourceNew = mppobjpobj[ pgobjmbnSource ];
  252. GOBJMBN * pgobjmbnSinkNew = mppobjpobj[ pgobjmbnSink ];
  253. assert( pgobjmbnSourceNew && pgobjmbnSinkNew );
  254. GEDGEMBN * pgedgeNew = pgedge->CloneNew( model,
  255. self,
  256. pgobjmbnSourceNew,
  257. pgobjmbnSinkNew );
  258. assert( pgedgeNew );
  259. AddElem( pgedgeNew );
  260. }
  261. }
  262. // Clone the network property list
  263. _ltProp.Clone( self, model, model._ltProp );
  264. }
  265. GOBJMBN * MODEL :: PgobjFind ( SZC szcName )
  266. {
  267. return Mpsymtbl().find(szcName);
  268. }
  269. void MPSYMTBL :: Clone ( const MPSYMTBL & mpsymtbl )
  270. {
  271. // Clone all the interned strings
  272. _stszstr.Clone( mpsymtbl._stszstr );
  273. // Clone the array of bit flag names
  274. CloneVzsref( mpsymtbl, mpsymtbl._mpzsrbit, _mpzsrbit );
  275. // All other symbol entries must be created from above
  276. }
  277. void MPSYMTBL :: CloneVzsref (
  278. const MPSYMTBL & mpsymtbl,
  279. const VZSREF & vzsrSource,
  280. VZSREF & vzsrTarget )
  281. {
  282. vzsrTarget.resize( vzsrSource.size() );
  283. for ( int i = 0; i < vzsrTarget.size(); i++ )
  284. {
  285. SZC szc = vzsrSource[i].Szc();
  286. vzsrTarget[i] = intern(szc);
  287. }
  288. }