LEB128

LEB128 o Little Endian Base 128, es una compresión de código de longitud variable que se utiliza para almacenar números enteros arbitrariamente largas en un …

LEB128

LEB128 o Little Endian Base 128, es una compresión de código de longitud variable que se utiliza para almacenar números enteros arbitrariamente largas en un número reducido de bytes. Se utiliza en el formato de archivo de depuración DWARF[1][2]​ y en la codificación binaria WebAssembly para todos los literales enteros.[3]

Formato de codificación

El formato LEB128 es muy similar al formato de cantidad de longitud variable (VLQ). La principal diferencia radica en que LEB128 es little-endian, mientras que las cantidades de longitud variable son big-endian. Ambos permiten almacenar números pequeños en un solo byte, además de codificar números de longitud arbitraria. Existen dos versiones de LEB128: LEB128 sin signo y LEB128 con signo. El decodificador debe saber si el valor codificado es LEB128 sin signo o con signo.

LEB128 sin signo

Para codificar un número sin signo usando LEB128 sin signo (ULEB128) primero se debe representar el número en binario. Luego, se convierte el número a un múltiplo de 7 bits mediante extensión de ceros(de modo que si el número no es cero, los 7 bits más significativos no sean todos 0). Divide el número en grupos de 7 bits. Genera un byte codificado por cada grupo de 7 bits, desde el menos significativo hasta el más significativo. Cada byte contendrá el grupo en sus 7 bits menos significativos. Establece el bit más significativo en cada byte, excepto en el último. El número cero se suele codificar como un solo byte 0x00. WebAssembly permite codificaciones alternativas para el cero (0x80 0x00, 0x80 0x80 0x00, ...).[3]

Como ejemplo, así se codifica el número sin signo 624485:

MSB ------------------ LSB
10011000011101100101 En binario puro
010011000011101100101 Rellenado a un múltiplo de 7 bits
0100110 0001110 1100101 Dividido en grupos de 7 bits
00100110 10001110 11100101 Se suman los bits 1 más significativos a todos los grupos excepto al último (el más significativo) para formar bytes
0x26 0x8E 0xE5 En hexadecimal
→ 0xE5 0x8E 0x26 Flujo de salida (LSB a MSB)

Los formatos LEB128 sin signo y VLQ (cantidad de longitud variable) comprimen cualquier entero dado no solo en la misma cantidad de bits, sino exactamente en los mismos bits; ambos formatos difieren únicamente en la disposición de dichos bits.

LEB128 con signo

Un número con signo se representa de forma similar: comenzando con Una representación de bits complemento a dos, donde es un múltiplo de 7, divide el número en grupos como en la codificación sin signo.

Por ejemplo, el número con signo -123456 se codifica como 0xC0 0xBB 0x78:

MSB ------------------ LSB
11110001001000000 Codificación binaria de 123456
000011110001001000000 Como un número de 21 bits
111100001110110111111 Negación de todos los bits (complemento a uno)
11110000111011100000 Sumando uno (complemento a dos)
1111000 0111011 1.000.000 Dividir en grupos de 7 bits
01111000 10111011 11000000 Sumar los bits 1 más significativos a todos los grupos excepto al último (el más significativo) para formar bytes
0x78 0xBB 0xC0 En hexadecimal
→ 0xC0 0xBB 0x78 Flujo de salida (LSB a MSB)

Decodificación rápida

Una implementación escalar sencilla de la decodificación LEB128 es bastante lenta, más aún en hardware moderno donde la predicción errónea de ramas es relativamente costosa. Una serie de artículos presenta técnicas SIMD para acelerar la decodificación (en estos artículos se llama VByte, pero es otro nombre para la misma codificación [cita requerida]). El documento[4]​ "Vectorized VByte Decoding" presentó "Masked VByte", que demostró velocidades de 6502700 millones de enteros por segundo en hardware básico Haswell, dependiendo de la densidad de codificación.

Un artículo de seguimiento presentó una variante de codificación, "Stream VByte: Faster Byte Oriented Integer Compression",[5]​ que aumentó las velocidades a más de 4 mil millones de enteros por segundo. Esta codificación de flujo separa el flujo de control de los datos codificados, por lo que no es compatible binariamente con LEB128.

