~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_groupcompress_pyx.pyx

  • Committer: Jelmer Vernooij
  • Date: 2011-05-01 21:02:50 UTC
  • mto: This revision was merged to the branch mainline in revision 5842.
  • Revision ID: jelmer@samba.org-20110501210250-24jq6hrxxc9psvzf
Actually use branch format 5 in branch format 5 test.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
 
24
24
cdef extern from "Python.h":
 
25
    ctypedef struct PyObject:
 
26
        pass
25
27
    ctypedef int Py_ssize_t # Required for older pyrex versions
26
28
    int PyString_CheckExact(object)
27
29
    char * PyString_AS_STRING(object)
44
46
        unsigned long agg_offset
45
47
    struct delta_index:
46
48
        pass
47
 
    delta_index * create_delta_index(source_info *src, delta_index *old) nogil
48
 
    delta_index * create_delta_index_from_delta(source_info *delta,
49
 
                                                delta_index *old) nogil
 
49
    ctypedef enum delta_result:
 
50
        DELTA_OK
 
51
        DELTA_OUT_OF_MEMORY
 
52
        DELTA_INDEX_NEEDED
 
53
        DELTA_SOURCE_EMPTY
 
54
        DELTA_SOURCE_BAD
 
55
        DELTA_BUFFER_EMPTY
 
56
        DELTA_SIZE_TOO_BIG
 
57
    delta_result create_delta_index(source_info *src,
 
58
                                    delta_index *old,
 
59
                                    delta_index **fresh) nogil
 
60
    delta_result create_delta_index_from_delta(source_info *delta,
 
61
                                               delta_index *old,
 
62
                                               delta_index **fresh) nogil
50
63
    void free_delta_index(delta_index *index) nogil
51
 
    void *create_delta(delta_index *indexes,
52
 
             void *buf, unsigned long bufsize,
53
 
             unsigned long *delta_size, unsigned long max_delta_size) nogil
 
64
    delta_result create_delta(delta_index *indexes,
 
65
                              void *buf, unsigned long bufsize,
 
66
                              unsigned long *delta_size,
 
67
                              unsigned long max_delta_size,
 
68
                              void **delta_data) nogil
54
69
    unsigned long get_delta_hdr_size(unsigned char **datap,
55
70
                                     unsigned char *top) nogil
 
71
    unsigned long sizeof_delta_index(delta_index *index)
56
72
    Py_ssize_t DELTA_SIZE_MIN
57
73
 
58
74
 
83
99
    return DeltaIndex(source)
84
100
 
85
101
 
 
102
cdef object _translate_delta_failure(delta_result result):
 
103
    if result == DELTA_OUT_OF_MEMORY:
 
104
        return MemoryError("Delta function failed to allocate memory")
 
105
    elif result == DELTA_INDEX_NEEDED:
 
106
        return ValueError("Delta function requires delta_index param")
 
107
    elif result == DELTA_SOURCE_EMPTY:
 
108
        return ValueError("Delta function given empty source_info param")
 
109
    elif result == DELTA_SOURCE_BAD:
 
110
        return RuntimeError("Delta function given invalid source_info param")
 
111
    elif result == DELTA_BUFFER_EMPTY:
 
112
        return ValueError("Delta function given empty buffer params")
 
113
    return AssertionError("Unrecognised delta result code: %d" % result)
 
114
 
 
115
 
86
116
cdef class DeltaIndex:
87
117
 
88
118
    # We need Pyrex 0.9.8+ to understand a 'list' definition, and this object
91
121
    cdef readonly object _sources
92
122
    cdef source_info *_source_infos
93
123
    cdef delta_index *_index
 
124
    cdef public unsigned long _source_offset
94
125
    cdef readonly unsigned int _max_num_sources
95
 
    cdef public unsigned long _source_offset
96
126
 
97
127
    def __init__(self, source=None):
98
128
        self._sources = []
105
135
        if source is not None:
106
136
            self.add_source(source, 0)
107
137
 
 
138
    def __sizeof__(self):
 
139
        # We want to track the _source_infos allocations, but the referenced
 
140
        # void* are actually tracked in _sources itself.
 
141
        # XXX: Cython is capable of doing sizeof(class) and returning the size
 
142
        #      of the underlying struct. Pyrex (<= 0.9.9) refuses, so we need
 
143
        #      to do it manually. *sigh* Note that we might get it wrong
 
144
        #      because of alignment issues.
 
145
        cdef Py_ssize_t size
 
146
        # PyObject start, vtable *, 3 object pointers, 2 C ints
 
