00001 00002 // MathCore = a WYSIWYG equation editor + a powerful math engine // 00003 // Copyright (C) 2003 by Francesco Montorsi // 00004 // // 00005 // This library is free software; you can redistribute it and/or // 00006 // modify it under the terms of the GNU Lesser General Public // 00007 // License as published by the Free Software Foundation; either // 00008 // version 2.1 of the License, or (at your option) any later // 00009 // version. // 00010 // // 00011 // This library is distributed in the hope that it will be useful, // 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of // 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // 00014 // GNU Lesser General Public License for more details. // 00015 // // 00016 // You should have received a copy of the GNU Lesser General Public // 00017 // License along with this program; if not, write to the Free // 00018 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, // 00019 // MA 02111-1307, USA. // 00020 // // 00021 // For any comment, suggestion or feature request, please contact // 00022 // the administrator of the project at frm@users.sourceforge.net // 00023 // // 00030 00031 00032 00033 // optimization for GCC compiler 00034 #ifdef __GNUG__ 00035 #pragma implementation "MathHelpers.h" 00036 #endif 00037 00038 // includes 00039 #include "mc/mcprec.h" 00040 #ifdef __BORLANDC__ 00041 #pragma hdrstop 00042 #endif 00043 00044 #ifndef mcPRECOMP 00045 #include "mc/MathHelpers.h" 00046 #include "mc/MathCore.h" 00047 #include "mc/Element.h" 00048 #include "mc/Symbol.h" 00049 #include "mc/Range.h" 00050 #endif 00051 00052 00053 00054 00055 // init statics 00056 mcRange *mcRange::pN = NULL; 00057 mcRange *mcRange::pZ = NULL; 00058 mcRange *mcRange::pR = NULL; 00059 mcRange *mcRange::pC = NULL; 00060 mcRange *mcRange::pEmpty = NULL; 00061 00062 mcExtRange *mcExtRange::pN = NULL; 00063 mcExtRange *mcExtRange::pZ = NULL; 00064 mcExtRange *mcExtRange::pR = NULL; 00065 mcExtRange *mcExtRange::pC = NULL; 00066 mcExtRange *mcExtRange::pEmpty = NULL; 00067 00068 00069 00070 00071 00072 // ---------------------------------------- 00073 // mcABSTRACTARRAY 00074 // ---------------------------------------- 00075 00076 void mcAbstractArray::data_Add(mcAbstractItem *pointer) 00077 { 00078 m_arr.Add(pointer); 00079 data_OnArrayChange(); 00080 } 00081 00082 void mcAbstractArray::data_Insert(mcAbstractItem *pointer, int pos) 00083 { 00084 // just ask the wxArrayPtrVoid to make space for a 00085 // new pointer and store it. 00086 m_arr.Insert(pointer, pos); 00087 data_OnArrayChange(); 00088 } 00089 00090 void mcAbstractArray::data_SetItem(mcAbstractItem *pointer, int n) 00091 { 00092 data_Insert(pointer, n); // OnArrayChange is called here 00093 data_RemoveAt(n+1, 1); // OnArrayChange is called here 00094 } 00095 00096 void mcAbstractArray::data_RemoveAt(int n, int count) 00097 { 00098 // check start & end indexes 00099 if (n < 0 || n >= data_GetCount()) 00100 return; 00101 if (n+count > data_GetCount()) 00102 count = data_GetCount()-n; 00103 00104 // delete the object(s) 00105 for (int i=n; i < n+count; i++) 00106 data_Delete(i); 00107 00108 // and detach it from the array 00109 m_arr.RemoveAt(n, count); 00110 data_OnArrayChange(); 00111 } 00112 00113 void mcAbstractArray::data_Remove(const mcAbstractItem *p) 00114 { 00115 int idx = data_Find(p); 00116 if (idx == -1) return; 00117 00118 data_RemoveAt(idx); 00119 } 00120 00121 mcAbstractItem *mcAbstractArray::data_Detach(int idx) 00122 { 00123 mcAbstractItem *toret = data_GetItem(idx); 00124 00125 // use wxArrayPtrVoid::RemoveAt which just removes the _pointer_ 00126 // from the array and does not delete it... 00127 m_arr.RemoveAt(idx, 1); 00128 00129 return toret; 00130 } 00131 00132 void mcAbstractArray::data_Clear() 00133 { 00134 data_RemoveAt(0, data_GetCount()); // OnArrayChange is called here 00135 00136 // the array should already be empty: free its memory 00137 m_arr.Clear(); 00138 } 00139 00140 int mcAbstractArray::data_Find(const mcAbstractItem *pointer) const 00141 { 00142 for (int i=0; i < data_GetCount(); i++) 00143 if (data_GetItem(i) == pointer) 00144 return i; 00145 return -1; 00146 } 00147 00148 void mcAbstractArray::data_DeepCopy(const mcAbstractArray &arr) 00149 { 00150 data_Clear(); 00151 for (int i=0, max=arr.data_GetCount(); i<max; i++) 00152 data_Add(arr.data_GetCopyOf(i)); // OnArrayChange is called here 00153 } 00154 00155 #ifdef __MCDEBUG__ 00156 void mcAbstractArray::data_Check() const 00157 { 00158 mcASSERT(data_GetCount() >= 0, wxT("Invalid count index")); 00159 00160 // slow but *very* important check 00161 for (int i=0; i < data_GetCount(); i++) 00162 for (int j=0; j < data_GetCount(); j++) 00163 mcASSERT(data_GetItem(i) != data_GetItem(j) || i == j, 00164 wxT("The i-th pointer is stored twice (as i and as j) !!!")); 00165 00166 } 00167 #endif 00168 00169 00170 00171 00172 // ---------------------------------------- 00173 // mcTEXTSETTINGS 00174 // ---------------------------------------- 00175 00176 void mcTextSettings::Decode(const wxString &fnt) 00177 { 00178 long style, weight, pointsize, family; 00179 wxString todecode(fnt); // create a modifiable copy of t 00180 wxString facename; 00181 00182 // extract the font style 00183 todecode.AfterLast(wxT('-')).ToLong(&style, 0); 00184 if (style <= 0) style = wxNORMAL; 00185 00186 // extract the weight of this font 00187 todecode = todecode.BeforeLast(wxT('-')); 00188 todecode.AfterLast(wxT('-')).ToLong(&weight, 0); 00189 if (weight == 0) weight = wxNORMAL; 00190 00191 // extract point size 00192 todecode = todecode.BeforeLast(wxT('-')); 00193 todecode.AfterLast(wxT('-')).ToLong(&pointsize, 0); 00194 if (pointsize <= 0) pointsize = 16; 00195 00196 // extract face name 00197 todecode = todecode.BeforeLast(wxT('-')); 00198 facename = todecode.AfterLast(wxT('-')); 00199 00200 // extract font family 00201 todecode = todecode.BeforeLast(wxT('-')); 00202 todecode.AfterLast(wxT('-')).ToLong(&family, 0); 00203 if (family <= 0) family = wxSWISS; 00204 00205 // build the font 00206 m_hFont.SetPointSize(pointsize); 00207 m_hFont.SetWeight(weight); 00208 m_hFont.SetStyle(style); 00209 m_hFont.SetFamily(family); 00210 if (!facename.IsEmpty()) 00211 m_hFont.SetFaceName(facename); 00212 } 00213 00214 00215 00216 00217 // ---------------------------------------- 00218 // mcSTYLE 00219 // ---------------------------------------- 00220 00221 bool mcStyle::Ok() 00222 { 00223 bool res = TRUE; 00224 00225 // scan the array checking each entry 00226 for (int i=0; i < mcSTYLE_TEXTSETTINGS_NUM; i++) 00227 res &= m_pTextSettings[i].Ok(); 00228 00229 return res; 00230 } 00231 00232 int mcStyle::GetIndexFor(mcElementType t) const 00233 { 00234 switch (t) { 00235 00236 // for mcET_OPERATOR, mcET_EMPTYBOX and all the remaining... 00237 default: 00238 return 0; 00239 00240 case mcET_NUMBER: 00241 return 1; 00242 00243 case mcET_FUNCTION: 00244 return 2; 00245 00246 case mcET_TEXT: 00247 case mcET_MATHANDSYSTEM: 00248 case mcET_MATHORSYSTEM: 00249 case mcET_MATHMNG: 00250 return 3; 00251 00252 case mcET_SYMBOL: 00253 return 4; 00254 } 00255 } 00256 00257 int mcStyle::GetIndexFor(const mcElement &e) const 00258 { 00259 // a little exception for mcSymbols 00260 if (e.data_GetType() == mcET_SYMBOL) { 00261 mcSymbol p(e); 00262 if (p.hlp()->data_isGreekSymbol()) 00263 return mcSTYLE_SPECIAL_SETTINGS; 00264 } 00265 00266 return GetIndexFor(e.data_GetType()); 00267 } 00268 00269 00270 00271 00272 // ---------------------------------------- 00273 // mcSTYLEARRAY 00274 // ---------------------------------------- 00275 00276 mcStyleArray::~mcStyleArray() 00277 { 00278 if (m_pStyles) 00279 delete [] m_pStyles; 00280 m_pStyles = NULL; 00281 } 00282 00283 void mcStyleArray::CreateArray() 00284 { 00285 if (m_pStyles == NULL) 00286 m_pStyles = new mcStyle[mcELEMENTMATH_MAX_EXPDEPTH]; 00287 } 00288 00289 void mcStyleArray::DeepCopy(const mcStyleArray *p) 00290 { 00291 // copy the array 00292 for (int i=0; i < mcELEMENTMATH_MAX_EXPDEPTH; i++) 00293 m_pStyles[i].DeepCopy(&p->m_pStyles[i]); 00294 } 00295 00296 void mcStyleArray::Set(const mcStyle *arr) 00297 { 00298 // copy the given styles 00299 for (int i=0; i < mcELEMENTMATH_MAX_EXPDEPTH; i++) 00300 m_pStyles[i].DeepCopy(&arr[i]); 00301 } 00302 00303 int mcStyleArray::GetCount() 00304 { 00305 // this function cannot be placed as inline function in the declaration 00306 // of mcStyleArray because mcELEMENTMATH_MAX_EXPDEPTH is a #define which 00307 // is placed in wxT("Element.h"), which in turn includes "MathHelpers.h"... 00308 return mcELEMENTMATH_MAX_EXPDEPTH; 00309 } 00310 00311 int mcStyleArray::gui_GetStyleIndexFor(const mcElement &p) const 00312 { 00313 // style index coincides with exponent depth... 00314 /*if (p.data_GetExpDepth() > 0) { 00315 int u=432; 00316 u=3; 00317 }*/ 00318 return p.gui_GetExpDepth(); 00319 } 00320 00321 void mcStyleArray::ScaleSize(float f) 00322 { 00323 for (int i=0; i < mcELEMENTMATH_MAX_EXPDEPTH; i++) 00324 m_pStyles[i].ScaleSize(f); 00325 } 00326 00327 00328 00329 00330 // --------------- 00331 // mcMATHTYPE 00332 // --------------- 00333 00334 wxString mcMathType::io_GetDescString() const 00335 { 00336 wxString res; 00337 00338 switch (m_tMath1) { 00339 case mcMTL1_POLYNOMIAL: 00340 res += wxT("polynomial "); break; 00341 case mcMTL1_RATIONAL: 00342 res += wxT("rational "); break; 00343 case mcMTL1_NOT_RECOGNIZED: 00344 res += wxT("[not-recognized] "); break; 00345 } 00346 00347 switch (m_tMath2) { 00348 case mcMTL2_ALGEBRAIC: 00349 res += wxT("algebraic "); break; 00350 case mcMTL2_TRANSCENDENT: 00351 res += wxT("transcendental "); break; 00352 case mcMTL2_NOT_RECOGNIZED: 00353 res += wxT("[not-recognized] "); break; 00354 } 00355 00356 switch (m_tMath3) { 00357 case mcMTL3_CONSTANT: 00358 res += wxT("constant"); break; 00359 case mcMTL3_UNKNOWN: 00360 res += wxT("unknown"); break; 00361 case mcMTL3_PARAMETRIC: 00362 res += wxT("parametric"); break; 00363 case mcMTL3_NOT_RECOGNIZED: 00364 res += wxT("[not-recognized]"); break; 00365 } 00366 00367 // do not check for the mcMTL4_NOTRECOGNIZED flag 00368 if (m_tMath4 & mcMTL4_LOGARITHMIC) 00369 res += wxT("logarithmic"); 00370 if (m_tMath4 & mcMTL4_EXPONENTIAL) 00371 res += wxT("exponential"); 00372 if (m_tMath4 & mcMTL4_TRIGONOMETRIC) 00373 res += wxT("trigonometric"); 00374 00375 // last check 00376 if (res.IsEmpty()) 00377 res = wxT("[invalid data]"); 00378 00379 return res; 00380 } 00381 00382 mcMathType mcMathType::math_MultiplyBy(const mcMathType &t) 00383 { 00384 // the result is exactly the same... 00385 return math_Add(t); 00386 } 00387 00388 mcMathType mcMathType::math_DivideBy(const mcMathType &t) 00389 { 00390 math_MultiplyBy(t); 00391 00392 // TOTEST 00393 if (t.m_tMath3 != mcMTL3_CONSTANT) 00394 m_tMath1 = mcMTL1_RATIONAL; 00395 00396 return *this; 00397 } 00398 00399 mcMathType mcMathType::math_Add(const mcMathType &t) 00400 { 00401 m_tMath1 = mcMIN(m_tMath1, t.m_tMath1); 00402 m_tMath2 = mcMIN(m_tMath2, t.m_tMath2); 00403 m_tMath3 = mcMIN(m_tMath3, t.m_tMath3); 00404 00405 m_tMath4 = m_tMath4 | t.m_tMath4; 00406 00407 /* if (m_tMath1 == mcMTL1_POLYNOMIAL && t.m_tMath1 == mcMTL1_POLYNOMIAL) 00408 m_tMath1 = mcMTL1_POLYNOMIAL; 00409 else 00410 m_tMath1 = mcMTL1_RATIONAL; 00411 00412 if (m_tMath2 == mcMTL2_ALGEBRAIC && t.m_tMath2 == mcMTL2_ALGEBRAIC) 00413 m_tMath2 = mcMTL2_ALGEBRAIC; 00414 else 00415 m_tMath2 = mcMTL2_TRANSCENDENT; 00416 00417 if (m_tMath3 == mcMTL3_PARAMETRIC || 00418 t.m_tMath3 == mcMTL3_PARAMETRIC) 00419 m_tMath3 = mcMTL3_PARAMETRIC; 00420 else if (m_tMath3 == mcMTL3_UNKNOWN || 00421 t.m_tMath3 == mcMTL3_UNKNOWN) 00422 m_tMath3 = mcMTL3_UNKNOWN; 00423 else 00424 m_tMath3 = mcMTL3_CONSTANT;*/ 00425 00426 return *this; 00427 } 00428 00429 mcMathType mcMathType::math_RaiseTo(const mcMathType &t) 00430 { 00431 math_MultiplyBy(t); 00432 00433 // TOTEST: it is trascendent only if 't' is not constant 00434 if (t.m_tMath3 != mcMTL3_CONSTANT) { 00435 m_tMath2 = mcMTL2_TRANSCENDENT; 00436 m_tMath4 = mcMTL4_EXPONENTIAL; 00437 } 00438 00439 return *this; 00440 } 00441 00442 mcMathType mcMathType::math_ApplyOp(mcElementType optype, const mcMathType &t) 00443 { 00444 if (optype == mcET_ADDOP || optype == mcET_SUBOP) 00445 math_Add(t); 00446 else if (optype == mcET_MULTOP) 00447 math_MultiplyBy(t); 00448 else if (optype == mcET_DIVOP) 00449 math_DivideBy(t); 00450 00451 return *this; 00452 } 00453 00454 00455 00456 // ---------------------------------------- 00457 // mcMATHSYSTEMTYPE 00458 // ---------------------------------------- 00459 00460 wxString mcMathSystemType::io_GetDescString(int nequ) const 00461 { 00462 wxString type; 00463 00464 switch (m_tMath1) { 00465 case mcMSTL1_NOT_RECOGNIZED: 00466 type = wxT("not recognized"); break; 00467 case mcMSTL1_EQUATIONS: 00468 type = wxString::Format(wxT(" %d-equations system"), nequ); break; 00469 case mcMSTL1_INEQUALITIES: 00470 type = wxString::Format(wxT(" %d-inequalities system"), nequ); break; 00471 case mcMSTL1_EXPRESSION: 00472 type += wxT(" expression"); break; 00473 case mcMSTL1_MIXED: 00474 type = wxT(" mixed system"); break; 00475 } 00476 00477 return type; 00478 } 00479 00480 mcMathSystemType mcMathSystemType::math_CombineWith(const mcMathSystemType &t) 00481 { 00482 // if one of the two is unrecognized, then 00483 // also the global system is unrecognized... 00484 if (m_tMath1 == mcMSTL1_NOT_RECOGNIZED || 00485 t.m_tMath1 == mcMSTL1_NOT_RECOGNIZED) { 00486 00487 m_tMath1 = mcMSTL1_NOT_RECOGNIZED; 00488 return *this; 00489 } 00490 00491 if (m_tMath1 != t.m_tMath1) 00492 m_tMath1 = mcMSTL1_MIXED; 00493 00494 return *this; 00495 } 00496 00497 00498 00499 00500 // ---------------------------------------- 00501 // mcRANGE 00502 // ---------------------------------------- 00503 00504 mcRange::~mcRange() // cannot be placed in the header 00505 { 00506 } 00507 00508 void mcRange::math_Set(const mcRealValue &l, const mcRealValue &u) 00509 { 00510 if (!u.isNAN()) { 00511 //mcSAFE_DELETE(m_pUpper); 00512 //m_pUpper = mcNewPolynomial(); 00513 //m_pUpper.math_ 00514 m_pUpper.math_WrapNumber(u); 00515 } 00516 if (!l.isNAN()) { 00517 //mcSAFE_DELETE(m_pLower); 00518 //m_pLower = mcNewPolynomial(); 00519 m_pLower.math_WrapNumber(l); 00520 } 00521 } 00522 00523 void mcRange::math_Set(const mcPolynomial &l, const mcPolynomial &u) 00524 { 00525 if (u != mcEmptyElement) m_pUpper = u; 00526 if (l != mcEmptyElement) m_pLower = l; 00527 } 00528 00529 bool mcRange::math_isFinite() const 00530 { 00531 return m_pUpper.math_isFinite() & 00532 m_pLower.math_isFinite(); 00533 } 00534 00535 mcRealValue mcRange::math_GetLowerLimitValue() const 00536 { return m_pLower.math_Evaluate(); } 00537 00538 mcRealValue mcRange::math_GetUpperLimitValue() const 00539 { return m_pUpper.math_Evaluate(); } 00540 00541 00542 00543 #define mcBM_INCLUDE_LCHAR wxT("[") 00544 #define mcBM_INCLUDE_RCHAR wxT("]") 00545 00546 #define mcBM_EXCLUDE_LCHAR wxT("(") 00547 #define mcBM_EXCLUDE_RCHAR wxT(")") 00548 00549 00550 wxString mcRange::io_GetInlinedExpr() const 00551 { 00552 wxString middle = m_pLower.io_GetInlinedExpr() + wxT(";") + 00553 m_pUpper.io_GetInlinedExpr(); 00554 00555 switch (m_nBounds) { 00556 case mcBM_INCLUDE_BOTH: 00557 return mcBM_INCLUDE_LCHAR + middle + mcBM_INCLUDE_RCHAR; 00558 case mcBM_INCLUDE_LEFT: 00559 return mcBM_INCLUDE_LCHAR + middle + mcBM_EXCLUDE_RCHAR; 00560 case mcBM_INCLUDE_RIGHT: 00561 return mcBM_EXCLUDE_LCHAR + middle + mcBM_INCLUDE_RCHAR; 00562 case mcBM_INCLUDE_NONE: 00563 return mcBM_EXCLUDE_LCHAR + middle + mcBM_EXCLUDE_RCHAR; 00564 } 00565 00566 // just to avoid warnings 00567 return wxEmptyString; 00568 } 00569 00570 00571 00572 00573 // ---------------------------------------- 00574 // mcEXTRANGE 00575 // ---------------------------------------- 00576 00577 bool mcExtRange::math_isFinite() const 00578 { 00579 bool finite = TRUE; 00580 for (int i=0; i < data_GetCount(); i++) 00581 finite &= data_GetRange(i)->math_isFinite(); 00582 return finite; 00583 } 00584 00585 00586 00587 00588 // ---------------------------------------- 00589 // mcSYMBOLPROPERTIES 00590 // ---------------------------------------- 00591 00592 mcSymbolProperties::mcSymbolProperties(int symtype, 00593 const wxString &name, 00594 wxFontEncoding encoding, 00595 const mcRealValue &value, 00596 const wxString &inlinedsym, 00597 const wxString &subscript, 00598 mcExtRange *domain, 00599 bool evaluating) 00600 { 00601 m_nSymbolType = symtype; 00602 m_fEncoding = encoding; 00603 00604 m_fValue = value; 00605 m_pDomain = NULL; 00606 00607 // FIXME: 00608 //if (domain) 00609 //m_pDomain = domain->data_Clone(); 00610 00611 m_strSubscript = subscript; 00612 m_strInlinedSymbol = inlinedsym; 00613 m_strSymbol = name; 00614 00615 m_bEvaluating = evaluating; 00616 00617 // create at least a mcSymbol class linked with us. 00618 mcSymbolHelpers *safe = new mcSymbolHelpers; 00619 safe->data_LinkWith(this); 00620 } 00621 00622 mcSymbolProperties::~mcSymbolProperties() 00623 { 00624 // this symbol is being deleted; if we have instances of 00625 // mcSymbolData which are linked with us, then we must 00626 // unlink them... 00627 for (int i=0,max=(int)m_arrLinkedSymbol.GetCount(); i < max; i++) { 00628 00629 mcSymbolHelpers *p = (mcSymbolHelpers *)m_arrLinkedSymbol.Item(0); 00630 00631 // mcSymbol will automatically call our Unlink() function 00632 //if (p) 00633 mcASSERT(p != NULL, wxT("We are linked with a NULL symbol ??")); 00634 p->data_Unlink(); 00635 00636 if (i == 0) { 00637 00638 // the first symbol linked with us is a special symbol 00639 // created during mcSymbolProperties construction and 00640 // we are the owner of it, so we must take care of its 00641 // deletion 00642 delete p; 00643 } 00644 } 00645 } 00646 00647 bool mcSymbolProperties::data_isSameAs(const mcSymbolProperties &s) const 00648 { 00649 // case #1: the two symbols have the same name & encoding & subscript 00650 if (s.m_strSymbol == m_strSymbol && 00651 s.m_fEncoding == m_fEncoding && 00652 s.m_strSubscript == m_strSubscript) 00653 return TRUE; 00654 00655 // case #2: the two symbols have the same inlined expression & subscript 00656 if (s.io_GetInlinedSym() == io_GetInlinedSym() && 00657 s.m_strSubscript == m_strSubscript) 00658 return TRUE; 00659 00660 // if the two symbols are different, then these check should be harmless 00661 00662 return FALSE; 00663 } 00664 00665 int mcSymbolProperties::math_FindDuplicate(const mcSymbolArray *arr, int occ) const 00666 { 00667 int occurrence = 0; 00668 int n = arr->data_FindSymbol(mcSYMFIND_MATCH_NAME, *this, occurrence); 00669 00670 while (n != mcSYM_NOTFOUND) { 00671 00672 const mcSymbolProperties *found = arr->data_GetSymbol(n); 00673 00674 // ok; we have found a symbol with the same name of *this; 00675 // now check if it satisfies the isSameAs function... 00676 if (this != found && this->data_isSameAs(*found)) { 00677 00678 // ok, this is the occurrence of the duplicate symbol we were 00679 // searching for the array 00680 if (occ == 0) 00681 return n; 00682 occ--; // wait for the next one... 00683 } 00684 00685 // this symbol has our same name but it's not a duplicate... 00686 occurrence++; // search next 00687 n = arr->data_FindSymbol(mcSYMFIND_MATCH_NAME, *this, occurrence); 00688 } 00689 00690 return mcSYM_NOTFOUND; 00691 } 00692 00693 00694 00695 00696 // ---------------------------------------- 00697 // mcSYMBOLARRAY 00698 // ---------------------------------------- 00699 00700 int mcSymbolArray::data_FindSymbol(long flags, const wxString &name, 00701 wxFontEncoding enc, const mcRealValue &value, 00702 const wxString &subscript, const wxString &inlined, 00703 int occurrence) const 00704 { 00705 // this should always be synchronized perfectly with mcSymbolProperties 00706 // constructor 00707 mcSymbolProperties tmp(mcSYM_NOTSET, name, enc, value, inlined, subscript); 00708 00709 return data_FindSymbol(flags, tmp, occurrence); 00710 } 00711 00712 int mcSymbolArray::data_FindSymbol(long flags, const mcSymbolProperties &sym, int occ) const 00713 { 00714 // search in this array 00715 for (int i=0; i < data_GetCount(); i++) { 00716 00717 bool match = TRUE; 00718 00719 // if all required conditions are met... 00720 if (flags & mcSYMFIND_MATCH_NAME) match &= (data_GetSymbolName(i) == sym.m_strSymbol); 00721 if (flags & mcSYMFIND_MATCH_ENCODING) match &= (data_GetEncoding(i) == sym.m_fEncoding); 00722 if (flags & mcSYMFIND_MATCH_VALUE) match &= (math_GetValue(i) == sym.m_fValue); 00723 if (flags & mcSYMFIND_MATCH_INLINED) match &= (io_GetInlinedSymbol(i) == sym.io_GetInlinedSym()); 00724 if (flags & mcSYMFIND_MATCH_SUBSCRIPT) match &= (data_GetSubscript(i) == sym.m_strSubscript); 00725 00726 if (match) { 00727 if (occ == 0) 00728 return i; // ...then, return what we found 00729 00730 // this is not the occurrence we're searching... 00731 occ--; 00732 } 00733 } 00734 00735 // we didn't find it 00736 return mcSYM_NOTFOUND; 00737 } 00738 00739 mcSymbolProperties *mcSymbolArray::data_AddSymbol(bool bRemovePrevious, 00740 const wxString &name, 00741 wxFontEncoding enc, 00742 const mcRealValue &value, 00743 const wxString &inlinedsym, 00744 const wxString &sub, 00745 mcExtRange *domain) 00746 { 00747 mcSymbolProperties sym(m_nSymbolArray, name, enc, value, inlinedsym, sub, domain); 00748 00749 // if we cannot add this symbol return NULL 00750 if (!data_AddSymbol(sym, bRemovePrevious)) 00751 return NULL; 00752 00753 // the new symbol is always appended in the last position... 00754 return data_GetSymbol(data_GetCount()-1); 00755 } 00756 00757 bool mcSymbolArray::data_AddSymbol(const mcSymbolProperties &newsym, bool bRemovePrevious) 00758 { 00759 bool bpresent = FALSE; 00760 int i, n; 00761 00762 // FIXME: the newsym.Clone() operation *must* be done before the 00763 // math_FindDuplicate function is called, because in this case that 00764 // function would miss to intercept itself (since it considers 00765 // a duplicate what is different from itself) as duplicate, 00766 // even if registered in another array (it cannot know it's 00767 // going to be added in *this). 00768 // 00769 // FIXME: data_MoveSymbols is forced to make a clone copy to work... 00770 00771 // before adding the given object, check if another symbol 00772 // with the same name is already present... 00773 for (i=0; i < mcMAX_SYMBOL_ARRAY_NUM; i++) { 00774 if (m_pArr[i] == NULL) continue; 00775 00776 n = newsym.math_FindDuplicate(m_pArr[i], 0); 00777 if (n != mcSYM_NOTFOUND) bpresent = TRUE; 00778 } 00779 00780 if (bpresent && !bRemovePrevious) 00781 return FALSE; // we cannot proceed 00782 00783 // add the symbol even if we know there is a duplicate of this one 00784 // somewhere in the linked arrays... 00785 mcSymbolProperties *added = newsym.data_Clone(); 00786 added->m_nSymbolType = m_nSymbolArray; 00787 mcAbstractArray::data_Add(added); 00788 00789 // 'added' is now hold by m_arrSym (who did not make a copy for internal 00790 // storage (and this is very important for the following code): 00791 // 00792 // GetSymbol(GetCount()-1) == added 00793 00794 // if no duplicates are present, we have finished... 00795 if (!bpresent) { 00796 00797 // don't forget to call the callback 00798 if (m_pAddSymbolCallback) 00799 (*m_pAddSymbolCallback)(); 00800 return TRUE; 00801 } 00802 00803 // ok; we have created a duplicate of the symbol; we must remove 00804 // the old one (redirecting all mcSymbols using that mcSymbolProperties 00805 // on the just added symbol). 00806 for (i=0; i < mcMAX_SYMBOL_ARRAY_NUM; i++) { 00807 if (m_pArr[i] == NULL) continue; 00808 00809 // search the first duplicate (but we hope only one duplicate is present !) 00810 n = newsym.math_FindDuplicate(m_pArr[i], 0); 00811 00812 // this is a valid link... 00813 if (n != mcSYM_NOTFOUND) { 00814 00815 mcSymbolProperties *torem = (mcSymbolProperties *)m_pArr[i]->data_GetSymbol(n); 00816 if (torem == added) { 00817 n = newsym.math_FindDuplicate(m_pArr[i], 1); 00818 if (n == mcSYM_NOTFOUND) continue; 00819 } 00820 00821 mcASSERT(torem != added, wxT("math_FindDuplicate is broken")); 00822 00823 // this mcSymbolProperties class must be deleted; 00824 // change the pointers of all mcSymbolHelpers classes 00825 // that are using that symbol... 00826 00827 // in this FOR loop it's important to get always the 00828 // 1st linked symbol because each Unlink() call will 00829 // remove the symbol wxT('toupdate') from 'torem.m_arrLinkedSymbol' 00830 00831 // another note: we start from the 1st unlinked symbol 00832 // and not from the 0th unlinked symbol because the first 00833 // mcSymbolHelpers linked with the mcSymbolProperties to remove, 00834 // is its safe symbol class (for more info see mcSymbolProperties) 00835 int j, max; 00836 for (j=1,max=torem->data_GetLinkedSymCount(); j < max; j++) { 00837 00838 // unlink the symbol from the old mcSymbolProperties 00839 // object (which is going to be removed) 00840 mcSymbolHelpers *toupdate = torem->data_GetLinkedSym(1); 00841 toupdate->data_Unlink(); 00842 00843 // and link it with the new one 00844 // (we cannot use torem.GetLinkedSym() because we 00845 // just unlinked the wxT('toupdate') symbol from 'torem' !!!) 00846 toupdate->data_LinkWith(added); 00847 } 00848 00849 mcASSERT(max >= 1, wxT("The symbol to remove did not have a safe instance ") 00850 wxT("of a mcSymbolHelpers class ?")); 00851 00852 // ok; we can now delete the old mcSymbolProperties. 00853 m_pArr[i]->data_RemoveAt(n); 00854 } 00855 } 00856 00857 // array integrity should have been preserved 00858 if (m_pAddSymbolCallback) (*m_pAddSymbolCallback)(); 00859 return TRUE; 00860 } 00861 00862 mcSymbolProperties *mcSymbolArray::data_MoveSymbols(int i, mcSymbolArray *parr) 00863 { 00864 // VERY IMPORTANT: here we *must* clone the symbol to move: we cannot 00865 // use it directly because ?!? FIXME 00866 mcSymbolProperties *p = data_GetSymbol(i)->data_Clone(); 00867 bool okay = parr->data_AddSymbol(*p, TRUE); 00868 mcSAFE_DELETE(p); // don't leak memory 00869 00870 // using math_AddSymbol, the just moved symbol is the last one of the array 00871 if (!okay) return NULL; 00872 return parr->data_GetSymbol(parr->data_GetCount()-1); 00873 } 00874 00875 00876 00877 00878 00879 00880 00881 // ---------------------------------------- 00882 // mcCURSORPOS 00883 // ---------------------------------------- 00884 00885 void mcCursorPos::gui_Pop() 00886 { 00887 for (int i=0; i<m_nUsed-1; i++) 00888 m_nPos[i] = m_nPos[i+1]; 00889 if (!isSpecial(m_nPos[m_nUsed-1])) { 00890 m_nPos[m_nUsed-1] = m_nPos[m_nUsed]; 00891 m_nUsed--; 00892 } 00893 } 00894 00895 void mcCursorPos::gui_Push(const mcCursorPos &c) 00896 { 00897 /*for (int i=m_nUsed; i>0; i--) 00898 m_nPos[i+c.m_nUsed] = m_nPos[i]; 00899 for (int j=0; j<c.m_nUsed; j++) 00900 m_nPos[j] = c.m_nPos[j]; 00901 m_nUsed+=c.m_nUsed;*/ 00902 }
[ Top ] |