NoesisGUI

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
© 2017 Noesis Technologies