Pseudocódigo tipo C

Codificar entero sin signo

do {
  byte= value & 0x7f; /* low-order 7 bits of value */
  value >>= 7;
  if (value != 0) /* more bytes to come */
    byte|= 0x80; /* set high-order bit of byte */
  emit(byte);
} while (value != 0);

Codificar entero con signo

more= 1;
negative= (value < 0);

/* the size in bits of the variable "value", e.g., 64 if value's type is int64_t */
size= sizeof(value) * CHAR_BITS; /* no. of bits in signed integer */

while (more) {
  byte= value & 0x7f; /* low-order 7 bits of value */
  value >>= 7;
  /* the following is only necessary if the implementation of >>= uses a
     logical shift rather than an arithmetic shift for a signed left operand
     this does not happen on most programming languages if "value" is in a signed type to begin with */
  if (negative)
    value|= (~0 << (size - 7)); /* sign extend */

  /* sign bit of byte is second high-order bit (0x40) */
  sign_bit= byte & 0x40;
  if ((value== 0 && sign_bit== 0)||(value== -1 && sign_bit != 0))
    more= 0;
  else
    byte|= 0x80; /* set high-order bit of byte */
  emit(byte);
}

Decodificar entero sin signo

result= 0;
shift= 0;
unsigned char byte;
do {
  byte= get_next_byte_in_input();
  result|= (byte & 0x7f) << shift; /* low-order 7 bits of byte */
  shift += 7;
} while ((byte & 0x80) != 0); /* get high-order bit of byte */

Decodificar entero con signo

result= 0;
shift= 0;

/* the size in bits of the result variable, e.g., 64 if result's type is int64_t */
size= sizeof(result) * CHAR_BITS; /* no. of bits in signed integer */

/* will be assigned inside the do-while loop, but referenced afterwards */
unsigned char byte;

do {
  byte= get_next_byte_in_input();
  result|= (byte & 0x7f) << shift; /* low-order 7 bits of byte */
  shift += 7;
} while ((byte & 0x80) != 0); /* get high-order bit of byte */

/* sign bit of byte is second high-order bit (0x40) */
if ((shift < size) && ((byte & 0x40) != 0))
  /* sign extend */
  result|= (~0 << shift);

Código en JavaScript

Codificar entero grande con signo

const encodeSignedLeb128FromBigInt= (value)=> {
  value= BigInt(value);
  const result= [];
  while (true) {
    const byte_= Number(value & 0x7fn);
    value >>= 7n;
    if (
      (value=== 0n && (byte_ & 0x40)=== 0)||
      (value=== -1n && (byte_ & 0x40) !== 0)
    ) {
      result.push(byte_);
      return result;
    }
    result.push(byte_|0x80);
  }
};

Decodificar entero grande con signo

const decodeSignedBigInt= (input)=> {
  let result= 0n;
  let shift= 0;
  while (true) {
    const byte= input.shift();
    result|= BigInt((byte & 0x7f) << shift);
    shift += 7;
    if ((byte & 0x80)=== 0) {
      // "sign-extending" does not apply to bigint because it has no fixed size
      // instead, we work by handling it as a two's complement of "shift" bits long,
      // which is provided by BigInt.asIntN
      return BigInt.asIntN(shift, result);
    }
  }
};

Aplicaciones

  • El proyecto Android utiliza LEB128 en su formato de archivo ejecutable Dalvik (.dex).[6]
  • Compresión de tablas en Hewlett-Packard IA-64 para el manejo de excepciones.[7]
  • El formato de archivo DWARF utiliza codificación LEB128 con y sin signo para diversos campos.[2]
  • LLVM, en su formato de mapeo de cobertura[8]​ la implementación de codificación y decodificación LEB128 de LLVM resulta útil junto con pseudocódigo mencionado anteriormente.[9]
  • .NET Core admite un formato de "entero codificado de 7 bits" en las clases BinaryReader y BinaryWriter.[10]​ Al escribir una cadena en un BinaryWriter, la longitud de la cadena se codifica con este método.
  • Minecraft utiliza LEB128 en su protocolo para medir la longitud de los datos dentro de los paquetes.[11]
  • La herramienta de depuración mpatrol utiliza LEB128 en su formato de archivo de rastreo.[12]
  • osu! utiliza LEB128 en su formato de repetición de osu! (.osr).[13]
  • W3C Efficient XML Interchange (EXI) representa enteros sin signo utilizando LEB128, exactamente de la misma manera que se describe aquí.[14]
  • WebAssembly, en su codificación binaria portátil de los módulos.[3]
  • En xZ Utils[15]

