| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .. | ||
| Def.mqh | ||
| Main.mqh | ||
| README.md | ||
Uso de bajo nivel de CFastHashTableBase
Esta guía es solo para quien quiere exprimir el rendimiento al máximo y está
dispuesto a acoplarse al estado interno del algoritmo. Si solo usas la API
normal (Add, TryGet, Contains, Remove(key), etc.) no necesitas leer
esto — este documento describe los miembros públicos "residuales"
(m_i, m_bit_pos, m_last_pos_tbl) que el motor deja expuestos para evitar
un segundo recorrido de la tabla (el clásico patrón find + luego add/replace
hecho en una sola pasada).
Estos tres campos no son un resultado estable: su valor solo tiene sentido inmediatamente después de la llamada que los dejó ahí, y cualquier otra llamada al mismo hashmap los vuelve a pisar (incluida una llamada anidada dentro de la misma expresión). No los guardes para usarlos más tarde.
Los tres campos
| Campo | Qué es |
|---|---|
m_i |
Índice de grupo (grupo de 8 slots) donde terminó la búsqueda. |
m_bit_pos |
Posición dentro del grupo, (multiplo de 8) - 1, en Remove* puede ser multiplo de ((8)-1)-7 |
m_last_pos_tbl |
Índice absoluto y ya resuelto en m_table[]. Es el único que puedes indexar directamente sin más cálculo. |
m_last_pos_tbl existe justamente para que no tengas que calcular nada:
siempre que un método lo garantice actualizado (ver tabla), puedes hacer
m_table[m_last_pos_tbl] directo. m_i y m_bit_pos son el detalle interno
que lo construye, expuestos solo para casos muy puntuales de bajo nivel
(por ejemplo, Remove los reutiliza sin tener que rebuscar la key).
Qué deja cada método, exactamente
| Método | Retorno | m_i |
m_bit_pos |
m_last_pos_tbl |
|---|---|---|---|---|
ReserveSlot(key) |
false (ya existía) |
grupo del slot existente | (sin uso) | posición exacta de la key existente |
ReserveSlot(key) |
true (no existía, se reservó) |
grupo del slot nuevo | (sin uso) | posición del slot recién reservado (sin key todavía escrita — eso te toca a ti) |
ContainsKey(key) / ContainsKeyByHash(hash) |
true |
grupo del match | bit-pos (múltiplo de 8, +7 → 7,15,23…63) posicion inicial del grupo en bit | posición exacta del match |
ContainsKey(key) / ContainsKeyByHash(hash) |
false |
último grupo probado | ultima posicion probada en grupo | sin significado |
Remove(key) |
true |
igual que el ContainsKey interno que usa |
Mismo valor que ContainsKey - 7 |
posición exacta del match (true) |
Remove(key) |
false |
último grupo probado | ultima posicion probada en grupo | sin significado |
RemoveLastFindCall() |
— | usa el m_i/m_bit_pos que haya dejado la llamada previa a ContainsKey/ContainsKeyByHash |
Valor reducido en 7 | — |
Patrón recomendado (find-or-insert en una sola pasada)
if(!hashmap.ReserveSlot(key))
{
// Ya existía → reemplazar/leer directo, sin recalcular nada
hashmap.m_table[hashmap.m_last_pos_tbl].value = nuevo_valor;
}
else
{
// No existía → el slot ya está reservado, solo falta llenar key/value
hashmap.m_table[hashmap.m_last_pos_tbl].key = key;
hashmap.m_table[hashmap.m_last_pos_tbl].value = nuevo_valor;
}
Este es el patrón que usan CDomNodeBase::Set() y operator[] en
BasesParserSLan para evitar
un Find + Add por separado.
Advertencia sobre re-entrancia
Estos campos son miembros de instancia, no valores locales por-llamada.
Si entre que guardas la intención de usarlos y realmente los usas se cuela
cualquier otra llamada al mismo hashmap (otro ReserveSlot, ContainsKey,
Remove, o un Reserve/Rehash disparado internamente por estar cerca del
límite de resize), el valor queda pisado. Usa siempre m_last_pos_tbl
inmediatamente después de la llamada que lo dejó, nunca lo arrastres a través
de otra operación sobre el mismo objeto.