Strings and Symbols
Two kinds of strings are supported in Noesis (both declared in the header for Noesis Types, NsCore/Types.h):
- C strings: arrays of chars using NsChar type
- C++ strings: stl strings using NsString
By default, string types default to unicode or multybyte as defined in the current configuration file. For specific character usage there are defined types: NsChar8, NsChar16, NsString8 and NsString16.
To generate code that is compatible with both unicode and multybyte builds, the macro NST must be used to enclose text declared in the source. For example:
NsString value(NST("A sample String"));
Simple chars should be inside NST too:
if (c >= NST('A') && c <= NST('Z'))
{
return c + NST('a') - NST('A');
}
NsChar vs NsString
NsChar is used as input and output to functions to avoid moving memory when it is not necessary. NsString are used as class members. The following is an example showing this use of both types:
class Name
{
public:
void SetName(const NsChar* name)
{
mName = name;
}
const NsChar* GetName() const
{
return mName.c_str();
}
private:
NsString mName;
};
NsChar functions
Standard C string functions (strcpy, strcmp) should be avoided. The functions declared in NsCore/String.h should be used instead. These functions are:
- Overloaded for Unicode/MultiByte
- Safer that standard functions. For example, they force you to give a size for destination buffers. They avoid writing past the limits of the buffers.
- Platform independant. These functions can be used in all the platforms where Noesis can be compiled.
Function | Description |
---|---|
ToString16() | Converts from NsChar8/NsChar16/String8/String16 to NsString16 |
ToString8() | Converts from NsChar8/NsChar16/String8/String16 to NsString8 |
ToString() | Converts from NsChar8/NsChar16/String8/String16 to NsString |
ToChar16() | Converts from NsChar8/NsChar16/String8/String16 to NsChar16 |
ToChar8() | Converts from NsChar8/NsChar16/String8/String16 to NsChar8 |
ToChar() | Converts from NsChar8/NsChar16/String8/String16 to NsChar |
IsNullOrEmpty() | Indicates whether the specified string is null or an empty string |
Length() | Gets the number of characters in this string |
Compare() | Compares two strings or substrings ignoring or honoring their case |
CompareFirst() | Compares the first characters in two strings ignoring or honoring their case |
StartsWith() | Determines whether the beginning of a string matches the specified string |
EndsWith() | Determines whether the end of a string matches the specified string |
FindFirst() | Reports the index of the first occurrence of the specified string in a string. The search starts at a specified character position and examines a specified number of character positions |
FindLast() | Reports the index of the last occurrence of the specified string in a string. The search starts at a specified character position and examines a specified number of character positions |
Copy() | Copies a specified number of characters of a specified string to an existing string until its capacity is reached |
Append() | Appends a specified number of characters of a specified string to an existing string until its capacity is reached |
Replace() | Replaces all occurrences of a specified string, with another specified string |
Format() | Formats a NsString using printf-like format |
Printf() | Write formatted data to the standard output stream or to a string |
PrintfArgs() | Write formatted data to a string using a pointer to a list of arguments |
ToLower() | Converts, in place, any uppercase letters in a string to lowercase |
ToUpper() | Converts, in place, any uppercase letters in a string to uppercase |
Trim() | Removes all occurrences of a set of characters from the beginning and/or end of a string |
Hash() | Calculate the hash value of a string. This function is case-sensitive |
IHash() | Calculate the case-insensitive hash value of a string |
ToInteger() | Conversion of text to integer |
ToFloat() | Conversion of text to float |
ToBool() | Conversion of text to boolean |
IsAlpha() | Checking for an alphabetic character |
IsAlphaNum() | Checking for an alphanumeric character |
IsDigit() | Checking for a decimal-digit character |
Symbols
Symbols is a term used in Noesis Engine for referring to inmutable strings that are stored in a symbol table and identified by an index to that table. Once a symbol is added to the table it remains there until the end of the program. Symbols are used in Noesis to represent strings defined at compile time.
As the implementation of a symbol is an index, the comparison between symbols is extremely efficient. When several symbols refer to the same string only one string is stored in the symbol table.
Symbols are Case-Insensitive, but it's recommended that the Upper Mixed Case naming scheme described in the Coding Style Guide is used, specially for symbols that will be converted back to strings for visualization (for example, profiling marks).
The macros NS_DECLARE_SYMBOL and NSS allows for easily using symbols in a efficient way:
////////////////////////////////////////////////////////////////////////////////////////////////////
NS_DECLARE_SYMBOL(GameTopPanel)
////////////////////////////////////////////////////////////////////////////////////////////////////
void BaseGame::Init()
{
// cache important UI elements
Ptr<INameScope> nameScope = mGamePanel;
// game top panel
mTopPanel = nameScope->FindName(NSS(GameTopPanel));
NS_ASSERT(mTopPanel);
}
Watching symbols in the debugger
For converting symbol ids to strings and vice versa the functions NsSymbolToString and NsStringToSymbol can be pasted into the Watch window using the following syntax:
{,,Debug.Core.Kernel.dll}NsSymbolToString(1146)
{,,Debug.Core.Kernel.dll}NsStringToSymbol(L"DiskFileSystem")
Watching symbols in the console
Each symbol created is logged to the console in a symbol section for debugging purposes.
Note on symbols efficiency
The pair of macros NS_DECLARE_SYMBOL and NSS use a static to hold the symbol. This implies that:
- If you use lots of symbols, code bloat could appear
- The use of the NSS macro implies and if before accessing the symbol to check if it has been initialized. Most of the times this has zero impact in the performance but it is useful to know what is going on under that macros.
When to use Symbols
It is a good idea to use symbols in this situation:
- When the strings are created and not destroyed until finishing the application
- When those strings are used as the key in a container
- When you are going to compare those strings