Basic Types

Primitive types

The following table lists all primitive typed designed by Luna SDK.

Type Description C++ STD Equivalent
u8 Unsigned 8-bit integer. std::uint8_t
i8 Signed 8-bit integer. std::int8_t
u16 Unsigned 16-bit integer. std::uint16_t
i16 Signed 16-bit integer. std::int16_t
u32 Unsigned 32-bit integer. std::uint32_t
i32 Signed 32-bit integer. std::int32_t
u64 Unsigned 64-bit integer. std::uint64_t
i64 Signed 64-bit integer. std::int64_t
usize Unsigned machine-sized integer. std::size_t
isize Signed machine-sized integer. std::ptrdiff_t
f32 32-bit floating-point number. float
f64 64-bit floating-point number. double
c8 8-bit character. char
c16 16-bit character. chat16_t
c32 32-bit character. char32_t

Aliasing types of primitive types

byte_t is an aliasing type of u8 that indicates one byte. You should use byte_t instead of u8 if you want to be clear that you are talking about bytes, not numbers, for example, in a binary stream (byte_t*).

opaque_t is an aliasing type of void* that indicated one opaque pointer that should not be dereferenced by the user. Such pointers are usually used as handles to internal data structures, the user should pass opaque_t to functions provided by the system to manipulate it.

InitializerList<T> is an aliasing type of std::initializer_list<_Ty>in Luna SDK.

VarList is an aliasing type of va_list in Luna SDK.

Containers

#include <Luna/Runtime/Vector.hpp>
#include <Luna/Runtime/List.hpp>
#include <Luna/Runtime/HashMap.hpp>
#include <Luna/Runtime/HashSet.hpp>
#include <Luna/Runtime/UnorderedMap.hpp>
#include <Luna/Runtime/UnorderedSet.hpp>
#include <Luna/Runtime/UnorderedMultiMap.hpp>
#include <Luna/Runtime/UnorderedMultiSet.hpp>
#include <Luna/Runtime/SelfIndexedHashMap.hpp>
#include <Luna/Runtime/SelfIndexedUnorderedMap.hpp>
#include <Luna/Runtime/SelfIndexedUnorderedMultiMap.hpp>
#include <Luna/Runtime/RingDeque.hpp>

For compatibility and cross-platform consistency reasons, Luna SDK does not use C++ Standard Template Library (STD), but implements its own container types using APIs similar to those of STD. The following table lists all containers provided by Luna SDK.

Container Type Description C++ STD Equivalent
Vector<T> Dynamic array type. std::vector<T>
List<T> Dynamic double-linked list type. std::list<T>
HashMap<K, V> Closed hash map type using Robinhood Hashing. N/A
HashSet<V> Closed hash set type using Robinhood Hashing. N/A
UnorderedMap<K, V> Open hash map type. std::unordered_map<K, V>
UnorderedSet<V> Open hash set type. std::unordered_set<V>
UnorderedMultiMap<K, V> Open hash map type that allows elements with the same key. std::unordered_multimap<K, V>
UnorderedMultiSet<V> Open hash map type that allows multiple insertions of the same elements. std::unordered_multiset<K, V>
SelfIndexedHashMap<K, V, E> Closed hash map whose key type can be extracted from the value type. N/A
SelfIndexedUnorderedMap<K, V, E> Open hash map whose key type can be extracted from the value type. N/A
SelfIndexedUnorderedMultiMap<K, V, E> Open hash map whose key type can be extracted from the value type, and allows multiple insertions of the same elements. N/A
RingDeque<T> Double-ended queue using ring buffering. std::deque<T>

Self indexed map containers

Self indexed map containers are used for elements whose key is a part of the value object. For example, given the following structure:

struct Player
{
    Name name;
    i32 hp;
    i32 mp;
};

Now we want to use one map to store all player records using their name as the key. If we use normal HashMap or UnorderedMap container, every entry in the container will be saved as Pair<const Name, Player>, thus stores the player name twice. In such case, we can use SelfIndexedHashMap and SelfIndexedUnorderedMap instead. The self indexed hash map container does not store the key object directly, instead, it requires the user to provide a special functional object E, which will be called when the key is needed. The functional object E takes a reference to the value object of the map element, and should returns a value or reference to the key object of the element. In our example, we can implement E as below:

struct PlayerExtractKey
{
    const Name& operator()(const Player& val) const
    {
        return val.name;
    }
};

Then we can define the self indexed map like so:

#include <Luna/Runtime/SelfIndexedHashMap.hpp>

