diff --git a/direct/src/dcparse/dcparse.cxx b/direct/src/dcparse/dcparse.cxx index 3baecd4355..3b9796e239 100644 --- a/direct/src/dcparse/dcparse.cxx +++ b/direct/src/dcparse/dcparse.cxx @@ -26,5 +26,8 @@ main(int argc, char *argv[]) { return (1); } + long hash = file.get_hash(); + cout << "File hash is " << hash << "\n"; + return (0); } diff --git a/direct/src/dcparser/Sources.pp b/direct/src/dcparser/Sources.pp index c3af3d7a69..ef2082f0f9 100644 --- a/direct/src/dcparser/Sources.pp +++ b/direct/src/dcparser/Sources.pp @@ -12,10 +12,13 @@ #define SOURCES \ dcAtomicField.cxx dcAtomicField.h dcClass.cxx dcClass.h \ - dcField.cxx dcField.h dcFile.cxx dcFile.h dcLexer.lxx dcLexerDefs.h \ + dcField.cxx dcField.h dcFile.cxx dcFile.h \ + dcLexer.lxx dcLexerDefs.h \ dcMolecularField.cxx dcMolecularField.h dcParser.yxx \ dcParserDefs.h dcSubatomicType.cxx dcSubatomicType.h dcbase.h \ - dcindent.cxx dcindent.h + dcindent.cxx dcindent.h \ + hashGenerator.cxx hashGenerator.h \ + primeNumberGenerator.h primeNumberGenerator.cxx #define IGATESCAN all #end lib_target diff --git a/direct/src/dcparser/dcAtomicField.cxx b/direct/src/dcparser/dcAtomicField.cxx index 04b7e8e1cf..598f50eea4 100644 --- a/direct/src/dcparser/dcAtomicField.cxx +++ b/direct/src/dcparser/dcAtomicField.cxx @@ -4,6 +4,7 @@ //////////////////////////////////////////////////////////////////// #include "dcAtomicField.h" +#include "hashGenerator.h" #include "dcindent.h" @@ -213,3 +214,23 @@ write(ostream &out, int indent_level) const { out << "; // field " << _number << "\n"; } + +//////////////////////////////////////////////////////////////////// +// Function: DCAtomicField::generate_hash +// Access: Public, Virtual +// Description: Accumulates the properties of this field into the +// hash. +//////////////////////////////////////////////////////////////////// +void DCAtomicField:: +generate_hash(HashGenerator &hash) const { + DCField::generate_hash(hash); + + hash.add_int(_elements.size()); + Elements::const_iterator ei; + for (ei = _elements.begin(); ei != _elements.end(); ++ei) { + const ElementType &element = (*ei); + hash.add_int(element._type); + hash.add_int(element._divisor); + } + hash.add_int(_flags); +} diff --git a/direct/src/dcparser/dcAtomicField.h b/direct/src/dcparser/dcAtomicField.h index d526bdf502..cddcd9a999 100644 --- a/direct/src/dcparser/dcAtomicField.h +++ b/direct/src/dcparser/dcAtomicField.h @@ -39,6 +39,7 @@ PUBLISHED: public: DCAtomicField(); virtual void write(ostream &out, int indent_level = 0) const; + virtual void generate_hash(HashGenerator &hash) const; public: // These members define the primary interface to the atomic field diff --git a/direct/src/dcparser/dcClass.cxx b/direct/src/dcparser/dcClass.cxx index c2b7b29c94..876e90586d 100644 --- a/direct/src/dcparser/dcClass.cxx +++ b/direct/src/dcparser/dcClass.cxx @@ -4,6 +4,7 @@ //////////////////////////////////////////////////////////////////// #include "dcClass.h" +#include "hashGenerator.h" #include "dcindent.h" //////////////////////////////////////////////////////////////////// @@ -162,9 +163,9 @@ DCClass() { //////////////////////////////////////////////////////////////////// DCClass:: ~DCClass() { - Fields::iterator ai; - for (ai = _fields.begin(); ai != _fields.end(); ++ai) { - delete (*ai); + Fields::iterator fi; + for (fi = _fields.begin(); fi != _fields.end(); ++fi) { + delete (*fi); } } @@ -190,14 +191,37 @@ write(ostream &out, int indent_level) const { } out << " { // index " << _number << "\n"; - Fields::const_iterator ai; - for (ai = _fields.begin(); ai != _fields.end(); ++ai) { - (*ai)->write(out, indent_level + 2); + Fields::const_iterator fi; + for (fi = _fields.begin(); fi != _fields.end(); ++fi) { + (*fi)->write(out, indent_level + 2); } indent(out, indent_level) << "};\n"; } +//////////////////////////////////////////////////////////////////// +// Function: DCClass::generate_hash +// Access: Public, Virtual +// Description: Accumulates the properties of this class into the +// hash. +//////////////////////////////////////////////////////////////////// +void DCClass:: +generate_hash(HashGenerator &hash) const { + hash.add_string(_name); + + hash.add_int(_parents.size()); + Parents::const_iterator pi; + for (pi = _parents.begin(); pi != _parents.end(); ++pi) { + hash.add_int((*pi)->get_number()); + } + + hash.add_int(_fields.size()); + Fields::const_iterator fi; + for (fi = _fields.begin(); fi != _fields.end(); ++fi) { + (*fi)->generate_hash(hash); + } +} + //////////////////////////////////////////////////////////////////// // Function: DCClass::add_field // Access: Public diff --git a/direct/src/dcparser/dcClass.h b/direct/src/dcparser/dcClass.h index c80cdad4b5..9962ef63d4 100644 --- a/direct/src/dcparser/dcClass.h +++ b/direct/src/dcparser/dcClass.h @@ -12,6 +12,8 @@ #include #include +class HashGenerator; + //////////////////////////////////////////////////////////////////// // Class : DCClass // Description : Defines a particular DistributedClass as read from an @@ -37,6 +39,8 @@ public: ~DCClass(); void write(ostream &out, int indent_level = 0) const; + void generate_hash(HashGenerator &hash) const; + bool add_field(DCField *field); public: diff --git a/direct/src/dcparser/dcField.cxx b/direct/src/dcparser/dcField.cxx index a92befff55..36ea2ca540 100644 --- a/direct/src/dcparser/dcField.cxx +++ b/direct/src/dcparser/dcField.cxx @@ -4,6 +4,7 @@ //////////////////////////////////////////////////////////////////// #include "dcField.h" +#include "hashGenerator.h" //////////////////////////////////////////////////////////////////// // Function: DCField::get_number @@ -59,3 +60,18 @@ as_molecular_field() { DCField:: ~DCField() { } + +//////////////////////////////////////////////////////////////////// +// Function: DCField::generate_hash +// Access: Public, Virtual +// Description: Accumulates the properties of this field into the +// hash. +//////////////////////////////////////////////////////////////////// +void DCField:: +generate_hash(HashGenerator &hash) const { + // It shouldn't be necessary to explicitly add _number to the + // hash--this is computed based on the relative position of this + // field with the other fields, so adding it explicitly will be + // redundant. However, the field name is significant. + hash.add_string(_name); +} diff --git a/direct/src/dcparser/dcField.h b/direct/src/dcparser/dcField.h index 3039ae04dd..2c55a0c2f4 100644 --- a/direct/src/dcparser/dcField.h +++ b/direct/src/dcparser/dcField.h @@ -10,6 +10,7 @@ class DCAtomicField; class DCMolecularField; +class HashGenerator; //////////////////////////////////////////////////////////////////// // Class : DCField @@ -27,6 +28,7 @@ PUBLISHED: public: virtual ~DCField(); virtual void write(ostream &out, int indent_level = 0) const=0; + virtual void generate_hash(HashGenerator &hash) const; public: int _number; diff --git a/direct/src/dcparser/dcFile.cxx b/direct/src/dcparser/dcFile.cxx index 606572e4c8..7b279b418b 100644 --- a/direct/src/dcparser/dcFile.cxx +++ b/direct/src/dcparser/dcFile.cxx @@ -6,6 +6,7 @@ #include "dcFile.h" #include "dcParserDefs.h" #include "dcLexerDefs.h" +#include "hashGenerator.h" #ifdef WITHIN_PANDA #include @@ -14,7 +15,7 @@ //////////////////////////////////////////////////////////////////// // Function: DCFile::Constructor -// Access: Public +// Access: Published // Description: //////////////////////////////////////////////////////////////////// DCFile:: @@ -23,7 +24,7 @@ DCFile() { //////////////////////////////////////////////////////////////////// // Function: DCFile::Destructor -// Access: Public +// Access: Published // Description: //////////////////////////////////////////////////////////////////// DCFile:: @@ -36,7 +37,7 @@ DCFile:: //////////////////////////////////////////////////////////////////// // Function: DCFile::read -// Access: Public +// Access: Published // Description: Opens and reads the indicated .dc file by name. The // distributed classes defined in the file will be // appended to the set of distributed classes already @@ -67,7 +68,7 @@ read(Filename filename) { //////////////////////////////////////////////////////////////////// // Function: DCFile::read -// Access: Public +// Access: Published // Description: Parses the already-opened input stream for // distributed class descriptions. The filename // parameter is optional and is only used when reporting @@ -92,7 +93,7 @@ read(istream &in, const string &filename) { //////////////////////////////////////////////////////////////////// // Function: DCFile::write -// Access: Public +// Access: Published // Description: Opens the indicated filename for output and writes a // parseable description of all the known distributed // classes to the file. @@ -120,7 +121,7 @@ write(Filename filename) const { //////////////////////////////////////////////////////////////////// // Function: DCFile::write -// Access: Public +// Access: Published // Description: Writes a parseable description of all the known // distributed classes to the file. The filename // parameter is optional and is only used when reporting @@ -147,7 +148,7 @@ write(ostream &out, const string &filename) const { //////////////////////////////////////////////////////////////////// // Function: DCFile::get_num_classes -// Access: Public +// Access: Published // Description: Returns the number of classes read from the .dc // file(s). //////////////////////////////////////////////////////////////////// @@ -158,7 +159,7 @@ get_num_classes() { //////////////////////////////////////////////////////////////////// // Function: DCFile::get_class -// Access: Public +// Access: Published // Description: Returns the nth class read from the .dc file(s). //////////////////////////////////////////////////////////////////// DCClass *DCFile:: @@ -169,7 +170,7 @@ get_class(int n) { //////////////////////////////////////////////////////////////////// // Function: DCFile::get_class_by_name -// Access: Public +// Access: Published // Description: Returns the class that has the indicated name, or // NULL if there is no such class. //////////////////////////////////////////////////////////////////// @@ -184,6 +185,37 @@ get_class_by_name(const string &name) { return (DCClass *)NULL; } +//////////////////////////////////////////////////////////////////// +// Function: DCFile::get_hash +// Access: Published +// Description: Returns a 32-bit hash index associated with this +// file. This number is guaranteed to be consistent if +// the contents of the file have not changed, and it is +// very likely to be different if the contents of the +// file do change. +//////////////////////////////////////////////////////////////////// +long DCFile:: +get_hash() const { + HashGenerator hash; + generate_hash(hash); + return hash.get_hash(); +} + +//////////////////////////////////////////////////////////////////// +// Function: DCFile::generate_hash +// Access: Public, Virtual +// Description: Accumulates the properties of this file into the +// hash. +//////////////////////////////////////////////////////////////////// +void DCFile:: +generate_hash(HashGenerator &hash) const { + hash.add_int(_classes.size()); + Classes::const_iterator ci; + for (ci = _classes.begin(); ci != _classes.end(); ++ci) { + (*ci)->generate_hash(hash); + } +} + //////////////////////////////////////////////////////////////////// // Function: DCFile::add_class // Access: Public diff --git a/direct/src/dcparser/dcFile.h b/direct/src/dcparser/dcFile.h index eeb4d66581..02185c7ff3 100644 --- a/direct/src/dcparser/dcFile.h +++ b/direct/src/dcparser/dcFile.h @@ -12,6 +12,8 @@ #include #include +class HashGenerator; + //////////////////////////////////////////////////////////////////// // Class : DCFile // Description : Represents the complete list of Distributed Class @@ -33,7 +35,10 @@ PUBLISHED: DCClass *get_class_by_name(const string &name); + long get_hash() const; + public: + void generate_hash(HashGenerator &hash) const; bool add_class(DCClass *dclass); public: diff --git a/direct/src/dcparser/dcMolecularField.cxx b/direct/src/dcparser/dcMolecularField.cxx index 194c0a7e64..88f77edece 100644 --- a/direct/src/dcparser/dcMolecularField.cxx +++ b/direct/src/dcparser/dcMolecularField.cxx @@ -5,6 +5,7 @@ #include "dcMolecularField.h" #include "dcAtomicField.h" +#include "hashGenerator.h" #include "dcindent.h" @@ -79,3 +80,20 @@ write(ostream &out, int indent_level) const { out << "; // field " << _number << "\n"; } + +//////////////////////////////////////////////////////////////////// +// Function: DCMolecularField::generate_hash +// Access: Public, Virtual +// Description: Accumulates the properties of this field into the +// hash. +//////////////////////////////////////////////////////////////////// +void DCMolecularField:: +generate_hash(HashGenerator &hash) const { + DCField::generate_hash(hash); + + hash.add_int(_fields.size()); + Fields::const_iterator fi; + for (fi = _fields.begin(); fi != _fields.end(); ++fi) { + (*fi)->generate_hash(hash); + } +} diff --git a/direct/src/dcparser/dcMolecularField.h b/direct/src/dcparser/dcMolecularField.h index 2368f5a839..cf2d9d19ae 100644 --- a/direct/src/dcparser/dcMolecularField.h +++ b/direct/src/dcparser/dcMolecularField.h @@ -30,6 +30,7 @@ PUBLISHED: public: DCMolecularField(); virtual void write(ostream &out, int indent_level = 0) const; + virtual void generate_hash(HashGenerator &hash) const; public: // These members define the primary interface to the molecular field diff --git a/direct/src/dcparser/hashGenerator.cxx b/direct/src/dcparser/hashGenerator.cxx new file mode 100644 index 0000000000..f85c9c24b7 --- /dev/null +++ b/direct/src/dcparser/hashGenerator.cxx @@ -0,0 +1,69 @@ +// Filename: hashGenerator.cxx +// Created by: drose (22Mar01) +// +//////////////////////////////////////////////////////////////////// + +#include "hashGenerator.h" +#include "primeNumberGenerator.h" + +// We multiply each consecutive integer by the next prime number and +// add it to the total, so in theory we will truly generate a unique +// hash number for each unique sequence of ints, as long as the number +// of ints does not exceed the number of prime numbers we have, and we +// do not overflow the limits of a 32-bit integer. + +// We do recycle the prime number table at some point, just to keep it +// from growing insanely large, however, and we also truncate +// everything to the low-order 32 bits, so we introduce ambiguity in +// this way. + +static const int max_prime_numbers = 10000; +static PrimeNumberGenerator primes; + +//////////////////////////////////////////////////////////////////// +// Function: HashGenerator::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +HashGenerator:: +HashGenerator() { + _hash = 0; + _index = 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: HashGenerator::add_int +// Access: Public +// Description: Adds another integer to the hash so far. +//////////////////////////////////////////////////////////////////// +void HashGenerator:: +add_int(int num) { + nassertv(_index >= 0 && _index < max_prime_numbers); + _hash += (int)primes[_index] * num; + _index = (_index + 1) % max_prime_numbers; +} + +//////////////////////////////////////////////////////////////////// +// Function: HashGenerator::add_string +// Access: Public +// Description: Adds a string to the hash, by breaking it down into a +// sequence of integers. +//////////////////////////////////////////////////////////////////// +void HashGenerator:: +add_string(const string &str) { + add_int(str.length()); + string::const_iterator si; + for (si = str.begin(); si != str.end(); ++si) { + add_int(*si); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: HashGenerator::get_hash +// Access: Public +// Description: Returns the hash number generated. +//////////////////////////////////////////////////////////////////// +long HashGenerator:: +get_hash() const { + return _hash & 0xffffffff; +} diff --git a/direct/src/dcparser/hashGenerator.h b/direct/src/dcparser/hashGenerator.h new file mode 100644 index 0000000000..38977da6a4 --- /dev/null +++ b/direct/src/dcparser/hashGenerator.h @@ -0,0 +1,30 @@ +// Filename: hashGenerator.h +// Created by: drose (22Mar01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef DCHASHGENERATOR_H +#define DCHASHGENERATOR_H + +#include "dcbase.h" + +//////////////////////////////////////////////////////////////////// +// Class : HashGenerator +// Description : This class generates an arbitrary hash number from a +// sequence of ints. +//////////////////////////////////////////////////////////////////// +class HashGenerator { +public: + HashGenerator(); + + void add_int(int num); + void add_string(const string &str); + + long get_hash() const; + +private: + long _hash; + int _index; +}; + +#endif diff --git a/direct/src/dcparser/primeNumberGenerator.cxx b/direct/src/dcparser/primeNumberGenerator.cxx new file mode 100644 index 0000000000..957fb25ae3 --- /dev/null +++ b/direct/src/dcparser/primeNumberGenerator.cxx @@ -0,0 +1,55 @@ +// Filename: primeNumberGenerator.cxx +// Created by: drose (22Mar01) +// +//////////////////////////////////////////////////////////////////// + +#include "primeNumberGenerator.h" + + +//////////////////////////////////////////////////////////////////// +// Function: PrimeNumberGenerator::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PrimeNumberGenerator:: +PrimeNumberGenerator() { + _primes.push_back(2); +} + +//////////////////////////////////////////////////////////////////// +// Function: PrimeNumberGenerator::Indexing operator +// Access: Public +// Description: Returns the nth prime number. this[0] returns 2, +// this[1] returns 3; successively larger values of n +// return larger prime numbers, up to the largest prime +// number that can be represented in an int. +//////////////////////////////////////////////////////////////////// +int PrimeNumberGenerator:: +operator [] (int n) { + nassertr(n >= 0, 0); + + // Compute the prime numbers between the last-computed prime number + // and n. + int candidate = _primes.back() + 1; + while ((int)_primes.size() <= n) { + // Is candidate prime? It is not if any one of the already-found + // prime numbers (up to its square root) divides it evenly. + bool maybe_prime = true; + int j = 0; + while (maybe_prime && _primes[j] * _primes[j] <= candidate) { + if ((_primes[j] * (candidate / _primes[j])) == candidate) { + // This one is not prime. + maybe_prime = false; + } + j++; + nassertr(j < (int)_primes.size(), 0) + } + if (maybe_prime) { + // Hey, we found a prime! + _primes.push_back(candidate); + } + candidate++; + } + + return _primes[n]; +} diff --git a/direct/src/dcparser/primeNumberGenerator.h b/direct/src/dcparser/primeNumberGenerator.h new file mode 100644 index 0000000000..b4cf927e6f --- /dev/null +++ b/direct/src/dcparser/primeNumberGenerator.h @@ -0,0 +1,30 @@ +// Filename: primeNumberGenerator.h +// Created by: drose (22Mar01) +// +//////////////////////////////////////////////////////////////////// + +#ifndef PRIMENUMBERGENERATOR_H +#define PRIMENUMBERGENERATOR_H + +#include "dcbase.h" + +//////////////////////////////////////////////////////////////////// +// Class : PrimeNumberGenerator +// Description : This class generates a table of prime numbers, up to +// the limit of an int. For a given integer n, it will +// return the nth prime number. This will involve a +// recompute step only if n is greater than any previous +// n. +//////////////////////////////////////////////////////////////////// +class PrimeNumberGenerator { +public: + PrimeNumberGenerator(); + + int operator [] (int n); + +private: + typedef vector Primes; + Primes _primes; +}; + +#endif