summaryrefslogtreecommitdiff
path: root/lang
diff options
context:
space:
mode:
authorKeith Bostic <keith@wiredtiger.com>2014-12-22 15:26:24 -0500
committerKeith Bostic <keith@wiredtiger.com>2014-12-22 15:26:24 -0500
commitd4239a38a95aea7bd736d78485a23626bbed4925 (patch)
treed9e8873fa67774b1a118da0d930d8ff03d44c574 /lang
parent8662942d711b25e5cea0583ba6b87ce6a0edeb58 (diff)
parenta2ab06bb676ab03ec75c0d3665d6169d4c5973df (diff)
downloadmongo-d4239a38a95aea7bd736d78485a23626bbed4925.tar.gz
Merge branch 'develop' into cursor-reconfigure
Diffstat (limited to 'lang')
-rw-r--r--lang/python/wiredtiger/packing-test.py51
-rw-r--r--lang/python/wiredtiger/packing.py79
2 files changed, 99 insertions, 31 deletions
diff --git a/lang/python/wiredtiger/packing-test.py b/lang/python/wiredtiger/packing-test.py
index eaae4d51ae7..4b06b2bc608 100644
--- a/lang/python/wiredtiger/packing-test.py
+++ b/lang/python/wiredtiger/packing-test.py
@@ -28,11 +28,50 @@
from packing import pack, unpack
+def check_common(fmt, verbose, *v):
+ v = list(v)
+ packed = pack(fmt, *v)
+ unpacked = unpack(fmt, packed)
+ if unpacked == v:
+ result = 'ok'
+ else:
+ result = '** FAIL!'
+ print '* %s as %s: %s' % (repr(v), fmt, result)
+ if verbose or unpacked != v:
+ print '** packed: ', ''.join('%02x' % ord(c) for c in packed)
+ print '** unpacked: ', unpacked
+
def check(fmt, *v):
- print fmt, repr(v), ''.join('%02x' % ord(c) for c in pack(fmt, *v))
+ check_common(fmt, False, *v)
+
+def check_verbose(fmt, *v):
+ check_common(fmt, True, *v)
+
+
+if __name__ == '__main__':
+ import sys
+ if 'verbose' in sys.argv:
+ check = check_verbose
+ check('iii', 0, 101, -99)
+ check('3i', 0, 101, -99)
+ check('iS', 42, "forty two")
+
+ #
+ check('S', 'abc')
+ check('9S', 'a' * 9)
+ check('9SS', "forty two", "spam egg")
+ check('42S', 'a' * 42)
+ check('42SS', 'a' * 42, 'something')
+ check('S42S', 'something', 'a' * 42)
+ # nul terminated string with padding
+ check('10SS', 'aaaaa\x00\x00\x00\x00\x00', 'something')
+ check('S10S', 'something', 'aaaaa\x00\x00\x00\x00\x00')
+
+ check('u', r"\x42" * 20)
+ check('uu', r"\x42" * 10, r"\x42" * 10)
+ check('3u', r"\x4")
+ check('3uu', r"\x4", r"\x42" * 10)
+ check('u3u', r"\x42" * 10, r"\x4")
-check('iii', 0, 101, -99)
-check('3i', 0, 101, -99)
-check('iS', 42, "forty two")
-check('u', r"\x42" * 20)
-check('uu', r"\x42" * 10, r"\x42" * 10)
+ check('s', "4")
+ check("2s", "42")
diff --git a/lang/python/wiredtiger/packing.py b/lang/python/wiredtiger/packing.py
index 6bcb82e76d5..ee12434cabd 100644
--- a/lang/python/wiredtiger/packing.py
+++ b/lang/python/wiredtiger/packing.py
@@ -27,6 +27,27 @@
#
# WiredTiger variable-length packing and unpacking functions
+"""Packing and unpacking functions
+The format string uses the following conversions:
+Format Python Notes
+ x N/A pad byte, no associated value
+ b int signed byte
+ B int unsigned byte
+ h int signed 16-bit
+ H int unsigned 16-bit
+ i int signed 32-bit
+ I int unsigned 32-bit
+ l int signed 32-bit
+ L int unsigned 32-bit
+ q int signed 64-bit
+ Q int unsigned 64-bit
+ r int record number
+ s str fixed-length string
+ S str NUL-terminated string
+ t int fixed-length bit field
+ u str raw byte array
+"""
+
from intpacking import pack_int, unpack_int
def __get_type(fmt):
@@ -40,6 +61,18 @@ def __get_type(fmt):
tfmt = '.'
return tfmt, fmt
+def __unpack_iter_fmt(fmt):
+ size = 0
+ havesize = 0
+ for offset, char in enumerate(fmt):
+ if char.isdigit():
+ size = (size * 10) + int(char)
+ havesize = 1
+ else:
+ yield offset, havesize, size, char
+ size = 0
+ havesize = 0
+
def unpack(fmt, s):
tfmt, fmt = __get_type(fmt)
if not fmt:
@@ -47,13 +80,8 @@ def unpack(fmt, s):
if tfmt != '.':
raise ValueError('Only variable-length encoding is currently supported')
result = []
- havesize = size = 0
- for offset, f in enumerate(fmt):
- if f.isdigit():
- size = (size * 10) + int(f)
- havesize = 1
- continue
- elif f == 'x':
+ for offset, havesize, size, f in __unpack_iter_fmt(fmt):
+ if f == 'x':
if not havesize:
size = 1
s = s[size:]
@@ -86,9 +114,23 @@ def unpack(fmt, s):
for j in xrange(size):
v, s = unpack_int(s)
result.append(v)
- havesize = size = 0
return result
+def __pack_iter_fmt(fmt, values):
+ index = 0
+ for offset, havesize, size, char in __unpack_iter_fmt(fmt):
+ if char == 'x': # padding no value
+ yield offset, havesize, size, char, None
+ elif char in 'Ssut':
+ yield offset, havesize, size, char, values[index]
+ index += 1
+ else: # integral type
+ size = size if havesize else 1
+ for i in xrange(size):
+ value = values[index]
+ yield offset, havesize, 1, char, value
+ index = index + 1
+
def pack(fmt, *values):
tfmt, fmt = __get_type(fmt)
if not fmt:
@@ -96,20 +138,15 @@ def pack(fmt, *values):
if tfmt != '.':
raise ValueError('Only variable-length encoding is currently supported')
result = ''
- havesize = i = size = 0
- for offset, f in enumerate(fmt):
- if f.isdigit():
- size = (size * 10) + int(f)
- havesize = 1
- continue
- elif f == 'x':
+ i = 0
+ for offset, havesize, size, f, val in __pack_iter_fmt(fmt, values):
+ if f == 'x':
if not havesize:
result += '\0'
else:
result += '\0' * size
# Note: no value, don't increment i
elif f in 'Ssu':
- val = values[i]
if f == 'S' and '\0' in val:
l = val.find('\0')
else:
@@ -129,7 +166,6 @@ def pack(fmt, *values):
result += '\0'
elif size > l:
result += '\0' * (size - l)
- i += 1
elif f in 't':
# bit type, size is number of bits
if not havesize:
@@ -137,17 +173,10 @@ def pack(fmt, *values):
if size > 8:
raise ValueError("bit count cannot be greater than 8 for 't' encoding")
mask = (1 << size) - 1
- val = values[i]
if (mask & val) != val:
raise ValueError("value out of range for 't' encoding")
result += chr(val)
- i += 1
else:
# integral type
- if not havesize:
- size = 1
- for j in xrange(size):
- result += pack_int(values[i])
- i += 1
- havesize = size = 0
+ result += pack_int(val)
return result