1
# Copyright (C) 2009, 2010 Canonical Ltd
1
# Copyright (C) 2009 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
30
30
cdef extern from "Python.h":
31
31
ctypedef int Py_ssize_t # Required for older pyrex versions
32
ctypedef struct PyObject:
34
ctypedef _PyObject PyObject
34
35
int PyTuple_CheckExact(object p)
35
36
Py_ssize_t PyTuple_GET_SIZE(object t)
36
37
int PyString_CheckExact(object)
37
38
char *PyString_AS_STRING(object s)
38
39
Py_ssize_t PyString_GET_SIZE(object)
39
unsigned long PyInt_AsUnsignedLongMask(object) except? -1
41
41
int PyDict_SetItem(object d, object k, object v) except -1
52
52
char *PyString_AS_STRING_ptr "PyString_AS_STRING" (PyObject *s)
53
53
object PyString_FromStringAndSize(char*, Py_ssize_t)
55
# cimport all of the definitions we will need to access
56
from _static_tuple_c cimport StaticTuple,\
57
import_static_tuple_c, StaticTuple_New, \
58
StaticTuple_Intern, StaticTuple_SET_ITEM, StaticTuple_CheckExact
60
cdef extern from "_static_tuple_c.h":
61
# Defined explicitly rather than cimport-ing. Trying to use cimport, the
62
# type for PyObject is a different class that happens to have the same
64
PyObject * StaticTuple_GET_ITEM_ptr "StaticTuple_GET_ITEM" (StaticTuple,
68
from zlib import crc32
71
# Set up the StaticTuple C_API functionality
72
import_static_tuple_c()
55
cdef extern from "zlib.h":
56
ctypedef unsigned long uLong
57
ctypedef unsigned int uInt
58
ctypedef unsigned char Bytef
60
uLong crc32(uLong crc, Bytef *buf, uInt len)
76
cdef object _InternalNode
77
64
_InternalNode = None
81
67
# We shouldn't just copy this from _dirstate_helpers_pyx
82
cdef void* _my_memrchr(void *s, int c, size_t n): # cannot_raise
68
cdef void* _my_memrchr(void *s, int c, size_t n):
83
69
# memrchr seems to be a GNU extension, so we have to implement it ourselves
98
84
cdef Py_ssize_t num_bits
99
85
cdef Py_ssize_t i, j
100
86
cdef Py_ssize_t num_out_bytes
101
cdef unsigned long crc_val
102
90
cdef Py_ssize_t out_off
94
if not PyTuple_CheckExact(key):
95
raise TypeError('key %r is not a tuple' % (key,))
96
num_bits = PyTuple_GET_SIZE(key)
106
97
# 4 bytes per crc32, and another 1 byte between bits
107
98
num_out_bytes = (9 * num_bits) - 1
108
99
out = PyString_FromStringAndSize(NULL, num_out_bytes)
112
103
c_out[0] = c'\x00'
113
104
c_out = c_out + 1
114
crc_val = PyInt_AsUnsignedLongMask(crc32(key[i]))
105
# We use the _ptr variant, because GET_ITEM returns a borrowed
106
# reference, and Pyrex assumes that returned 'object' are a new
108
bit = PyTuple_GET_ITEM_ptr(key, i)
109
if not PyString_CheckExact_ptr(bit):
110
raise TypeError('Bit %d of %r is not a string' % (i, key))
111
c_bit = <Bytef *>PyString_AS_STRING_ptr(bit)
112
c_len = PyString_GET_SIZE_ptr(bit)
113
crc_val = crc32(0, c_bit, c_len)
116
115
sprintf(c_out, '%08X', crc_val)
117
116
c_out = c_out + 8
123
122
cdef Py_ssize_t num_bits
124
123
cdef Py_ssize_t i, j
125
124
cdef Py_ssize_t num_out_bytes
126
cdef unsigned long crc_val
127
128
cdef Py_ssize_t out_off
132
if not PyTuple_CheckExact(key):
133
raise TypeError('key %r is not a tuple' % (key,))
134
num_bits = PyTuple_GET_SIZE(key)
131
135
# 4 bytes per crc32, and another 1 byte between bits
132
136
num_out_bytes = (5 * num_bits) - 1
133
137
out = PyString_FromStringAndSize(NULL, num_out_bytes)
137
141
c_out[0] = c'\x00'
138
142
c_out = c_out + 1
139
crc_val = PyInt_AsUnsignedLongMask(crc32(key[i]))
143
bit = PyTuple_GET_ITEM_ptr(key, i)
144
if not PyString_CheckExact_ptr(bit):
145
raise TypeError('Bit %d of %r is not a string: %r' % (i, key,
147
c_bit = <Bytef *>PyString_AS_STRING_ptr(bit)
148
c_len = PyString_GET_SIZE_ptr(bit)
149
crc_val = crc32(0, c_bit, c_len)
141
151
c_out[0] = (crc_val >> 24) & 0xFF
142
152
c_out[1] = (crc_val >> 16) & 0xFF
185
195
cdef char *prefix, *value_start, *prefix_tail
186
196
cdef char *next_null, *last_null, *line_start
187
197
cdef char *c_entry, *entry_start
188
cdef StaticTuple entry_bits
190
199
if _LeafNode is None:
191
200
from bzrlib import chk_map
256
265
if next_line == NULL:
257
266
raise ValueError('missing trailing newline')
258
267
cur = next_line + 1
259
entry_bits = StaticTuple_New(width)
268
entry_bits = PyTuple_New(width)
260
269
for i from 0 <= i < num_prefix_bits:
261
# TODO: Use PyList_GetItem, or turn prefix_bits into a
263
270
entry = prefix_bits[i]
264
271
# SET_ITEM 'steals' a reference
266
StaticTuple_SET_ITEM(entry_bits, i, entry)
273
PyTuple_SET_ITEM(entry_bits, i, entry)
267
274
value = PyString_FromStringAndSize(value_start, next_line - value_start)
268
275
# The next entry bit needs the 'tail' from the prefix, and first part
281
288
memcpy(c_entry + prefix_tail_len, line_start, next_null - line_start)
283
290
i = num_prefix_bits
284
StaticTuple_SET_ITEM(entry_bits, i, entry)
291
PyTuple_SET_ITEM(entry_bits, i, entry)
285
292
while next_null != last_null: # We have remaining bits
294
301
entry = PyString_FromStringAndSize(entry_start,
295
302
next_null - entry_start)
297
StaticTuple_SET_ITEM(entry_bits, i, entry)
304
PyTuple_SET_ITEM(entry_bits, i, entry)
298
305
if len(entry_bits) != width:
299
306
raise AssertionError(
300
307
'Incorrect number of elements (%d vs %d)'
301
308
% (len(entry_bits)+1, width + 1))
302
entry_bits = StaticTuple_Intern(entry_bits)
303
309
PyDict_SetItem(items, entry_bits, value)
304
310
if len(items) != length:
305
311
raise ValueError("item count (%d) mismatch for key %s,"
337
343
_unknown = chk_map._unknown
338
344
result = _InternalNode(search_key_func=search_key_func)
340
if not StaticTuple_CheckExact(key):
341
raise TypeError('key %r is not a StaticTuple' % (key,))
342
346
if not PyString_CheckExact(bytes):
343
347
raise TypeError('bytes must be a plain string not %s' % (type(bytes),))
380
384
memcpy(c_item_prefix + prefix_length, cur, next_null - cur)
381
385
flat_key = PyString_FromStringAndSize(next_null + 1,
382
386
next_line - next_null - 1)
383
flat_key = StaticTuple(flat_key).intern()
384
PyDict_SetItem(items, item_prefix, flat_key)
387
PyDict_SetItem(items, item_prefix, (flat_key,))
385
388
cur = next_line + 1
386
389
assert len(items) > 0
387
390
result._items = items