Codificaciones relacionadas

  • Codificación de enteros de longitud variable de Dlugosz (original) utiliza múltiplos de 7 bits para los tres primeros intervalos de tamaño, pero a partir de ahí los incrementos varían. Además, coloca todos los bits de prefijo al principio de la palabra, en lugar de al principio de cada byte.
  • Los bytes del descriptor de informe HID utilizan un campo de bits de conteo de bytes de 2 bits para codificar el tamaño del siguiente entero de cero, uno, dos o cuatro bytes, siempre little endian. El signo, es decir, si se expande el entero acortado con signo o no, depende del tipo de descriptor.
  • El formato de archivo de código de bits LLVM utiliza una técnica similar a la,[16]​ excepto que el valor se divide en grupos de bits de tamaño dependiente del contexto, donde el bit más significativo indica una continuación, en lugar de 7 bits fijos.
  • Protocol Buffers (Protobuf) utiliza la misma codificación para enteros sin signo, pero codifica los enteros con signo anteponiendo el signo como el bit menos significativo del primer byte.
  • ASN.1 BER, DER Codifica los valores de cada tipo ASN.1 como una cadena de octetos de ocho bits.

Referencias

  1. UNIX International (mes de julio de 1993). «7.8». DWARF Debugging Information Format Specification Version 2.0, Draft. Consultado el 19 de julio de 2009. 
  2. a b Free Standards Group (mes de diciembre de 2005). «DWARF Debugging Information Format Specification Version 3.0». p. 70. Consultado el 19 de julio de 2009. 
  3. a b c WebAssembly Community Group (12 de noviembre de 2020). «Values — Binary Format — WebAssembly 1.1». Consultado el 31 de diciembre de 2020. 
  4. Plaisance, Jeff; Kurz, Nathan; Lemire, Daniel (2015). «Vectorized VByte Decoding». arXiv:1503.07387  [cs.IR]. 
  5. Lemire, Daniel; Kurz, Nathan; Rupp, Christoph (mes de febrero de 2018). «Stream VByte: Faster Byte-Oriented Integer Compression». Information Processing Letters (First International Symposium on Web Algorithms) 130: 1-6. S2CID 8265597. arXiv:1709.08990. doi:10.1016/j.ipl.2017.09.011. 
  6. «Dalvik Executable Format». Consultado el 18 de mayo de 2021. 
  7. Christophe de Dinechin (mes de octubre de 2000). «C++ Exception Handling for IA-64». Consultado el 19 de julio de 2009. 
  8. LLVM Project (2016). «LLVM Code Coverage Mapping Format». Consultado el 20 de octubre de 2016. 
  9. LLVM Project (2019). «LLVM LEB128 encoding and decoding». Consultado el 2 de noviembre de 2019. 
  10. System.IO.BinaryWriter.Write7BitEncodedInt(int) method and System.IO.BinaryReader.Read7BitEncodedInt() method.
  11. «Minecraft Modern Varint & Varlong». wiki.vg. 2020. Archivado desde el original el 26 de septiembre de 2024. Consultado el 29 de noviembre de 2020. 
  12. «MPatrol documentation». mes de diciembre de 2008. Consultado el 19 de julio de 2009. 
  13. «Osr (file format) - osu!wiki». osu.ppy.sh (en inglés). Consultado el 18 de marzo de 2017. 
  14. «Efficient XML Interchange (EXI) Format 1.0». www.w3.org (Second edición). World Wide Web Consortium. 11 de febrero de 2014. Consultado el 31 de diciembre de 2020. 
  15. «The .xz File Format». tukaani.org. 2009. Consultado el 30 de octubre de 2017. 
  16. «LLVM Bitcode File Format — LLVM 13 documentation». 

Véase también

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.