// UniqueId.cxx #include "dataset_id/UniqueId.h" #include #if ( __GNUC__ == 2 ) #include "dataset_id/sstream.h" #else #include #endif #include #include #include "dataset_util/XmlElement.h" using std::string; using std::ostream; using std::istringstream; using std::ostringstream; using std::setw; using std::setfill; using std::hex; typedef UniqueId::Index Index; //********************************************************************** // Local definitions. //********************************************************************** namespace { string DSEP = "/"; // Convert hex index ijklmnop to string "ij/kl/mn/op". string index_to_path(Index ival) { assert( sizeof(Index) >= 4 ); int rightshift = 8*(sizeof(Index)-1); ostringstream spath; for ( int i=0; i<4; ++i ) { int leftshift = 8*i; int shifted = ival<>rightshift; if ( i != 0 ) spath << DSEP; spath << hex << setw(2) << setfill('0') << shifted; } return spath.str(); } //********************************************************************** const Index BAD_DIGIT = 16; // Convert hex digit to decimal. Index hex_to_int(char chex) { switch(chex) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': return 10; case 'b': return 11; case 'c': return 12; case 'd': return 13; case 'e': return 14; case 'f': return 15; case 'A': return 10; case 'B': return 11; case 'C': return 12; case 'D': return 13; case 'E': return 14; case 'F': return 15; } return BAD_DIGIT; } //********************************************************************** // Convert "ij/kl/mn/op" back to index. Index path_to_index(string path) { assert( sizeof(Index) >= 4 ); if ( path.size() != 11 ) return 0; Index ival = 0; for ( int i=0; i<4; ++i ) { int ipos = 3*i; Index i1 = hex_to_int(path[ipos]); if ( i1 == BAD_DIGIT ) return 0; i1 = i1<<4; Index i2 = hex_to_int(path[ipos+1]); if ( i2 == BAD_DIGIT ) return 0; Index ifield = i1 + i2; ival = ival<<8; ival += ifield; } return ival; } } // end unnamed namespace //********************************************************************** // Static member functions. //********************************************************************** // DTD. Text UniqueId::make_dtd(string name) { Text txt; txt.append(""); txt.append(""); return txt; } //********************************************************************** // Member functions. //********************************************************************** // Write to XML with specified name. const XmlElement* UniqueId::xml_with_name(string xname) const { XmlElement* pele = new XmlElement(xname); Index icol = collection(); string sent = "entry"; string scol = "collection"; // This line corrupts *pele!!! Index ient = entry(); pele->add_attribute_as_unsigned_int(scol, icol); pele->add_attribute_as_unsigned_int(sent, ient); return pele; } //********************************************************************** // Default constructor. UniqueId::UniqueId() : m_col(0), m_ent(0) { } //********************************************************************** // Constructor from collection and entry. UniqueId::UniqueId(Index col, Index ent) : m_col(col), m_ent(ent) { } //********************************************************************** // Constructor from string iii-eee or path. UniqueId::UniqueId(string sid) : m_col(0), m_ent(0) { string::size_type isep = sid.find('-'); // String. if ( isep != string::npos ) { string::size_type lcol = isep; string::size_type lent = sid.size() - lcol - 1; if ( lcol==0 || lent==0 ) return; string scol = sid.substr(0,lcol); string sent = sid.substr(isep+1,lent); istringstream sscol(scol); sscol >> m_col; istringstream ssent(sent); ssent >> m_ent; // Path. } else if ( sid.size() == 23 ) { m_col = path_to_index(sid.substr(0,11)); m_ent = path_to_index(sid.substr(12,11)); } } //********************************************************************** // Constructor from XML. UniqueId::UniqueId(const XmlElement& ele) : m_col(0), m_ent(0) { int errcount = ele.error_count(); assert( ele.has_attribute("collection") ); assert( ele.has_attribute("entry") ); if ( ! ele.has_attribute("collection") || ! ele.has_attribute("entry") ) return; m_col = ele.attribute_as_unsigned_int("collection"); m_ent = ele.attribute_as_unsigned_int("entry"); if ( ele.error_count() != errcount ) { m_col = 0; m_ent = 0; } } //********************************************************************** // Validity. bool UniqueId::is_valid() const { return m_ent != 0; } //********************************************************************** // Global index? bool UniqueId::is_global() const { return is_valid() && collection()!=0; } //********************************************************************** // Return the collection. Index UniqueId::collection() const { return m_col; } //********************************************************************** // Return the entry. Index UniqueId::entry() const { return m_ent; } //********************************************************************** // Return the next entry. UniqueId UniqueId::next() const { if ( ! is_valid() ) return UniqueId(); return UniqueId(m_col, m_ent+1); } //********************************************************************** // Convert to a string. string UniqueId::to_string(bool pad) const { string sid; if ( pad ) { sid = index_to_string(collection(), '0') + "-" + index_to_string(entry(), '0'); } else { sid = index_to_string(collection()) + "-" + index_to_string(entry()); } return sid; } //********************************************************************** // Convert to a path. string UniqueId::to_path() const { if ( ! is_valid() ) return ""; return index_to_path(collection()) + DSEP + index_to_path(entry()); } //********************************************************************** // Write to XML. const XmlElement* UniqueId::xml() const { return xml_with_name(xml_name()); } //********************************************************************** // Free functions. //********************************************************************** // Ordering. bool operator<(const UniqueId& lhs, const UniqueId& rhs) { if ( lhs.collection() < rhs.collection() ) { return true; } else if ( rhs.collection() < lhs.collection() ) { return false; } else { return lhs.entry() < rhs.entry(); } } //********************************************************************** // Equality. bool operator==(const UniqueId& lhs, const UniqueId& rhs) { if ( lhs.collection() != rhs.collection() ) return false; return lhs.entry() == rhs.entry(); } //********************************************************************** // Inquality. bool operator!=(const UniqueId& lhs, const UniqueId& rhs) { if ( lhs.collection() != rhs.collection() ) return true; return lhs.entry() != rhs.entry(); } //********************************************************************** // Convert index to padded string. string index_to_string(Index idx, char pad) { char cint[16]; if ( pad == '\000' ) { sprintf(cint, "%lu", idx); } else { sprintf(cint, "%10lu", idx); } string sint(cint); // Remove leading blanks. for ( string::size_type is=0; is