more PART parser work
This commit is contained in:
parent
b942ebdc69
commit
0af1004f5c
|
@ -459,8 +459,12 @@ void DIR_LIB_SOURCE::GetRevisions( STRINGS* aResults, const STRING& aPartName )
|
|||
PN_ITER it = partnames.upper_bound( partName +'/' );
|
||||
PN_ITER end = partnames.lower_bound( partName + char( '/' +1 ) );
|
||||
|
||||
while( it != end )
|
||||
aResults->push_back( *it++ );
|
||||
for( ; it != end; ++it )
|
||||
{
|
||||
const char* rev = endsWithRev( *it );
|
||||
assert( rev );
|
||||
aResults->push_back( it->substr( rev - it->c_str() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
100
new/sch_lib.cpp
100
new/sch_lib.cpp
|
@ -39,13 +39,12 @@
|
|||
|
||||
/*
|
||||
|
||||
The LIB part cache consist of a std::map of partnames without revisions at the top level.
|
||||
Each top level map entry can point to another std::map which it owns and holds all the revisions
|
||||
for that part name. At any point in the tree, there can be NULL pointers which
|
||||
allow for lazy loading, including the very top most root pointer itself, which
|
||||
is PARTS* parts. We use the key to hold the partName at one level, and revision
|
||||
at the deeper nested level, and that key information may not be present within
|
||||
right hand side of the map tuple.
|
||||
The LIB part cache consists of a std::map of partnames without revisions at the
|
||||
top level. Each top level map entry can point to another std::map which it owns
|
||||
and which holds all the revisions for that part name. At any point in the tree,
|
||||
there can be NULL pointers which allow for lazy loading, including the very top
|
||||
most root pointer itself, which is PARTS* parts. We use the key to hold the
|
||||
partName at one level, and revision at the deeper nested level.
|
||||
|
||||
1) Only things which are asked for are done.
|
||||
2) Anything we learn we remember.
|
||||
|
@ -54,10 +53,31 @@ right hand side of the map tuple.
|
|||
|
||||
namespace SCH {
|
||||
|
||||
class PART_REVS : public std::map< STRING, PART* >
|
||||
{
|
||||
// @todo provide an integer sort on revN.. strings here.
|
||||
|
||||
/**
|
||||
* Struct LTREV
|
||||
* is for PART_REVS, and provides a custom way to compare rev STRINGs.
|
||||
* Namely, the revN[N..] string if present, is collated according to a
|
||||
* 'higher revision first'.
|
||||
*/
|
||||
struct LTREV
|
||||
{
|
||||
bool operator() ( const STRING& s1, const STRING& s2 ) const
|
||||
{
|
||||
return RevCmp( s1.c_str(), s2.c_str() ) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class PART_REVS
|
||||
* contains the collection of revisions for a particular part name, in the
|
||||
* form of cached PARTs. The tuple consists of a rev string and a PART pointer.
|
||||
* The rev string is like "rev1", the PART pointer will be NULL until the PART
|
||||
* gets loaded, lazily.
|
||||
*/
|
||||
class PART_REVS : public std::map< STRING, PART*, LTREV >
|
||||
{
|
||||
public:
|
||||
~PART_REVS()
|
||||
{
|
||||
|
@ -68,6 +88,15 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class PARTS
|
||||
* contains the collection of PART_REVS for all PARTs in the lib.
|
||||
* The tuple consists of a part name and a PART_REVS pointer.
|
||||
* The part name does not have the revision attached (of course this is understood
|
||||
* by definition of "part name"). The PART_REVS pointer will be NULL until a client
|
||||
* askes about the revisions for a part name, so the loading is done lazily.
|
||||
*/
|
||||
class PARTS : public std::map< STRING, PART_REVS* >
|
||||
{
|
||||
public:
|
||||
|
@ -126,7 +155,7 @@ LIB::~LIB()
|
|||
}
|
||||
|
||||
|
||||
const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
||||
const PART* LIB::lookupPart( const LPID& aLPID ) throw( IO_ERROR )
|
||||
{
|
||||
if( !parts )
|
||||
{
|
||||
|
@ -137,7 +166,7 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
|||
// insert a PART_REVS for each part name
|
||||
for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it )
|
||||
{
|
||||
// D(printf("findPart:%s\n", it->c_str() );)
|
||||
D(printf("lookupPart:%s\n", it->c_str() );)
|
||||
(*parts)[*it] = new PART_REVS;
|
||||
}
|
||||
}
|
||||
|
@ -152,44 +181,46 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
|||
// if the key for parts has no aLPID.GetPartName() the part is not in this lib
|
||||
if( revs )
|
||||
{
|
||||
if( revs->size() == 0 )
|
||||
if( revs->size() == 0 ) // assume rev list has not been loaded yet
|
||||
{
|
||||
// load all the revisions for this part.
|
||||
source->GetRevisions( &vfetch, aLPID.GetPartName() );
|
||||
|
||||
// creat a PART_REV entry for revision, but leave the PART* NULL
|
||||
// create a PART_REV entry for each revision, but leave the PART* NULL
|
||||
for( STRINGS::const_iterator it = vfetch.begin(); it!=vfetch.end(); ++it )
|
||||
{
|
||||
// D(printf("findPartRev:%s\n", it->c_str() );)
|
||||
D(printf("lookupPartRev:%s\n", it->c_str() );)
|
||||
(*revs)[*it] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PART_REVS::iterator result = revs->find( aLPID.GetPartNameAndRev() );
|
||||
|
||||
if( result != revs->end() )
|
||||
{
|
||||
if( !result->second ) // the PART has never been loaded before
|
||||
{
|
||||
result->second = new PART( this, aLPID.GetPartNameAndRev() );
|
||||
}
|
||||
|
||||
return result->second;
|
||||
}
|
||||
PART_REVS::iterator rev;
|
||||
|
||||
// If caller did not say what revision, find the highest numbered one and return that.
|
||||
// Otherwise he knew what he wanted specifically, and we do not have it.
|
||||
if( !aLPID.GetRevision().size() && revs->size() )
|
||||
{
|
||||
result = revs->begin(); // sort order has highest rev first
|
||||
rev = revs->begin(); // sort order has highest rev first
|
||||
|
||||
if( !result->second ) // the PART has never been loaded before
|
||||
if( !rev->second ) // the PART has never been instantiated before
|
||||
{
|
||||
result->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), result->first ) );
|
||||
rev->second = new PART( this, LPID::Format( "", aLPID.GetPartName(), rev->first ) );
|
||||
}
|
||||
|
||||
return result->second;
|
||||
D(printf("lookupPartLatestRev:%s\n", rev->second->partNameAndRev.c_str() );)
|
||||
return rev->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
rev = revs->find( aLPID.GetRevision() );
|
||||
|
||||
if( rev != revs->end() )
|
||||
{
|
||||
if( !rev->second ) // the PART has never been instantiated before
|
||||
{
|
||||
rev->second = new PART( this, aLPID.GetPartNameAndRev() );
|
||||
}
|
||||
return rev->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,7 +230,7 @@ const PART* LIB::findPart( const LPID& aLPID ) throw( IO_ERROR )
|
|||
|
||||
PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR )
|
||||
{
|
||||
PART* part = (PART*) findPart( aLPID );
|
||||
PART* part = (PART*) lookupPart( aLPID );
|
||||
|
||||
if( !part ) // part does not exist in this lib
|
||||
{
|
||||
|
@ -221,7 +252,8 @@ PART* LIB::LookupPart( const LPID& aLPID, LIB_TABLE* aLibTable ) throw( IO_ERROR
|
|||
printf( "\n" );
|
||||
#endif
|
||||
|
||||
SWEET_LEXER sw( part->body, wxString::FromUTF8("body") /* @todo have ReadPart give better source */ );
|
||||
// @todo consider changing ReadPart to return a "source"
|
||||
SWEET_LEXER sw( part->body, wxString::FromUTF8( aLPID.Format().c_str() ) );
|
||||
|
||||
part->Parse( &sw, aLibTable );
|
||||
}
|
||||
|
|
|
@ -343,14 +343,17 @@ protected:
|
|||
PARTS* parts;
|
||||
|
||||
/**
|
||||
* Function findPart
|
||||
* finds a PART, returns NULL if cannot find.
|
||||
* Function lookupPart
|
||||
* looks up a PART, returns NULL if cannot find in source. Does not parse
|
||||
* the part. Does not even load the part's Sweet string. No ownership
|
||||
* is given to the PART, it stays in the cache that is this LIB.
|
||||
*
|
||||
* @throw IO_ERROR if there is some kind of communications error reading
|
||||
* the original list of parts.
|
||||
*
|
||||
* @return PART* - the cached PART, or NULL if not found. No ownership transferred.
|
||||
*/
|
||||
const PART* findPart( const LPID& aLPID ) throw( IO_ERROR );
|
||||
|
||||
|
||||
const PART* lookupPart( const LPID& aLPID ) throw( IO_ERROR );
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -58,6 +58,20 @@ const char* EndsWithRev( const char* start, const char* tail, char separator )
|
|||
return 0;
|
||||
}
|
||||
|
||||
int RevCmp( const char* s1, const char* s2 )
|
||||
{
|
||||
int r = strncmp( s1, s2, 3 );
|
||||
|
||||
if( r || strlen(s1)<4 || strlen(s2)<4 )
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
int rnum1 = atoi( s1+3 );
|
||||
int rnum2 = atoi( s2+3 );
|
||||
|
||||
return -(rnum1 - rnum2); // swap the sign, higher revs first
|
||||
}
|
||||
|
||||
//----<Policy and field test functions>-------------------------------------
|
||||
|
||||
|
@ -94,7 +108,7 @@ static int okRevision( const STRING& aField )
|
|||
{
|
||||
char rev[32]; // C string for speed
|
||||
|
||||
if( aField.size() >= 4 && aField.size() <= sizeof(rev)-3 )
|
||||
if( aField.size() >= 4 )
|
||||
{
|
||||
strcpy( rev, "x/" );
|
||||
strcat( rev, aField.c_str() );
|
||||
|
|
|
@ -228,4 +228,16 @@ static inline const char* EndsWithRev( const STRING& aPartName, char separator =
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function RevCmp
|
||||
* compares two rev strings in a way like strcmp() except that the highest numbered
|
||||
* revision is considered first in the sort order. The function probably won't work
|
||||
* unless you give it two rev strings.
|
||||
* @param s1 is a rev string like "rev10"
|
||||
* @param s2 is a rev string like "rev1".
|
||||
* @return int - either negative, zero, or positive depending on whether the revision
|
||||
* is greater, equal, or less on the left hand side.
|
||||
*/
|
||||
int RevCmp( const char* s1, const char* s2 );
|
||||
|
||||
#endif // SCH_LPID_H_
|
||||
|
|
|
@ -135,19 +135,28 @@ public:
|
|||
/// @param me = ja mir, the object getting stuffed, from its perspective
|
||||
void parsePart( PART* me )
|
||||
{
|
||||
PART_T tok = in->NextTok();
|
||||
PART_T tok;
|
||||
|
||||
#if 0
|
||||
// Be flexible regarding the starting point of the stream.
|
||||
// Caller may not have read the first two tokens out of the
|
||||
// stream: T_LEFT and T_part, so ignore them if seen here.
|
||||
// The 1st two tokens T_LEFT and T_part are then optional in the grammar.
|
||||
|
||||
if( tok == T_LEFT )
|
||||
if( (tok = in->NextTok() ) == T_LEFT )
|
||||
{
|
||||
if( ( tok = in->NextTok() ) != T_part )
|
||||
in->Expecting( T_part );
|
||||
}
|
||||
|
||||
#else
|
||||
// "( part" are not optional
|
||||
in->NeedLEFT();
|
||||
|
||||
if( ( tok = in->NextTok() ) != T_part )
|
||||
in->Expecting( T_part );
|
||||
#endif
|
||||
|
||||
in->NeedSYMBOLorNUMBER(); // read in part NAME_HINT, and toss
|
||||
tok = in->NextTok();
|
||||
|
||||
|
@ -267,7 +276,7 @@ public:
|
|||
|
||||
contains |= PB(PARSED);
|
||||
|
||||
this->contains |= contains;
|
||||
me->contains |= contains;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue