Mercurial > hg
comparison mercurial/util.py @ 35755:2384523cee4d
util: implement varint functions
This will be useful in an incoming version-2 of the stream format.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Fri, 19 Jan 2018 22:52:35 +0100 |
parents | fb0be099063f |
children | 72de5c504833 48783333f45c |
comparison
equal
deleted
inserted
replaced
35754:fb0be099063f | 35755:2384523cee4d |
---|---|
3872 if len(s) < n: | 3872 if len(s) < n: |
3873 raise error.Abort(_("stream ended unexpectedly" | 3873 raise error.Abort(_("stream ended unexpectedly" |
3874 " (got %d bytes, expected %d)") | 3874 " (got %d bytes, expected %d)") |
3875 % (len(s), n)) | 3875 % (len(s), n)) |
3876 return s | 3876 return s |
3877 | |
3878 def uvarintencode(value): | |
3879 """Encode an unsigned integer value to a varint. | |
3880 | |
3881 A varint is a variable length integer of 1 or more bytes. Each byte | |
3882 except the last has the most significant bit set. The lower 7 bits of | |
3883 each byte store the 2's complement representation, least significant group | |
3884 first. | |
3885 | |
3886 >>> uvarintencode(0) | |
3887 '\\x00' | |
3888 >>> uvarintencode(1) | |
3889 '\\x01' | |
3890 >>> uvarintencode(127) | |
3891 '\\x7f' | |
3892 >>> uvarintencode(1337) | |
3893 '\\xb9\\n' | |
3894 >>> uvarintencode(65536) | |
3895 '\\x80\\x80\\x04' | |
3896 >>> uvarintencode(-1) | |
3897 Traceback (most recent call last): | |
3898 ... | |
3899 ProgrammingError: negative value for uvarint: -1 | |
3900 """ | |
3901 if value < 0: | |
3902 raise error.ProgrammingError('negative value for uvarint: %d' | |
3903 % value) | |
3904 bits = value & 0x7f | |
3905 value >>= 7 | |
3906 bytes = [] | |
3907 while value: | |
3908 bytes.append(pycompat.bytechr(0x80 | bits)) | |
3909 bits = value & 0x7f | |
3910 value >>= 7 | |
3911 bytes.append(pycompat.bytechr(bits)) | |
3912 | |
3913 return ''.join(bytes) | |
3914 | |
3915 def uvarintdecodestream(fh): | |
3916 """Decode an unsigned variable length integer from a stream. | |
3917 | |
3918 The passed argument is anything that has a ``.read(N)`` method. | |
3919 | |
3920 >>> try: | |
3921 ... from StringIO import StringIO as BytesIO | |
3922 ... except ImportError: | |
3923 ... from io import BytesIO | |
3924 >>> uvarintdecodestream(BytesIO(b'\\x00')) | |
3925 0 | |
3926 >>> uvarintdecodestream(BytesIO(b'\\x01')) | |
3927 1 | |
3928 >>> uvarintdecodestream(BytesIO(b'\\x7f')) | |
3929 127 | |
3930 >>> uvarintdecodestream(BytesIO(b'\\xb9\\n')) | |
3931 1337 | |
3932 >>> uvarintdecodestream(BytesIO(b'\\x80\\x80\\x04')) | |
3933 65536 | |
3934 >>> uvarintdecodestream(BytesIO(b'\\x80')) | |
3935 Traceback (most recent call last): | |
3936 ... | |
3937 Abort: stream ended unexpectedly (got 0 bytes, expected 1) | |
3938 """ | |
3939 result = 0 | |
3940 shift = 0 | |
3941 while True: | |
3942 byte = ord(readexactly(fh, 1)) | |
3943 result |= ((byte & 0x7f) << shift) | |
3944 if not (byte & 0x80): | |
3945 return result | |
3946 shift += 7 |