Заказать игровой сервер Контакты (заказать плагин/исправить ошибки/другое) Пожертвовать Поиск

[ вход ]
[ последние сообщения ]

  • Страница 1 из 1
  • 1
adt_trie.inc StringMap
_wS_ Дата: Воскресенье, 13.05.2012, 18:49:44 | Сообщение # 1
Класс: StringMap (adt_trie.inc)
https://sm.alliedmods.net/new-api/adt_trie/StringMap

Позволяет хранить разные типы данных по уникальным ключам-строкам, например, "zx".
Ключ "zx" и "Zx" это разные ключи.
Символы в имени ключа могут быть любыми, SourceMod запустит цикл по каждому из них, чтобы преобразовать ключ-строку в unsigned int хэш.

Для хранения строк StringMap подходит лучше, чем ArrayList, т.к. хранит строку такой, какая она есть.
ArrayList же каждому элементу выделяет одинаковое количество байтов.
Поиск в StringMap работает намного быстрее, чем в ArrayList.

Создать StringMap объект. Уничтожьте, если больше не нужен: delete map

Код
StringMap map = new StringMap();


Создать точно такой же StringMap объект-копию, который никак не связан с оригиналом.
Требуется SourceMod 1.11+

Код
StringMap map_clone = map.Clone();


Добавить/изменить значение.
Если replace false и key уже существует, то значение перезаписано не будет и вернёт false.
Значением может быть int/bool/float/Handle.

Код
bool map.SetValue(const char[] key, any value, bool replace=true);


Добавить/изменить массив. Можно использовать и структуры (enum struct).

Код
bool map.SetArray(const char[] key, const any[] array, int num_items, bool replace=true);


Добавить/изменить строку:

Код
bool map.SetString(const char[] key, const char[] value, bool replace=true);


Получить данные. size = сколько байтов записано в буфер. Например, для строки "t" вернёт 1, а для "т" 2.

Код
bool map.GetValue(const char[] key, any &value);
bool map.GetArray(const char[] key, any[] array, int max_size, int &size=0);
bool map.GetString(const char[] key, char[] value, int max_size, int &size=0);


Удалить ключ:

Код
bool map.Remove(const char[] key);


Удалить все ключи:

Код
void map.Clear();


Получить количество всех ключей:

Код
int map.Size


Получить список всех ключей (их имена).
Этот список (snapshot) никак не связан с map, и его нужно уничтожить (delete), когда он не нужен.
Если удалить ключ из map, или уничтожить map, то snapshot остаётся прежним.

Код
StringMapSnapshot snapshot = map.Snapshot();


Количество ключей в snapshot:

Код
int snapshot.Length


Возвращает размер буфера, необходимый для хранения данного ключа (длина ключа + 1).
char[] buffer = new char[размер];
index - позиция ключа от 0 до snapshot.Length - 1

Код
int snapshot.KeyBufferSize(int index);


Получить имя ключа по его позиции (index).
По идее ключи упорядочены в случайном порядке и не стоит ожидать какого-то конкретного порядка.
Возвращает количество байтов, записанных в буфер.

Код
int snapshot.GetKey(int index, char[] buffer, int maxlength);


Примеры:

Код
enum struct Test
{
    int number;
    char name[4];
}

public void OnPluginStart()
{
    StringMap map = new StringMap();
    
    // Записываем данные:
    
    map.SetValue("hp", 150);
    
    if (!map.SetValue("hp", 200, false)) {
        PrintToServer("Ключ \"hp\" уже существует");
    }
    
    map.SetArray("rgb", {255, 100, 200}, 3);
    
    Test t;
    t.number = 12345;
    strcopy(t.name, sizeof(t.name), "Cat");
    map.SetArray("test", t, sizeof(t));
    
    map.SetString("game", "CS:S");
    
    // Получаем записанные данные:
    
    int hp;
    if (map.GetValue("hp", hp)) {
        PrintToServer("hp = %d", hp); // hp = 150
    }
    
    int rgb[3];
    if (map.GetArray("rgb", rgb, sizeof(rgb))) {
        PrintToServer("rgb = %d %d %d", rgb[0], rgb[1], rgb[2]); // rgb = 255 100 200
    }
    
    t.number  = 0;
    t.name[0] = 0;
    if (map.GetArray("test", t, sizeof(t))) {
        PrintToServer("Test::number = %d, Test::name = %s", t.number, t.name); // Test::number = 12345, Test::name = Cat
    }
    
    // Если нужно получить не весь элемент, а определённое кол-во первых ячеек:
    any a[1];
    if (map.GetArray("test", a, sizeof(a))) {
        PrintToServer("Test::number = %d", a[0]); // Test::number = 12345
    }
    
    int bytes;
    char game[16];
    if (map.GetString("game", game, sizeof(game), bytes)) {
        PrintToServer("game = %s, bytes = %d", game, bytes); // game = CS:S, bytes = 4
    }
    
    PrintToServer("Ключей в map: %d", map.Size); // Ключей в map: 4
    
    if (map.Remove("hp")) {
        PrintToServer("Ключ \"hp\" удалён. Осталось ключей: %d", map.Size); // Ключ "hp" удалён. Осталось ключей: 3
    }
    
    StringMapSnapshot snapshot = map.Snapshot();
    if (snapshot)
    {
        int snapshotLength = snapshot.Length;
        PrintToServer("snapshot.Length = %d", snapshotLength); // snapshot.Length = 3
        
        for (int index = 0, keyBufferSize; index < snapshotLength; index++)
        {
            keyBufferSize = snapshot.KeyBufferSize(index);
            char[] key = new char[keyBufferSize];
            
            bytes = snapshot.GetKey(index, key, keyBufferSize);
            
            PrintToServer("Ключ: \"%s\", keyBufferSize: %d, bytes = %d.",
                key, keyBufferSize, bytes);

            // Ключ: "test", keyBufferSize: 5, bytes = 4.
            // Ключ: "game", keyBufferSize: 5, bytes = 4.
            // Ключ: "rgb" , keyBufferSize: 4, bytes = 3.
        }
        
        // Не забываем уничтожать.
        delete snapshot;
    }
    
    // Раз map уже совсем не нужен, уничтожаем.
    delete map;
}


Если map содержит ключи с разными типами данных, то в StringMapSnapshot можно столкнуться с проблемой.
SourceMod API не позволяет определить тип данных, у нас есть только имя ключа.
Если попытаться получить/перезаписать один тип данных на другой, то скорее всего будет ошибка.
Поэтому, нужно или имена ключей сравнивать, или где-то хранить инфу о типе, или использовать несколько StringMap под каждый тип.


Сообщение отредактировал _wS_ - Вторник, 14.12.2021, 05:43:33
 
  • Страница 1 из 1
  • 1
Поиск: