Portal SAMP
[Tutorial] Economia de memória para grandes Strings - Versão de Impressão

+- Portal SAMP (https://portalsamp.com)
+-- Fórum: SA-MP (https://portalsamp.com/forumdisplay.php?fid=5)
+--- Fórum: Guias e Tutoriais (https://portalsamp.com/forumdisplay.php?fid=7)
+--- Tópico: [Tutorial] Economia de memória para grandes Strings (/showthread.php?tid=822)



Economia de memória para grandes Strings - Levi.M - 28/02/2021

Este é um tutorial simples e rápido para você compreender algumas coisas básicas sobre declaração de vars/arrays em Pawn (1) e como economizar memória com isso (2).

Vou passar rápido no tópico 1 (declaração de vars/arrays em Pawn) e me estender no tópico 2.
Coisas que você precisa saber para entender este tópico:

- Basicamente, todas as variáveis declaradas em Pawn (seja new, seja static) alocarão 32 bits (4 bytes ou 4B) p/cell.
- Cells são representadas por colchetes var[0] e bytes por chaves var{0}.
- Todo caractere da table ASCII (inclusive os especiais) compreendem nos decimais que vão de 0 a 255
- 8 bits podem armazenar um número de 0 a 255.

Logo podemos concluir que: 8 bits (1B) são suficientes para armazenar qualquer caractere (inclusive os especiais).
Sendo assim, a maneira mais eficiente de armazenar uma mensagem dentro de uma string não é inserindo um caractere por cell (4B), e sim um caractere por byte, ou seja, 4 caracteres por cell.



Como faremos isso?

Fácil, use ' ! ' antes de declarar uma String.

Ao invés de:
Código PHP:
new String[16] = "Tutorial Maroto"

Use:
Código PHP:
new String[4] = !"Tutorial Maroto"

Isso faz com que você economize 12 Bytes de um total de 16 (75%). Imagine fazer isso para um servidor inteiro, a memória cai muito.
Enfim, tudo tem seus prós e contras. O nome desse tipo de string, de acordo com Pawn, é packed strings (mensagens compactadas), em que, realmente, alocam uma quantia menor de memória, mas não é possível que você use a função 'format' com elas, o que ferra tudo, porque são muito poucas as strings em um servidor que não passem por um format.vou mostrar uma alternativa.

Existe um comando que por aí em GameModes chamado /Cores, que basicamente faz com que uma dialog MSGBOX apareça na tela do player com as 256 cores de veículos, cada cor com seu respectivo número, tipo isso:


Mas pensa bem, se você for armazenar as 3072 caracteres que tem aí dentro (não é um palpite, têm exatos 3072 caracteres), você teria que fazer algo mais ou menos assim:
Código PHP:
if(!strcmp(cmd"/cores"true))
    {
         new 
color_list[3072];

    
    for (new coloridcolorid != sizeof gVehicleColorscolorid++)
    
    {
    
        format(color_listsizeof color_list"%s{%06x}%03d%s"color_listgVehicleColors[colorid] >>> 8colorid, !((colorid 1) % 16) ? ("\n") : (" "));
    
    }
    
    ShowPlayerDialog(playerid1DIALOG_STYLE_MSGBOX"Color List"color_list"Close""");
    
    return 1;
    } 

Sim, declarar uma string de 3072 cells, quero dizer 12.288bytes, exatos 12 KILOBYTES.
Será se conseguimos diminuir para 3 KB? diminuir em 75%? Não exatamente, mas conseguimos diminuir muito a memória alocada, e é agora que começa o tutorial.

 Já que são 3072 caracteres, precisamos de apenas 768 cells (3072/4). Começamos por aí.
Além disso, vamos ter que criar outra array para armazenar a string que será formatada (usaremos 14 cells).
Por último, usaremos uma função.
Código PHP:
if(!strcmp(cmd"/Cores"true)) {
        new 
Result[768]; // Os 3072 caracteres do resultado final
        
new String[14];     // Os 14 caracteres que serão formatados a cada looping
        
for(new i!= 256; ++i) { // 256 cores
            
format(String14"{%06x}%03i%s", (VehicleColors[i] >>> 8), i, (((i+1) % 16) ? (" ") : ("\n"))); // Não precisa entender isso, apenas que fique claro que estamos usando format
            
strpack(StringString); // compactando as 14 cells em 14 bytes (que fique claro que a array String NÃO diminuiu de tamanho, apenas a informação foi compactada)
            
strpackcat(ResultString); // juntando a array Result com a array String (formatada e depois compactada)
        
// Depois do processo ter terminado, a array Result estará prontinha para uso
        
ShowPlayerDialog(playeridDIALOG_NOANSDIALOG_STYLE_MSGBOX"Cores"Result"Ok""");
        return 
1;
    } 


a stock strpackcat (que basicamente concatena 2 packed strings, como se fosse strcat só que de packed strings):
Código PHP:
stock strpackcat(dest[], const source[], maxlength=sizeof(dest)) {
    if(
dest{3}) { if(!dest{0}) { print("JBScript [strpackcat] ERROR: The destiny string must be already packed before using this function."); return 0; } }
    if(
source{3}) { if(!source{0}) { print("JBScript [strpackcat] ERROR: The source string must be already packed before using this function."); return 0; } }
    new 
dl strlen(dest), sl strlen(source);
    
maxlength *= 4;
    if(
maxlength dl) { print("JBScript [strpackcat] ERROR: The maxlength is lesser then destiny string length."); return 0; }
    if(
maxlength sl+dl) { sl maxlength-dl; }
    for(new 
i!= sl; ++i) { dest{dl+i} = source{i}; }
    return 
1;


Bom, o tutorial é basicamente isso, não tão útil até porque nem sempre criamos uma array assim tão grande. É mais usado nesses casos (raros) mesmo.

Algumas coisas eu não falei durante o tutorial pois não é o foco (já que devem existir outros tutoriais sobre os detalhes que eu deixei de falar, como o uso de 'char', que basicamente retorna o número de cells que são necessárias para armazenar x caracteres, etc).


Créditos ao JohnBlack.