namespace Luna
{
    SelfIndexedHashMap<Name, Player, PlayerExtractKey> players;
}

When using self indexed map containers, the user must ensure that the key object is immutable for all elements in the container, or the behavior is undefined.

BLOB

#include <Luna/Runtime/Blob.hpp>

BLOB refers to Binary Large OBject, which is a memory block with arbitrary data. In Luna SDK, we use Blob structure to represent one BLOB object. Blob can be used in many ways, but the common use for it is to store and transfer binary data. For example, load_file_data function returns a Blob object, which contains the data of the file.

Span

#include <Luna/Runtime/Span.hpp>

Span is a template type that refers to one continuous sequence of instances. There are two types of spans in Luna SDK: fixed span and variable span.

Fixed spans are spans whose size is decided at compile time, and cannot be changed. Such span only requires one pointer to the object range to be well defined, and the number of elements in the span should be declared as part of the type:

i32 data[] = {3, 4, 5, 6, 7};

Span<i32, 3> range(data + 1);
debug_printf("%d", range.size()); // 3
for (i32 i : range) debug_printf("%d, ", i); // 4, 5, 6,

range = Span<i32, 3>(data + 2);
debug_printf("%d", range.size()); // 3
for (i32 i : range) debug_printf("%d, ", i); // 5, 6, 7,

Variable spans are spans whose size may change at run time. Such span requires both the pointer to the object range and the size of the range to be well defined:

i32 data[] = {3, 4, 5, 6, 7};

Span<i32> range(data + 1), 3;
debug_printf("%d", range.size()); // 3
for (i32 i : range) debug_printf("%d, ", i); // 4, 5, 6, 

range = Span<i32>(data + 2, 2);
debug_printf("%d", range.size()); // 2
for (i32 i : range) debug_printf("%d, ", i); // 5, 6, 

Note that spans are NOT containers, they don't allocate memory to store the data, only stores pointers to the objects provided by the user. So use spans only when the original object sequence is valid.

Prefer using Span<T> instead of C-style pointer and size pair when referring memory ranges.

GUID

#include <Luna/Runtime/Base.hpp>

Globally Unique Identifier (GUID) is a algorithm-generated 128-bit integer identifier. In Luna SDK, GUIDs are represented by Guid type:

struct Guid
{
    u64 high;
    u64 low;
};

Luna SDK supports generating GUID instances from the registry form (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx or {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}) at compile time:

constexpr Guid test_id("{5cf28858-60b0-49f2-9674-5888fa7ad027}");
static_assert(test_id.low == 10841387548328775719Ui64, "Incorrect GUID values.");
static_assert(test_id.high == 6697565509014014450Ui64, "Incorrect GUID values.");

GUIDs are used widely in Luna SDK for identifying assets, types, interfaces, objects and many other entities.

Version type

#include <Luna/Runtime/Base.hpp>

Version represent the version of one application, module or any version-controlled entity. Every version is composed by three numbers: major, minor and patch:

struct Version
{
    u32 major;
    u32 minor;
    u32 patch;
};

We suggest using the following rules to manage the version number:

  1. An increment of major version indicates a breaking change to the interface of the entity, so that existing codes, programs and services using the entity must be explicitly modified to use the newer version of the entity correctly.
  2. An increment of minor version indicates a non-breaking change to the interface of the entity, so that existing codes, programs and services can use the newer version of the entity correctly without any source-level modification.
  3. An increment of patch version indicates a internal change of the entity and should not affect the entity interface, so that existing codes, programs and services can use the newer version of the entity correctly without any source-level modification.

Pair and tuple types

#include <Luna/Runtime/Base.hpp> // For Pair.
#include <Luna/Runtime/Tuple.hpp> // For Tuple.

Pair<T1, T2> encapsulates one pair of elements with T1 and T2 type as the first and second element of the pair. Pair is mainly used by map containers to represent elements.

Tuple<Tys...> is a generalization of Pair and may contain one or multiple elements. Elements in Tuple can be fetched by calling get<N>(tuple) function. This type is mainly used to store function arguments in functional programming.

Path

#include <Luna/Runtime/Path.hpp>

Path is one kind of string that describes the location of one node in a hierarchical-based node tree, given that each node in the tree can be identified by a name string. One common use of Path is to represent the location of one file or directory in the file system.

Path is represented by a root name (like C:), plus a Vector of Name that stores nodes of the path. One path can be absolute or relative, which is identified by PathFlag::absolute. One relative path can be calculated by two paths, it can also be appended to another path to create a new path. Path can be created form one string, it can also be encoded to one string using the user-specified path separator.