Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:41

0001 #pragma once
0002 
0003 /**
0004 SName.h  : formerly CSG/CSGName.h
0005 =====================================
0006 
0007 Identity machinery based around a referenced vector of string names.
0008 Canonical usage is with the meshnames.txt, aka the lv solid names.
0009 
0010 An important user of this is::
0011 
0012     SGeoConfig::ELVSelection
0013 
0014 **/
0015 
0016 #include <cstring>
0017 #include <vector>
0018 #include <string>
0019 #include <sstream>
0020 #include <iostream>
0021 #include <iomanip>
0022 #include <fstream>
0023 #include <algorithm>
0024 
0025 #include "spath.h"
0026 #include "sstr.h"
0027 
0028 
0029 enum { SName_EXACT, SName_START, SName_CONTAIN } ;
0030 
0031 struct SName
0032 {
0033     static constexpr const bool VERBOSE = false ;
0034     static constexpr const char* EXACT = "EXACT" ;
0035     static constexpr const char* START = "START" ;
0036     static constexpr const char* CONTAIN = "CONTAIN" ;
0037 
0038     //static constexpr const char* STARTING_ = "STARTING_" ;
0039     static constexpr const char* STARTING_ = "^" ;
0040     static bool Has_STARTING(const char* str);
0041     static bool Has_STARTING(const std::vector<std::string>& qq);
0042 
0043     static unsigned QType(char qt);
0044     static const char* QLabel(unsigned qtype);
0045     static const char* QTypeLabel(char qt);
0046     static bool Match( const char* n, const char* q, unsigned qtype );
0047 
0048     static SName* Load(const char* path);
0049     static constexpr const char* GEOMLoadPath = "$CFBaseFromGEOM/CSGFoundry/meshname.txt" ;
0050     static SName* GEOMLoad();
0051 
0052     static constexpr const char* parseArg_ALL = "ALL" ;
0053     static const bool dump = false ;
0054     static int ParseIntString(const char* arg, int fallback=-1);
0055     static void ParseSOPR(int& solidIdx, int& primIdxRel, const char* sopr );
0056 
0057 
0058     const std::vector<std::string>& name ;
0059 
0060     SName(const std::vector<std::string>& name );
0061 
0062     std::string desc() const ;
0063     std::string detail() const ;
0064 
0065     unsigned getNumName() const;
0066     const char* getName(unsigned idx) const ;
0067     const char* getAbbr(unsigned idx) const ;
0068 
0069 
0070     int findIndexWithName(const char* qname, bool startswith) const ;
0071 
0072     int getIndex( const char* name    , unsigned& count) const ;
0073     int findIndex(const char* q, unsigned& count, int max_count=-1, bool starting=false, std::ostream* out=nullptr ) const ;
0074     int findIndex(const char* q, bool starting, std::ostream* out  ) const ;
0075 
0076     void findIndicesStarting(std::vector<unsigned>& idxs, const char* name_start ) const ;
0077     void findIndicesFromNames(std::vector<unsigned>& idxs, const std::vector<std::string>& qq, std::vector<std::string>* qq_missing, std::ostream* out ) const ;
0078 
0079     static void SortUnique( std::vector<unsigned>& v );
0080 
0081 
0082     bool hasName(  const char* q, bool starting, std::ostream* out=nullptr ) const ;
0083     bool hasNames( const char* qq, char delim=',', const char* prefix=nullptr,  std::vector<std::string>* qq_missing=nullptr, std::ostream* out=nullptr ) const ;
0084     bool hasNames( const std::vector<std::string>& qq, std::vector<std::string>* qq_missing=nullptr,  std::ostream* out=nullptr ) const ;
0085 
0086 
0087     void findIndicesMatch(std::vector<unsigned>& idxs, const char* query, char qt='S' ) const ;
0088     std::string descIndices(const std::vector<unsigned>& idxs) const ;
0089 
0090 
0091     const char* getIDXListFromNames( const char* qq,  char delim=','   , const char* prefix=nullptr, std::vector<std::string>* qq_missing=nullptr, std::ostream* out=nullptr ) const ;
0092     const char* getIDXListFromNames( const std::vector<std::string>& qq, const char* prefix=nullptr, std::vector<std::string>* qq_missing=nullptr, std::ostream* out=nullptr ) const ;
0093     const char* getIDXListFromContaining( const char* names_containing="_virtual0x", const char* prefix=nullptr ) const;
0094     static const char* IDXList(const std::vector<unsigned>& idxs, const char* prefix=nullptr );
0095 
0096 
0097     int parseArg(const char* arg, unsigned& count ) const ;
0098     void parseMOI(int& midx, int& mord, int& iidx, const char* moi) const ;
0099 
0100 };
0101 
0102 
0103 inline bool SName::Has_STARTING(const char* str)
0104 {
0105     if(!str) return false ;
0106     if(!STARTING_) return false ;
0107     bool one = strlen(STARTING_) == 1 ;
0108     return one ? str[0] == STARTING_[0] :  ( nullptr != strstr( str, STARTING_ )) ;
0109 }
0110 inline bool SName::Has_STARTING(const std::vector<std::string>& qq)
0111 {
0112     int count = 0 ;
0113     for(size_t i=0 ; i < qq.size() ; i++ ) if(Has_STARTING(qq[i].c_str())) count += 1 ;
0114     return count > 0 ;
0115 }
0116 
0117 
0118 inline SName* SName::Load(const char* path_)
0119 {
0120     const char* path = spath::Resolve(path_);
0121     if(path == nullptr)
0122     {
0123         std::cerr
0124             << "SName::Load FAILED to Resolve["
0125             << ( path_ ? path_ : "-" )
0126             << std::endl
0127             ;
0128         return nullptr ;
0129     }
0130 
0131     typedef std::vector<std::string> VS ;
0132     VS* names = new VS ;
0133 
0134     std::ifstream ifs(path);
0135     std::string line;
0136     while(std::getline(ifs, line)) names->push_back(line) ;
0137 
0138     SName* id = new SName(*names) ;
0139     return id ;
0140 }
0141 
0142 inline SName* SName::GEOMLoad(){ return Load(GEOMLoadPath); }
0143 
0144 
0145 inline SName::SName( const std::vector<std::string>& name_ )
0146     :
0147     name(name_)
0148 {
0149 }
0150 
0151 inline std::string SName::desc() const
0152 {
0153     unsigned num_name = getNumName() ;
0154     std::stringstream ss ;
0155     ss << "SName::desc numName " << num_name ;  ;
0156     if( num_name > 0 ) ss << " name[0] " << getName(0) << " name[-1] " <<  getName(num_name-1 ) ;
0157     std::string s = ss.str();
0158     return s ;
0159 }
0160 
0161 inline std::string SName::detail() const
0162 {
0163     unsigned num_name = getNumName() ;
0164     std::stringstream ss ;
0165     ss << "SName::detail num_name " << num_name << std::endl ;
0166     for(unsigned i=0 ; i < num_name ; i++) ss << getName(i) << std::endl ;
0167     std::string s = ss.str();
0168     return s ;
0169 }
0170 
0171 
0172 inline unsigned SName::getNumName() const
0173 {
0174     return name.size();
0175 }
0176 inline const char* SName::getName(unsigned idx) const
0177 {
0178     return idx < name.size() ? name[idx].c_str() : nullptr ;
0179 }
0180 
0181 /**
0182 SName::getAbbr
0183 ------------------
0184 
0185 Return the shortest string that still yields the same index
0186 
0187 **/
0188 
0189 inline const char* SName::getAbbr(unsigned idx) const
0190 {
0191     const char* name = getName(idx);
0192 
0193     unsigned count = 0 ;
0194     int idx0 = getIndex(name, count) ;
0195 
0196     if( idx0 != int(idx) )  return nullptr ;  // happens for 2nd of duplicated
0197     // count is 2 for the first of duplicated
0198 
0199     char* sname = strdup(name);
0200     int nj = int(strlen(sname));
0201 
0202     if( idx == 0 )
0203     {
0204         std::cout
0205            << " idx " << idx
0206            << " idx0 " << idx0
0207            << " count " << count
0208            << " name " << name
0209            << " sname " << sname
0210            << " nj " << nj
0211            << std::endl
0212            ;
0213     }
0214 
0215 
0216     unsigned max_count = 2 ;  // strict, but permit duplicated
0217     for(int j=0 ; j < nj ; j++)
0218     {
0219         sname[nj-1-j] = '\0' ;   // progressive trimming from the right
0220         count = 0 ;
0221         int idx1 = findIndex(sname, count, max_count );
0222 
0223         if( idx == 0 )
0224            std::cout
0225                << " j " << j
0226                << " sname " << sname
0227                << " idx1 " << idx1
0228                << std::endl
0229                ;
0230 
0231 
0232         if(idx1 != int(idx) )
0233         {
0234             sname[nj-1-j] = name[nj-1-j] ; // repair the string
0235             break ;
0236         }
0237     }
0238     return sname ;
0239 }
0240 
0241 
0242 
0243 /**
0244 SName::findIndexWithName
0245 --------------------------
0246 
0247 Method to assist with fulfilment of SGeo::getIndexWithName
0248 
0249 **/
0250 
0251 inline int SName::findIndexWithName(const char* qname, bool startswith) const
0252 {
0253     unsigned count = 0 ;
0254     int max_count = -1 ;
0255     return startswith ? findIndex(qname, count, max_count) : getIndex( qname, count ) ;
0256 }
0257 
0258 
0259 /**
0260 SName::getIndex
0261 --------------------
0262 
0263 Returns the index of the first listed name that exactly matches the query string.
0264 A count of the number of matches is also provided.
0265 Returns -1 if not found.
0266 
0267 NB NP::get_name_index does the same as this, it can be simpler to use that
0268 method when an array is being updated
0269 
0270 **/
0271 
0272 inline int SName::getIndex(const char* query, unsigned& count) const
0273 {
0274     int result(-1);
0275     count = 0 ;
0276     for(unsigned i=0 ; i < name.size() ; i++)
0277     {
0278         const char* k = name[i].c_str() ;
0279         if(strcmp(k, query) == 0 )
0280         {
0281             if(count == 0) result = i ;
0282             count += 1 ;
0283         }
0284     }
0285     return result ;
0286 }
0287 
0288 
0289 /**
0290 SName::findIndex
0291 --------------------
0292 
0293 Returns the index of the first listed name that starts with the query string.
0294 A count of the number of matches is also provided.
0295 
0296 Start strings are used to allow names with pointer suffixes such as
0297 the below to be found without including the pointer suffix in the query string::
0298 
0299    HamamatsuR12860sMask_virtual0x5f50520
0300    HamamatsuR12860sMask_virtual0x
0301 
0302 It is recommended to make the point by using query strings ending in 0x
0303 
0304 When max_count argument > -1  is provided, eg max_count=1
0305 the number of occurences of the match is required to be less than
0306 or equal to *max_count*.
0307 
0308 Returns -1 if not found.
0309 
0310 This is used from CSGFoundry::findMeshIndex and results in -1 for
0311 names with common prefixes::
0312 
0313     CSGFoundry::descELV elv.num_bits 139 num_include 139 num_exclude 0
0314     INCLUDE:139
0315 
0316     p:  0:midx:  0:mn:sTopRock_domeAir
0317     p:  1:midx: -1:mn:sTopRock_dome
0318     p:  2:midx:  2:mn:sDomeRockBox
0319     p:  3:midx:  3:mn:PoolCoversub
0320     p:  4:midx:  4:mn:Upper_LS_tube
0321     p:  5:midx:  5:mn:Upper_Steel_tube
0322     p:  6:midx:  6:mn:Upper_Tyvek_tube
0323     p:  7:midx:  7:mn:Upper_Chimney
0324     p:  8:midx: -1:mn:sBar
0325     p:  9:midx: -1:mn:sBar
0326     p: 10:midx: 10:mn:sPanelTape
0327     p: 11:midx: -1:mn:sPanel
0328     p: 12:midx: 12:mn:sPlane
0329 
0330 
0331 **/
0332 
0333 inline int SName::findIndex(const char* q, unsigned& count, int max_count, bool starting, std::ostream* out ) const
0334 {
0335     int result(-1);
0336     count = 0 ;
0337     for(unsigned i=0 ; i < name.size() ; i++)
0338     {
0339         const char* k = name[i].c_str() ;
0340         if( sstr::Match( k, q, starting ))
0341         {
0342             if(count == 0) result = i ;
0343             count += 1 ;
0344         }
0345     }
0346     bool count_ok = max_count == -1 || count <= unsigned(max_count) ;
0347     int idx = count_ok ? result : -1 ;
0348 
0349     if(out && idx < 0) *out
0350          << "[SName::findIndex.0"
0351          << " q [" << ( q ? q : "-" ) << "]"
0352          << " count_ok " << ( count_ok ? "YES" : "NO " )
0353          << " count " << count
0354          << " max_count " << max_count
0355          << " result " << result
0356          << " idx " << idx
0357          << "]\n"
0358          ;
0359 
0360     return idx ;
0361 
0362 }
0363 
0364 inline void SName::findIndicesStarting(std::vector<unsigned>& idxs, const char* name_start ) const
0365 {
0366     bool starting = true ;
0367     for(unsigned i=0 ; i < name.size() ; i++)
0368     {
0369         const char* k = name[i].c_str() ;
0370         if( sstr::Match( k, name_start, starting ))
0371         {
0372             idxs.push_back(i) ;
0373         }
0374     }
0375 }
0376 
0377 
0378 
0379 inline int SName::findIndex(const char* q, bool starting, std::ostream* out ) const
0380 {
0381     unsigned count = 0 ;
0382     int max_count = -1 ;
0383     int idx = findIndex(q, count, max_count, starting, out );
0384     if(out && idx < 0) *out << "[SName::findIndex.1"
0385       << " q [" << ( q ? q : "-" )
0386       << " count " << count
0387       << " max_count " << max_count
0388       << " idx " << idx
0389       << "]\n"
0390       ;
0391 
0392     return idx ;
0393 }
0394 
0395 /**
0396 SName::findIndicesFromNames
0397 ----------------------------
0398 
0399 As SGeoConfig::GeometrySpecificSetup/SName::hasNames uses SName::findIndicesFromNames
0400 to identify an unknown geometry via the presence of names this must not require
0401 the names to be found, as they will often not be there.
0402 
0403 **/
0404 
0405 inline void SName::findIndicesFromNames(std::vector<unsigned>& idxs, const std::vector<std::string>& qq, std::vector<std::string>* qq_missing, std::ostream* out ) const
0406 {
0407     unsigned nqq = qq.size();
0408 
0409     if(out) *out
0410         << "[SName::findIndicesFromNames"
0411         << " qq.size " << nqq
0412         << "\n"
0413         ;
0414 
0415     if(VERBOSE) for(unsigned i=0 ; i < nqq ; i++ ) std::cerr << qq[i] << std::endl ;
0416 
0417     bool with_STARTING = false ;
0418 
0419     for(unsigned i=0 ; i < nqq ; i++)
0420     {
0421         const char* q = qq[i].c_str();
0422         bool q_starting = 0 == strncmp(q, STARTING_, strlen(STARTING_) );
0423 
0424         if( q_starting == false )
0425         {
0426             int idx = findIndex(q, false, out ) ;
0427             bool found = idx > -1 ;
0428             if(found)
0429             {
0430                 idxs.push_back(idx) ;
0431             }
0432             else
0433             {
0434                 if(qq_missing) qq_missing->push_back(q);
0435             }
0436         }
0437         else
0438         {
0439             const char* q_unprefixed = q + strlen(STARTING_);
0440             findIndicesStarting(idxs, q_unprefixed );
0441             with_STARTING = true ;
0442         }
0443     }
0444 
0445     if(with_STARTING)
0446     {
0447         SortUnique(idxs);
0448     }
0449 
0450 
0451     if(out) *out
0452         << "]SName::findIndicesFromNames"
0453         << " qq.size " << nqq
0454         << "\n"
0455         ;
0456 
0457 
0458 
0459 }
0460 
0461 
0462 
0463 inline void SName::SortUnique( std::vector<unsigned>& v )
0464 {
0465     std::sort(v.begin(), v.end());
0466     auto last = std::unique(v.begin(), v.end()); // Move duplicates to the end (O(N))
0467     v.erase(last, v.end()); // Remove the extra elements
0468 }
0469 
0470 
0471 inline bool SName::hasName(  const char* q, bool starting, std::ostream* out ) const
0472 {
0473     int idx = findIndex(q, starting, out );
0474     bool has = idx > -1 ;
0475     return has ;
0476 }
0477 
0478 
0479 
0480 inline bool SName::hasNames( const char* qq_, char delim, const char* prefix, std::vector<std::string>* qq_missing, std::ostream* out ) const
0481 {
0482     const char* uqq = qq_ + ( prefix ? strlen(prefix) : 0 ) ;
0483     if(out) *out
0484         << "SName::hasNames.qq.d.p "
0485         << " prefix " << ( prefix ? prefix : "-" )
0486         << " qq_ [" << ( qq_ ? qq_ : "-" ) << "]\n"
0487         << " uqq [" << ( uqq ? uqq : "-" ) << "]\n"
0488         ;
0489 
0490     std::vector<std::string> qq;
0491     sstr::SplitTrimSuppress( uqq, delim, qq );   // handles filepath: ELV
0492     return hasNames(qq, qq_missing, out );
0493 }
0494 
0495 
0496 inline bool SName::hasNames( const std::vector<std::string>& qq, std::vector<std::string>* qq_missing, std::ostream* out) const
0497 {
0498     std::vector<unsigned> idxs ;
0499     findIndicesFromNames(idxs, qq, qq_missing, out );
0500     bool has_all = qq.size() == idxs.size() ;
0501     if(out) *out
0502         << "SName::hasNames.qq "
0503         << " qq.size " << qq.size()
0504         << " idxs.size " << idxs.size()
0505         << " qq_missing " << ( qq_missing ? "YES" : "NO" )
0506         << " qq_missing.size " << ( qq_missing ? qq_missing->size() : -1 )
0507         << " has_all " << has_all
0508         << std::endl
0509         ;
0510     return has_all ;
0511 }
0512 
0513 
0514 
0515 
0516 
0517 
0518 
0519 inline const char* SName::QLabel(unsigned qtype)  // static
0520 {
0521     const char* s = nullptr ;
0522     switch(qtype)
0523     {
0524        case SName_EXACT :   s = EXACT ; break ;
0525        case SName_START :   s = START ; break ;
0526        case SName_CONTAIN : s = CONTAIN ; break ;
0527     }
0528     return s ;
0529 }
0530 
0531 inline unsigned SName::QType(char qt)  // static
0532 {
0533     unsigned qtype = SName_EXACT ;
0534     switch(qt)
0535     {
0536         case 'E': qtype = SName_EXACT   ; break ;
0537         case 'S': qtype = SName_START   ; break ;
0538         case 'C': qtype = SName_CONTAIN ; break ;
0539     }
0540     return qtype ;
0541 }
0542 inline const char* SName::QTypeLabel(char qt) // static
0543 {
0544     unsigned qtype = QType(qt);
0545     return QLabel(qtype);
0546 }
0547 
0548 
0549 inline bool SName::Match( const char* n, const char* q, unsigned qtype ) // static
0550 {
0551     bool match = false ;
0552     switch( qtype )
0553     {
0554         case SName_EXACT:   match = strcmp(n,q) == 0       ; break ;  // n exactly matches q string
0555         case SName_START:   match = sstr::MatchStart(n,q)  ; break ;  // n starts with q string
0556         case SName_CONTAIN: match = sstr::Contains(n,q)    ; break ;  // n contains the q string
0557     }
0558     return match ;
0559 }
0560 
0561 inline void SName::findIndicesMatch(std::vector<unsigned>& idxs, const char* q, char qt ) const
0562 {
0563     unsigned qtype = QType(qt);
0564     for(unsigned i=0 ; i < name.size() ; i++)
0565     {
0566         const char* n = name[i].c_str() ;
0567         if(Match(n,q,qtype)) idxs.push_back(i) ;
0568     }
0569 }
0570 
0571 /**
0572 SName::getIDXListFromNames
0573 ---------------------------
0574 
0575 Returns a comma delimited string list of indices prefixed with the input prefix when provided.
0576 
0577 **/
0578 
0579 inline const char* SName::getIDXListFromNames( const char* names_, char delim, const char* prefix, std::vector<std::string>* qq_missing, std::ostream* out ) const
0580 {
0581     const char* unames = prefix == nullptr ?  names_ : names_ + strlen(prefix ) ;
0582     std::vector<std::string> names ;
0583     sstr::SplitTrimSuppress(unames, delim, names);  // handles unames with newlines
0584 
0585 
0586     return getIDXListFromNames( names, prefix, qq_missing, out );
0587 }
0588 
0589 /**
0590 SName::getIDXListFromNames
0591 ----------------------------
0592 
0593 Ordinarily when the *qq* strings do not contain the STARTING_ token eg "^"
0594 then an assert insists all names must be found.
0595 However when a pointer to a vector of missing names is provided *qq_missing*
0596 this requirement is lifted.
0597 **/
0598 
0599 
0600 inline const char* SName::getIDXListFromNames( const std::vector<std::string>& qq, const char* prefix, std::vector<std::string>* qq_missing, std::ostream* out ) const
0601 {
0602     bool require_all_names = !Has_STARTING(qq) && qq_missing == nullptr ;
0603 
0604     std::vector<unsigned> idxs ;
0605     findIndicesFromNames(idxs, qq, qq_missing, out );
0606 
0607     if(require_all_names)
0608     {
0609         bool found_all_names =  qq.size() == idxs.size() ;
0610         if(!found_all_names) std::cerr
0611             << "SName::getIDXListFromNames !found_all_names "
0612             << " qq.size " << qq.size()
0613             << " idxs.size " << idxs.size()
0614             << " require_all_names " << ( require_all_names ? "YES" : "NO " )
0615             << std::endl
0616             ;
0617         assert( found_all_names );
0618     }
0619 
0620     return IDXList(idxs, prefix);
0621 }
0622 inline const char* SName::getIDXListFromContaining( const char* names_containing, const char* prefix) const
0623 {
0624     std::vector<unsigned> idxs ;
0625     findIndicesMatch(idxs, names_containing, 'C' );
0626     return IDXList(idxs, prefix);
0627 }
0628 inline const char* SName::IDXList(const std::vector<unsigned>& idxs, const char* prefix ) // static
0629 {
0630     unsigned num_idx = idxs.size() ;
0631     std::stringstream ss ;
0632     if(prefix) ss << prefix ;
0633     for(unsigned i=0 ; i < num_idx ; i++) ss << idxs[i] <<  ( i < num_idx - 1 ? "," : "" ) ;
0634     std::string s = ss.str();
0635     return strdup(s.c_str());
0636 }
0637 
0638 
0639 inline std::string SName::descIndices(const std::vector<unsigned>& idxs) const
0640 {
0641     std::stringstream ss ;
0642     for(unsigned i=0 ; i < idxs.size() ; i++)
0643     {
0644         unsigned idx = idxs[i] ;
0645         ss << std::setw(4) << idx << " : " << name[idx] << std::endl ;
0646     }
0647     std::string s = ss.str();
0648     return s ;
0649 }
0650 
0651 /**
0652 SName::parseArg
0653 -------------------
0654 
0655 An arg of "ALL" is special cased yielding -1 otherwise parsing the string
0656 as an integer is attempted. If the entire string does not parse as an integer
0657 or it matches the fallback "-1" then look for the string in the list of names.
0658 If a name starting with the arg is found the 0-based index is returned,
0659 otherwise -1 is returned.
0660 
0661 **/
0662 
0663 
0664 inline int SName::parseArg(const char* arg, unsigned& count) const
0665 {
0666     count = 0 ;
0667 
0668     int fallback = -1 ;
0669     int idx = fallback ;
0670 
0671     bool is_all = strcmp( arg, parseArg_ALL) == 0 ? true : false ;
0672     if(is_all)
0673     {
0674         count = 1 ;
0675     }
0676     else
0677     {
0678         idx = ParseIntString(arg, fallback ) ;
0679         if(idx == fallback)
0680         {
0681             int max_count = -1 ;
0682             bool starting = true ;
0683             idx = findIndex(arg, count, max_count, starting );   // index of 1st listed name starting with arg
0684         }
0685         else
0686         {
0687             count = 1 ;
0688         }
0689     }
0690 
0691     /*
0692     if(dump || idx == fallback) std::cout
0693         << "SName::parseArg"
0694         << " arg " << arg
0695         << " idx " << idx
0696         << " count " << count
0697         << " is_all " << is_all
0698         << std::endl
0699         ;
0700     */
0701 
0702     return idx ;
0703 }
0704 
0705 /**
0706 SName::ParseIntString
0707 -------------------------
0708 
0709 If the entire arg can be parsed as an integer that is returned,
0710 otherwise the fallback integer is returned.
0711 
0712 **/
0713 
0714 inline int SName::ParseIntString(const char* arg, int fallback)  // static
0715 {
0716     char* end ;
0717     char** endptr = &end ;
0718     int base = 10 ;
0719     unsigned long int uli = strtoul(arg, endptr, base);
0720     bool end_points_to_terminator = end == arg + strlen(arg) ;
0721     int result = int(uli) ;
0722     int ret = end_points_to_terminator ? result : fallback ;
0723 
0724     if(dump) std::cout
0725          << " arg [" << arg << "] "
0726          << " uli " << uli
0727          << " end_points_to_terminator " << end_points_to_terminator
0728          << " result " << result
0729          << " ret " << ret
0730          << std::endl
0731          ;
0732 
0733     return ret ;
0734 }
0735 
0736 
0737 /**
0738 SName::ParseSOPR
0739 --------------------
0740 
0741 Parses colon or underscore delimited integers into solidId primIdxRel, eg::
0742 
0743    SOPR=0:0
0744    SOPR=0_0
0745 
0746 **/
0747 
0748 inline void SName::ParseSOPR(int& solidIdx, int& primIdxRel, const char* sopr_ ) // static
0749 {
0750     const char* sopr = sstr::ReplaceChars(sopr_, "_", ':');
0751 
0752     std::stringstream ss;
0753     ss.str(sopr)  ;
0754     std::string s;
0755     char delim = ':' ;
0756     std::vector<std::string> elem ;
0757     while (std::getline(ss, s, delim)) elem.push_back(s) ;
0758 
0759     unsigned num_elem = elem.size();
0760 
0761     solidIdx = num_elem > 0 ? ParseIntString( elem[0].c_str() ) : 0 ;
0762     primIdxRel = num_elem > 1 ? ParseIntString( elem[1].c_str() ) : 0 ;
0763 
0764     if(dump) std::cout
0765         << " sopr_ " << sopr_
0766         << " sopr " << sopr
0767         << " solidIdx " << solidIdx
0768         << " primIdxRel " << primIdxRel
0769         << std::endl
0770         ;
0771 }
0772 
0773 
0774 
0775 /**
0776 SName::parseMOI
0777 -------------------
0778 
0779 Used from CSGFoundry::parseMOI
0780 
0781 
0782 Parses MOI string into three integers:
0783 
0784 midx
0785     mesh index
0786 mord
0787     mesh ordinal
0788 iidx
0789     instance index
0790     (not the global instance index)
0791 
0792 
0793 MOI are strings delimited by colons of form::
0794 
0795     sWorld:0:0
0796     sWorld:0      # skipped integers default to zero
0797     sWorld        # skipped integers default to zero
0798 
0799     0:0:0
0800     0:0
0801     0
0802 
0803 The first element of the string can be a string such as "sWorld" or an integer,
0804 subsequent elements are expected to be integers.
0805 
0806 **/
0807 
0808 inline void SName::parseMOI(int& midx, int& mord, int& iidx, const char* moi ) const
0809 {
0810     std::stringstream ss;
0811     ss.str(moi)  ;
0812     std::string s;
0813     char delim = ':' ;
0814     std::vector<std::string> elem ;
0815     while (std::getline(ss, s, delim)) elem.push_back(s) ;
0816 
0817     unsigned num_elem = elem.size();
0818 
0819     unsigned count = 0 ;
0820     midx = num_elem > 0 ? parseArg( elem[0].c_str(), count) : 0 ;
0821     mord = num_elem > 1 ? ParseIntString( elem[1].c_str() ) : 0 ;
0822     iidx = num_elem > 2 ? ParseIntString( elem[2].c_str() ) : 0 ;
0823 
0824 
0825     if(dump) std::cout
0826         << " moi " << moi
0827         << " num_elem " << num_elem
0828         << " count " << count
0829         << " midx " << midx
0830         << " mord " << mord
0831         << " iidx " << iidx
0832         << " name.size " << name.size()
0833         << std::endl
0834         ;
0835 }
0836 
0837 
0838