369 lines
11 KiB
C++
369 lines
11 KiB
C++
/*
|
|
** Command & Conquer Generals(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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// (c) 2001-2003 Electronic Arts Inc. //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// FILE: Dict.h
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Westwood Studios Pacific.
|
|
//
|
|
// Confidential Information
|
|
// Copyright (C) 2001 - All Rights Reserved
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Project: RTS3
|
|
//
|
|
// File name: Dict.h
|
|
//
|
|
// Created: Steven Johnson, November 2001
|
|
//
|
|
// Desc: General-purpose dictionary class
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma once
|
|
|
|
#ifndef Dict_H
|
|
#define Dict_H
|
|
|
|
#include "Common/Errors.h"
|
|
#include "Common/NameKeyGenerator.h"
|
|
|
|
// -----------------------------------------------------
|
|
/**
|
|
Dict provides a general utility class for maintaining
|
|
a sorted key-value pair list. Keys are currently required
|
|
to be of type NameKeyType, and data may be Bool, int, real,
|
|
or string.
|
|
|
|
Current implementation keeps the pairs sorted by key, and
|
|
does a binary search for lookups; this might change in the future,
|
|
depending on usage and performance (e.g., to a hashtable). So
|
|
don't rely on the quirks of this implementation.
|
|
*/
|
|
class Dict
|
|
{
|
|
public:
|
|
enum
|
|
{
|
|
MAX_LEN = 32767 ///< max total len of any Dict, in Pairs
|
|
};
|
|
|
|
enum DataType
|
|
{
|
|
DICT_NONE = -1, // this is returned by getType and getNthType to indicate "invalid key/index"
|
|
DICT_BOOL = 0, // note, we rely on the fact that this constant is zero in the code. so don't change it.
|
|
DICT_INT,
|
|
DICT_REAL,
|
|
DICT_ASCIISTRING,
|
|
DICT_UNICODESTRING
|
|
};
|
|
|
|
/**
|
|
Default constructor -- construct a new, empty Dict.
|
|
*/
|
|
Dict(Int numPairsToPreAllocate = 0);
|
|
|
|
/**
|
|
Copy constructor -- make this Dict identical to the
|
|
other Dict. (This is actually quite efficient, because
|
|
they will simply share the same data and increment the
|
|
refcount.)
|
|
*/
|
|
Dict(const Dict& src);
|
|
|
|
/**
|
|
Destructor. Not too exciting... clean up the works and such.
|
|
*/
|
|
~Dict();
|
|
|
|
/**
|
|
*/
|
|
Dict& operator=(const Dict& src);
|
|
|
|
/**
|
|
remove all pairs.
|
|
*/
|
|
void clear();
|
|
|
|
/**
|
|
return the number of key-value pairs in the dict.
|
|
*/
|
|
Int getPairCount() const;
|
|
|
|
/**
|
|
Return the key for the nth pair (0-based index).
|
|
return NAMEKEY_INVALID if n is out of range.
|
|
*/
|
|
NameKeyType getNthKey(Int n) const;
|
|
|
|
/**
|
|
Return the datatype for the pair with the given key.
|
|
return DICT_NONE if no pair with the key exists.
|
|
*/
|
|
DataType getType(NameKeyType key) const;
|
|
|
|
/**
|
|
Return there is a pair with the given key and datatype, return true.
|
|
*/
|
|
inline Bool known(NameKeyType key, DataType d) const
|
|
{
|
|
return getType(key) == d;
|
|
}
|
|
|
|
/**
|
|
Return the datatype for the nth pair (0-based index).
|
|
return DICT_NONE if n is out of range.
|
|
*/
|
|
DataType getNthType(Int n) const;
|
|
|
|
/**
|
|
return the value for the pair with the given key.
|
|
if there is no pair with the given key, or the value is
|
|
not of the correct type, 0 is returned.
|
|
*/
|
|
Bool getBool(NameKeyType key, Bool* exists = NULL) const;
|
|
/**
|
|
return the value for the pair with the given key.
|
|
if there is no pair with the given key, or the value is
|
|
not of the correct type, 0 is returned.
|
|
*/
|
|
Int getInt(NameKeyType key, Bool* exists = NULL) const;
|
|
/**
|
|
return the value for the pair with the given key.
|
|
if there is no pair with the given key, or the value is
|
|
not of the correct type, 0 is returned.
|
|
*/
|
|
Real getReal(NameKeyType key, Bool* exists = NULL) const;
|
|
/**
|
|
return the value for the pair with the given key.
|
|
if there is no pair with the given key, or the value is
|
|
not of the correct type, "" is returned.
|
|
*/
|
|
AsciiString getAsciiString(NameKeyType key, Bool* exists = NULL) const;
|
|
/**
|
|
return the value for the pair with the given key.
|
|
if there is no pair with the given key, or the value is
|
|
not of the correct type, "" is returned.
|
|
*/
|
|
UnicodeString getUnicodeString(NameKeyType key, Bool* exists = NULL) const;
|
|
|
|
/**
|
|
return the value for the pair with the given index.
|
|
if the index is out of range, or the value is
|
|
not of the correct type, 0 is returned.
|
|
*/
|
|
Bool getNthBool(Int n) const;
|
|
/**
|
|
return the value for the pair with the given index.
|
|
if the index is out of range, or the value is
|
|
not of the correct type, 0 is returned.
|
|
*/
|
|
Int getNthInt(Int n) const;
|
|
/**
|
|
return the value for the pair with the given index.
|
|
if the index is out of range, or the value is
|
|
not of the correct type, 0 is returned.
|
|
*/
|
|
Real getNthReal(Int n) const;
|
|
/**
|
|
return the value for the pair with the given index.
|
|
if the index is out of range, or the value is
|
|
not of the correct type, "" is returned.
|
|
*/
|
|
AsciiString getNthAsciiString(Int n) const;
|
|
/**
|
|
return the value for the pair with the given index.
|
|
if the index is out of range, or the value is
|
|
not of the correct type, "" is returned.
|
|
*/
|
|
UnicodeString getNthUnicodeString(Int n) const;
|
|
|
|
/**
|
|
set the value for the pair with the given key.
|
|
if no such pair exists, it is created.
|
|
if such a pair exists, it is replaced.
|
|
note that when replacing a pair, the new and old
|
|
data types need not match.
|
|
*/
|
|
void setBool(NameKeyType key, Bool value);
|
|
/**
|
|
set the value for the pair with the given key.
|
|
if no such pair exists, it is created.
|
|
if such a pair exists, it is replaced.
|
|
note that when replacing a pair, the new and old
|
|
data types need not match.
|
|
*/
|
|
void setInt(NameKeyType key, Int value);
|
|
/**
|
|
set the value for the pair with the given key.
|
|
if no such pair exists, it is created.
|
|
if such a pair exists, it is replaced.
|
|
note that when replacing a pair, the new and old
|
|
data types need not match.
|
|
*/
|
|
void setReal(NameKeyType key, Real value);
|
|
/**
|
|
set the value for the pair with the given key.
|
|
if no such pair exists, it is created.
|
|
if such a pair exists, it is replaced.
|
|
note that when replacing a pair, the new and old
|
|
data types need not match.
|
|
*/
|
|
void setAsciiString(NameKeyType key, const AsciiString& value);
|
|
/**
|
|
set the value for the pair with the given key.
|
|
if no such pair exists, it is created.
|
|
if such a pair exists, it is replaced.
|
|
note that when replacing a pair, the new and old
|
|
data types need not match.
|
|
*/
|
|
void setUnicodeString(NameKeyType key, const UnicodeString& value);
|
|
|
|
/**
|
|
remove the pair with the given key. if such a pair existed, return true.
|
|
if no such pair existed, return false.
|
|
*/
|
|
Bool remove(NameKeyType key);
|
|
|
|
/**
|
|
copy the pair with the given key from 'that', replacing any such pair in 'this'.
|
|
if no such pair exists in 'that', any pair with that key will be removed from 'this'.
|
|
*/
|
|
void copyPairFrom(const Dict& that, NameKeyType key);
|
|
|
|
private:
|
|
|
|
struct DictPair;
|
|
struct DictPairData;
|
|
|
|
DictPairData* m_data; // pointer to ref counted Pair data
|
|
|
|
void sortPairs();
|
|
Dict::DictPair *setPrep(NameKeyType key, Dict::DataType type);
|
|
DictPair* findPairByKey(NameKeyType key) const;
|
|
void releaseData();
|
|
DictPair *ensureUnique(int numPairsNeeded, Bool preserveData, DictPair *pairToTranslate);
|
|
|
|
enum DictPairKeyType
|
|
{
|
|
DICTPAIRKEY_ILLEGAL = 0
|
|
};
|
|
|
|
// danger... this is Plain Old Data and allocated in a skanky way;
|
|
// and thus the ctor/dtor for DictPair will never be called. so don't
|
|
// bother writing one.
|
|
struct DictPair
|
|
{
|
|
private:
|
|
DictPairKeyType m_key;
|
|
void* m_value;
|
|
|
|
inline static DictPairKeyType createKey(NameKeyType keyVal, DataType nt)
|
|
{
|
|
return (DictPairKeyType)((((UnsignedInt)(keyVal)) << 8) | ((UnsignedInt)nt));
|
|
}
|
|
|
|
inline static DataType getTypeFromKey(DictPairKeyType nk)
|
|
{
|
|
return (DataType)(((UnsignedInt)nk) & 0xff);
|
|
}
|
|
|
|
inline static NameKeyType getNameFromKey(DictPairKeyType nk)
|
|
{
|
|
return (NameKeyType)(((UnsignedInt)nk) >> 8);
|
|
}
|
|
|
|
|
|
public:
|
|
void clear();
|
|
void copyFrom(DictPair* that);
|
|
void setNameAndType(NameKeyType key, DataType type);
|
|
inline DataType getType() const { return getTypeFromKey(m_key); }
|
|
inline NameKeyType getName() const { return getNameFromKey(m_key); }
|
|
inline Bool* asBool() { return (Bool*)&m_value; }
|
|
inline Int* asInt() { return (Int*)&m_value; }
|
|
inline Real* asReal() { return (Real*)&m_value; }
|
|
inline AsciiString* asAsciiString() { return (AsciiString*)&m_value; }
|
|
inline UnicodeString* asUnicodeString() { return (UnicodeString*)&m_value; }
|
|
};
|
|
|
|
struct DictPairData
|
|
{
|
|
unsigned short m_refCount; // reference count
|
|
unsigned short m_numPairsAllocated; // length of data allocated
|
|
unsigned short m_numPairsUsed; // length of data allocated
|
|
//DictPair m_pairs[];
|
|
|
|
inline DictPair* peek() { return (DictPair*)(this+1); }
|
|
};
|
|
|
|
#ifdef _DEBUG
|
|
void validate() const;
|
|
#else
|
|
inline void validate() const { }
|
|
#endif
|
|
|
|
};
|
|
|
|
// -----------------------------------------------------
|
|
inline Dict::Dict(const Dict& src) : m_data(src.m_data)
|
|
{
|
|
if (m_data)
|
|
++m_data->m_refCount;
|
|
}
|
|
|
|
// -----------------------------------------------------
|
|
inline Dict::~Dict()
|
|
{
|
|
releaseData();
|
|
}
|
|
|
|
// -----------------------------------------------------
|
|
inline Int Dict::getPairCount() const
|
|
{
|
|
return m_data ? m_data->m_numPairsUsed : 0;
|
|
}
|
|
|
|
// -----------------------------------------------------
|
|
inline NameKeyType Dict::getNthKey(Int n) const
|
|
{
|
|
if (!m_data || n < 0 || n >= m_data->m_numPairsUsed)
|
|
return NAMEKEY_INVALID;
|
|
return m_data->peek()[n].getName();
|
|
}
|
|
|
|
// -----------------------------------------------------
|
|
inline Dict::DataType Dict::getNthType(Int n) const
|
|
{
|
|
if (!m_data || n < 0 || n >= m_data->m_numPairsUsed)
|
|
return DICT_NONE;
|
|
return m_data->peek()[n].getType();
|
|
}
|
|
|
|
#endif // Dict_H
|
|
|
|
|