/* ** Command & Conquer Generals Zero Hour(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: NameKeyGenerator.h /////////////////////////////////////////////////////////////////////// // Created: Michael Booth, May 2001 // Colin Day, May 2001 // Desc: Name key system to translate between names and unique key ids /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma once #ifndef __NAMEKEYGENERATOR_H_ #define __NAMEKEYGENERATOR_H_ #include "Lib/BaseType.h" #include "Common/SubsystemInterface.h" #include "Common/GameMemory.h" #include "Common/AsciiString.h" //------------------------------------------------------------------------------------------------- /** Note that NameKeyType isn't a "real" enum, but an enum type used to enforce the fact that NameKeys are really magic cookies, and aren't really interchangeable with ints. NAMEKEY_INVALID is always a legal value, but all other values are dynamically determined at runtime. (The generated code is basically identical, of course.) */ //------------------------------------------------------------------------------------------------- enum NameKeyType { NAMEKEY_INVALID = 0, NAMEKEY_MAX = 1<<23, // max ordinal value of a NameKey (some code relies on these fitting into 24 bits safely) FORCE_NAMEKEYTYPE_LONG = 0x7fffffff // a trick to ensure the NameKeyType is a 32-bit int }; //------------------------------------------------------------------------------------------------- /** A bucket entry for the name key generator */ //------------------------------------------------------------------------------------------------- class Bucket : public MemoryPoolObject { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE( Bucket, "NameKeyBucketPool" ); public: Bucket(); //~Bucket(); Bucket *m_nextInSocket; NameKeyType m_key; AsciiString m_nameString; }; inline Bucket::Bucket() : m_nextInSocket(NULL), m_key(NAMEKEY_INVALID) { } inline Bucket::~Bucket() { } //------------------------------------------------------------------------------------------------- /** This class implements the conversion of an arbitrary string into a unique * integer "key". Calling the nameToKey() method with the same string is * guaranteed to return the same key. Also, all keys generated by an * instance of this class are guaranteed to be unique with respect to that * instance's catalog of names. Multiple instances of this class can be * created to service multiple namespaces. */ //------------------------------------------------------------------------------------------------- class NameKeyGenerator : public SubsystemInterface { public: NameKeyGenerator(); virtual ~NameKeyGenerator(); virtual void init(); virtual void reset(); virtual void update() { } /// Given a string, convert into a unique integer key. NameKeyType nameToKey(const AsciiString& name) { return nameToKey(name.str()); } NameKeyType nameToLowercaseKey(const AsciiString& name) { return nameToLowercaseKey(name.str()); } /// Given a string, convert into a unique integer key. NameKeyType nameToKey(const char* name); NameKeyType nameToLowercaseKey(const char *name); /** given a key, return the name. this is almost never needed, except for a few rare cases like object serialization. also note that it's not particularly fast; it does a dumb linear search for the key. */ AsciiString keyToName(NameKeyType key); // Get a string out of the INI. Store it into a NameKeyType static void parseStringAsNameKeyType( INI *ini, void *instance, void *store, const void* userData ); private: enum { // socketcount should be prime, and not "close" to a power of 2, for best results. SOCKET_COUNT = 45007 }; void freeSockets(); Bucket* m_sockets[SOCKET_COUNT]; ///< Catalog of all Buckets already generated UnsignedInt m_nextID; ///< Next available ID }; // end class NameKeyGenerator //------------------------------------------------------------------------------------------------- // Externals //------------------------------------------------------------------------------------------------- extern NameKeyGenerator *TheNameKeyGenerator; ///< just one namespace for now // typing "TheNameKeyGenerator->nameToKey()" is awfully wordy. Here are shorter synonyms: inline NameKeyType NAMEKEY(const AsciiString& name) { return TheNameKeyGenerator->nameToKey(name); } inline NameKeyType NAMEKEY(const char* name) { return TheNameKeyGenerator->nameToKey(name); } inline AsciiString KEYNAME(NameKeyType nk) { return TheNameKeyGenerator->keyToName(nk); } //------------------------------------------------------------------------------------------------- class StaticNameKey { private: mutable NameKeyType m_key; const char* m_name; public: StaticNameKey(const char* p) : m_key(NAMEKEY_INVALID), m_name(p) {} NameKeyType key() const; // ugh, this is a little hokey, but lets us pretend that a StaticNameKey == NameKeyType inline operator NameKeyType() const { return key(); } }; #endif // __NAMEKEYGENERATOR_H_