147
        size = ((sizeof(PyObject) + sizeof(void*) + 3*sizeof(PyObject*)
 
148
                 + sizeof(unsigned long)
 
149
                 + sizeof(unsigned int))
 
150
                + (sizeof(source_info) * self._max_num_sources)
 
151
                + sizeof_delta_index(self._index))
 
152
        return size
 
153
 
108
154
    def __repr__(self):
109
155
        return '%s(%d, %d)' % (self.__class__.__name__,
110
156
            len(self._sources), self._source_offset)
128
174
        cdef char *c_delta
129
175
        cdef Py_ssize_t c_delta_size
130
176
        cdef delta_index *index
 
177
        cdef delta_result res
131
178
        cdef unsigned int source_location
132
179
        cdef source_info *src
133
180
        cdef unsigned int num_indexes
146
193
        src.size = c_delta_size
147
194
        src.agg_offset = self._source_offset + unadded_bytes
148
195
        with nogil:
149
 
            index = create_delta_index_from_delta(src, self._index)
 
196
            res = create_delta_index_from_delta(src, self._index, &index)
 
197
        if res != DELTA_OK:
 
198
            raise _translate_delta_failure(res)
150
199
        self._source_offset = src.agg_offset + src.size
151
 
        if index != NULL:
 
200
        if index != self._index:
152
201
            free_delta_index(self._index)
153
202
            self._index = index
154
203
 
162
211
        cdef char *c_source
163
212
        cdef Py_ssize_t c_source_size
164
213
        cdef delta_index *index
 
214
        cdef delta_result res
165
215
        cdef unsigned int source_location
166
216
        cdef source_info *src
167
217
        cdef unsigned int num_indexes
187
237
        # We delay creating the index on the first insert
188
238
        if source_location != 0:
189
239
            with nogil:
190
 
                index = create_delta_index(src, self._index)
191
 
            if index != NULL:
 
240
                res = create_delta_index(src, self._index, &index)
 
241
            if res != DELTA_OK:
 
242
                raise _translate_delta_failure(res)
 
243
            if index != self._index:
192
244
                free_delta_index(self._index)
193
245
                self._index = index
194
246
 
195
247
    cdef _populate_first_index(self):
196
248
        cdef delta_index *index
 
249
        cdef delta_result res
197
250
        if len(self._sources) != 1 or self._index != NULL:
198
251
            raise AssertionError('_populate_first_index should only be'
199
252
                ' called when we have a single source and no index yet')
200
253
 
201
 
        # We know that self._index is already NULL, so whatever
202
 
        # create_delta_index returns is fine
 
254
        # We know that self._index is already NULL, so create_delta_index
 
255
        # will always create a new index unless there's a malloc failure
203
256
        with nogil:
204
 
            self._index = create_delta_index(&self._source_infos[0], NULL)
205
 
        assert self._index != NULL
 
257
            res = create_delta_index(&self._source_infos[0], NULL, &index)
 
258
        if res != DELTA_OK:
 
259
            raise _translate_delta_failure(res)
 
260
        self._index = index
206
261
 
207
262
    cdef _expand_sources(self):
208
263
        raise RuntimeError('if we move self._source_infos, then we need to'
219
274
        cdef void * delta
220
275
        cdef unsigned long delta_size
221
276
        cdef unsigned long c_max_delta_size
 
277
        cdef delta_result res
222
278
 
223
279
        if self._index == NULL:
224
280
            if len(self._sources) == 0:
237
293
        #       allocate the bytes into the final string
238
294
        c_max_delta_size = max_delta_size
239
295
        with nogil:
240
 
            delta = create_delta(self._index,
241
 
                                 target, target_size,
242
 
                                 &delta_size, c_max_delta_size)
 
296
            res = create_delta(self._index, target, target_size,
 
297
                               &delta_size, c_max_delta_size, &delta)
243
298
        result = None
244
 
        if delta:
 
299
        if res == DELTA_OK:
245
300
            result = PyString_FromStringAndSize(<char *>delta, delta_size)
246
301
            free(delta)
 
302
        elif res != DELTA_SIZE_TOO_BIG:
 
303
            raise _translate_delta_failure(res)
247
304
        return result
248
305
 
249
306
 
350
407
                # Copy instruction
351
408
                data = _decode_copy_instruction(data, cmd, &cp_off, &cp_size)
352
409
                if (cp_off + cp_size < cp_size or
353
 
                    cp_off + cp_size > source_size or
354
 
                    cp_size > size):
 
410
                    cp_off + cp_size > <unsigned int>source_size or
 
411
                    cp_size > <unsigned int>size):
355
412
                    failed = 1
356
413
                    break
357
414
                memcpy(out, source + cp_off, cp_size)