Merge lp:~mhr3/dee/introspectable-sort-methods into lp:dee
- introspectable-sort-methods
- Merge into trunk
Proposed by
Michal Hruby
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Paweł Stołowski | ||||
Approved revision: | 376 | ||||
Merged at revision: | 376 | ||||
Proposed branch: | lp:~mhr3/dee/introspectable-sort-methods | ||||
Merge into: | lp:dee | ||||
Diff against target: |
418 lines (+289/-6) 5 files modified
bindings/python/Dee.py (+20/-1) src/dee-model.c (+98/-0) src/dee-model.h (+37/-5) tests/test-model-rows.c (+130/-0) vapi/dee-1.0.vapi (+4/-0) |
||||
To merge this branch: | bzr merge lp:~mhr3/dee/introspectable-sort-methods | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paweł Stołowski (community) | Approve | ||
Review via email: mp+118801@code.launchpad.net |
Commit message
Make the *sorted methods usable with introspection
Description of the change
Dee's find_sorted and insert_sorted were not usable from introspectable languages.
Added a delegate that's introspection friendly and tests that make sure it's working.
To post a comment you must log in.
- 376. By Michal Hruby
-
Remove fixed FIXME
Revision history for this message
Michal Hruby (mhr3) wrote : | # |
> Looks, good. Just one question:
> 30 + # FIXME: perhaps override __eq__ on ModelIter?
> is this still applicable?
Right, already fixed.
Revision history for this message
Paweł Stołowski (stolowski) wrote : | # |
Looks good, tests pass.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bindings/python/Dee.py' |
2 | --- bindings/python/Dee.py 2012-06-27 15:36:53 +0000 |
3 | +++ bindings/python/Dee.py 2012-08-15 13:38:19 +0000 |
4 | @@ -63,14 +63,20 @@ |
5 | def insert_before (self, iter, *args): |
6 | return self.insert_row_before (iter, self._build_row(args)) |
7 | |
8 | + def insert_row_sorted (self, row_spec, sort_func, data): |
9 | + return self.insert_row_sorted_with_sizes (row_spec, sort_func, data) |
10 | + |
11 | def insert_sorted (self, sort_func, *args): |
12 | return self.insert_row_sorted (self._build_row(args), sort_func, None) |
13 | |
14 | + def find_row_sorted (self, row_spec, sort_func, data): |
15 | + return self.find_row_sorted_with_sizes (row_spec, sort_func, data) |
16 | + |
17 | def find_sorted (self, sort_func, *args): |
18 | return self.find_row_sorted (self._build_row(args), sort_func, None) |
19 | |
20 | def get_schema (self): |
21 | - return Dee.Model.get_schema(self)[0] |
22 | + return Dee.Model.get_schema(self) |
23 | |
24 | def get_value (self, itr, column): |
25 | return Dee.Model.get_value (self, itr, column).unpack() |
26 | @@ -108,8 +114,21 @@ |
27 | return self.get_n_rows() |
28 | |
29 | |
30 | +class ModelIter(Dee.ModelIter): |
31 | + |
32 | + def __init__(self): |
33 | + Dee.ModelIter.__init__(self) |
34 | + |
35 | + def __eq__ (self, other): |
36 | + if not isinstance (other, ModelIter): |
37 | + return False |
38 | + return repr(self) == repr(other) |
39 | + |
40 | + |
41 | |
42 | Model = override(Model) |
43 | __all__.append('Model') |
44 | +ModelIter = override(ModelIter) |
45 | +__all__.append('ModelIter') |
46 | |
47 | |
48 | |
49 | === modified file 'src/dee-model.c' |
50 | --- src/dee-model.c 2012-02-28 00:36:16 +0000 |
51 | +++ src/dee-model.c 2012-08-15 13:38:19 +0000 |
52 | @@ -975,6 +975,20 @@ |
53 | return (* iface->insert_row_before) (self, iter, row_members); |
54 | } |
55 | |
56 | +/* Translates DeeCompareRowFunc callback into DeeCompareRowSizedFunc */ |
57 | +static gint |
58 | +dee_model_cmp_func_translate_func (GVariant **row1, |
59 | + GVariant **row2, |
60 | + gpointer data) |
61 | +{ |
62 | + gpointer *all_data = (gpointer*) data; |
63 | + DeeCompareRowSizedFunc cmp_func = (DeeCompareRowSizedFunc) all_data[0]; |
64 | + gpointer user_data = all_data[1]; |
65 | + guint array_length = GPOINTER_TO_UINT (all_data[2]); |
66 | + |
67 | + return cmp_func (row1, array_length, row2, array_length, user_data); |
68 | +} |
69 | + |
70 | /** |
71 | * dee_model_insert_row_sorted: |
72 | * @self: The model to do a sorted insert on |
73 | @@ -1009,6 +1023,41 @@ |
74 | } |
75 | |
76 | /** |
77 | + * dee_model_insert_row_sorted_with_sizes: |
78 | + * @self: The model to do a sorted insert on |
79 | + * @row_members: (array zero-terminated=1): An array of |
80 | + * #GVariants with type signature matching those of the |
81 | + * column schemas of @self. If any of the variants have floating |
82 | + * references they will be consumed. |
83 | + * @cmp_func: (scope call): Callback used for comparison or rows |
84 | + * @user_data: (closure): Arbitrary pointer passed to @cmp_func during search |
85 | + * |
86 | + * Inserts a row in @self according to the sorting specified by @cmp_func. |
87 | + * If you use this method for insertion you should not use other methods as this |
88 | + * method assumes the model to be already sorted by @cmp_func. |
89 | + * |
90 | + * Returns: (transfer none) (type Dee.ModelIter): A #DeeModelIter pointing to the new row |
91 | + */ |
92 | +DeeModelIter* |
93 | +dee_model_insert_row_sorted_with_sizes (DeeModel *self, |
94 | + GVariant **row_members, |
95 | + DeeCompareRowSizedFunc cmp_func, |
96 | + gpointer user_data) |
97 | +{ |
98 | + gpointer all_data[3]; |
99 | + |
100 | + g_return_val_if_fail (DEE_IS_MODEL (self), NULL); |
101 | + |
102 | + all_data[0] = cmp_func; |
103 | + all_data[1] = user_data; |
104 | + all_data[2] = GUINT_TO_POINTER (dee_model_get_n_columns (self)); |
105 | + |
106 | + return dee_model_insert_row_sorted (self, row_members, |
107 | + dee_model_cmp_func_translate_func, |
108 | + all_data); |
109 | +} |
110 | + |
111 | +/** |
112 | * dee_model_insert_sorted: |
113 | * @self: The model to do a sorted insert on |
114 | * @cmp_func: (scope call): Callback used for comparison or rows |
115 | @@ -1103,6 +1152,55 @@ |
116 | } |
117 | |
118 | /** |
119 | + * dee_model_find_row_sorted_with_sizes: |
120 | + * @self: The model to search |
121 | + * @row_spec: (array zero-terminated=1): An array of |
122 | + * #GVariants with type signature matching those of the |
123 | + * column schemas of @self. No references will be taken on the variants. |
124 | + * @cmp_func: (scope call): Callback used for comparison or rows |
125 | + * @user_data: (closure): Arbitrary pointer passed to @cmp_func during search |
126 | + * @out_was_found: (out): A place to store a boolean value that will be set when |
127 | + * this method returns. If %TRUE then an exact match was found. |
128 | + * If %FALSE then the returned iter points to a row just after |
129 | + * where @row_spec would have been inserted. |
130 | + * Pass %NULL to ignore. |
131 | + * |
132 | + * Like dee_model_find_row_sorted(), but uses DeeCompareRowSizedFunc and |
133 | + * therefore doesn't cause trouble when used from introspected languages. |
134 | + * |
135 | + * Finds a row in @self according to the sorting specified by @cmp_func. |
136 | + * This method will assume that @self is already sorted by @cmp_func. |
137 | + * |
138 | + * If you use this method for searching you should only use |
139 | + * dee_model_insert_row_sorted() (or dee_model_insert_row_sorted_with_sizes()) |
140 | + * to insert rows in the model. |
141 | + * |
142 | + * Returns: (transfer none) (type Dee.ModelIter): If @out_was_found is set to |
143 | + * %TRUE then a #DeeModelIter pointing to the first matching row. |
144 | + * If it is %FALSE then the iter pointing to the row just after where |
145 | + * @row_spec_would have been inserted. |
146 | + */ |
147 | +DeeModelIter* |
148 | +dee_model_find_row_sorted_with_sizes (DeeModel *self, |
149 | + GVariant **row_spec, |
150 | + DeeCompareRowSizedFunc cmp_func, |
151 | + gpointer user_data, |
152 | + gboolean *out_was_found) |
153 | +{ |
154 | + gpointer all_data[3]; |
155 | + |
156 | + g_return_val_if_fail (DEE_IS_MODEL (self), NULL); |
157 | + |
158 | + all_data[0] = cmp_func; |
159 | + all_data[1] = user_data; |
160 | + all_data[2] = GUINT_TO_POINTER (dee_model_get_n_columns (self)); |
161 | + |
162 | + return dee_model_find_row_sorted (self, row_spec, |
163 | + dee_model_cmp_func_translate_func, |
164 | + all_data, out_was_found); |
165 | +} |
166 | + |
167 | +/** |
168 | * dee_model_find_sorted: |
169 | * @self: The model to search |
170 | * @cmp_func: (scope call): Callback used for comparison or rows |
171 | |
172 | === modified file 'src/dee-model.h' |
173 | --- src/dee-model.h 2012-03-19 11:18:50 +0000 |
174 | +++ src/dee-model.h 2012-08-15 13:38:19 +0000 |
175 | @@ -78,6 +78,27 @@ |
176 | GVariant** row2, |
177 | gpointer user_data); |
178 | |
179 | +/** |
180 | + * DeeCompareRowSizedFunc: |
181 | + * @row1: (array length=row1_length): Row data |
182 | + * @row1_length: The number of elements in row1 array |
183 | + * @row2: (array length=row2_length): Row data to compare with |
184 | + * @row2_length: The number of elements in row2 array |
185 | + * @user_data: (closure): User data passed to comparison function |
186 | + * |
187 | + * Compares @row1 and @row2. Mainly used with |
188 | + * dee_model_insert_row_sorted_with_sizes() and |
189 | + * dee_model_find_row_sorted_with_sizes(). |
190 | + * |
191 | + * Returns: -1, 0, or 1 if @row1 is respectively less than, equal, or greater |
192 | + * than @row2. |
193 | + */ |
194 | +typedef gint (*DeeCompareRowSizedFunc) (GVariant** row1, |
195 | + guint row1_length, |
196 | + GVariant** row2, |
197 | + guint row2_length, |
198 | + gpointer user_data); |
199 | + |
200 | struct _DeeModelIface |
201 | { |
202 | GTypeInterface g_iface; |
203 | @@ -291,6 +312,11 @@ |
204 | DeeCompareRowFunc cmp_func, |
205 | gpointer user_data); |
206 | |
207 | +DeeModelIter* dee_model_insert_row_sorted_with_sizes (DeeModel *self, |
208 | + GVariant **row_members, |
209 | + DeeCompareRowSizedFunc cmp_func, |
210 | + gpointer user_data); |
211 | + |
212 | DeeModelIter* dee_model_insert_sorted (DeeModel *self, |
213 | DeeCompareRowFunc cmp_func, |
214 | gpointer user_data, |
215 | @@ -302,11 +328,17 @@ |
216 | gpointer user_data, |
217 | gboolean *out_was_found); |
218 | |
219 | -DeeModelIter* dee_model_find_sorted (DeeModel *self, |
220 | - DeeCompareRowFunc cmp_func, |
221 | - gpointer user_data, |
222 | - gboolean *out_was_found, |
223 | - ...); |
224 | +DeeModelIter* dee_model_find_row_sorted_with_sizes (DeeModel *self, |
225 | + GVariant **row_spec, |
226 | + DeeCompareRowSizedFunc cmp_func, |
227 | + gpointer user_data, |
228 | + gboolean *out_was_found); |
229 | + |
230 | +DeeModelIter* dee_model_find_sorted (DeeModel *self, |
231 | + DeeCompareRowFunc cmp_func, |
232 | + gpointer user_data, |
233 | + gboolean *out_was_found, |
234 | + ...); |
235 | |
236 | void dee_model_remove (DeeModel *self, |
237 | DeeModelIter *iter); |
238 | |
239 | === modified file 'tests/test-model-rows.c' |
240 | --- tests/test-model-rows.c 2012-01-26 19:08:42 +0000 |
241 | +++ tests/test-model-rows.c 2012-08-15 13:38:19 +0000 |
242 | @@ -47,6 +47,7 @@ |
243 | static void test_iter_backwards (RowsFixture *fix, gconstpointer data); |
244 | static void test_illegal_access (RowsFixture *fix, gconstpointer data); |
245 | static void test_sorted (RowsFixture *fix, gconstpointer data); |
246 | +static void test_sorted_with_sizes (RowsFixture *fix, gconstpointer data); |
247 | |
248 | static void test_model_iter_copy (RowsFixture *fix, gconstpointer data); |
249 | static void test_model_iter_free (RowsFixture *fix, gconstpointer data); |
250 | @@ -133,6 +134,13 @@ |
251 | proxy_rows_setup, test_sorted, proxy_rows_teardown); |
252 | g_test_add (TXN_DOMAIN"/Sorted", RowsFixture, 0, |
253 | txn_rows_setup, test_sorted, txn_rows_teardown); |
254 | + |
255 | + g_test_add (SEQ_DOMAIN"/Sorted/WithSizes", RowsFixture, 0, |
256 | + seq_rows_setup, test_sorted_with_sizes, seq_rows_teardown); |
257 | + g_test_add (PROXY_DOMAIN"/Sorted/WithSizes", RowsFixture, 0, |
258 | + proxy_rows_setup, test_sorted_with_sizes, proxy_rows_teardown); |
259 | + g_test_add (TXN_DOMAIN"/Sorted/WithSizes", RowsFixture, 0, |
260 | + txn_rows_setup, test_sorted_with_sizes, txn_rows_teardown); |
261 | } |
262 | |
263 | static void |
264 | @@ -560,3 +568,125 @@ |
265 | g_assert (was_found); |
266 | g_assert (result == hter); |
267 | } |
268 | + |
269 | +static gint |
270 | +sized_cmp_col_0 (GVariant **row1, guint row1_length, |
271 | + GVariant **row2, guint row2_length, gpointer user_data) |
272 | +{ |
273 | + g_assert_cmpstr (user_data, ==, "test-user-data"); |
274 | + g_assert_cmpuint (row1_length, ==, 2); |
275 | + g_assert_cmpuint (row2_length, ==, 2); |
276 | + g_assert_cmpuint (row1_length, ==, row2_length); |
277 | + return g_variant_get_int32 (row2[0]) - g_variant_get_int32 (row1[0]); |
278 | +} |
279 | + |
280 | +static void |
281 | +test_sorted_with_sizes (RowsFixture *fix, gconstpointer data) |
282 | +{ |
283 | + DeeModelIter *hter, *iter, *jter, *kter; |
284 | + gboolean was_found; |
285 | + GVariant *row_spec[2]; |
286 | + |
287 | + /* FINAL MODEL: [(28,s), (27,s), (26,s), (25,s)] |
288 | + * ~= [hter, iter, jter, kter] */ |
289 | + |
290 | + row_spec[0] = g_variant_new_int32 (0); |
291 | + row_spec[1] = g_variant_new_string (""); |
292 | + /* Test find() with an empty model. With NULL was_found arg */ |
293 | + iter = dee_model_find_row_sorted_with_sizes (fix->model, row_spec, |
294 | + sized_cmp_col_0, |
295 | + "test-user-data", |
296 | + NULL); |
297 | + g_assert (iter == dee_model_get_last_iter (fix->model)); |
298 | + |
299 | + /* Test find() with an empty model. With non-NULL was_found arg */ |
300 | + was_found = TRUE; |
301 | + iter = dee_model_find_row_sorted_with_sizes (fix->model, row_spec, |
302 | + sized_cmp_col_0, |
303 | + "test-user-data", |
304 | + &was_found); |
305 | + g_assert (!was_found); |
306 | + g_assert (iter == dee_model_get_last_iter (fix->model)); |
307 | + |
308 | + /* Insert the first row */ |
309 | + row_spec[0] = g_variant_new_int32 (27); |
310 | + row_spec[1] = g_variant_new_string ("Sorta sorted"); |
311 | + iter = dee_model_insert_row_sorted_with_sizes (fix->model, row_spec, |
312 | + sized_cmp_col_0, |
313 | + "test-user-data"); |
314 | + g_assert (iter != dee_model_get_last_iter (fix->model)); |
315 | + g_assert (iter == dee_model_get_first_iter (fix->model)); |
316 | + |
317 | + /* Test append */ |
318 | + row_spec[0] = g_variant_new_int32 (25); |
319 | + row_spec[1] = g_variant_new_string ("Sorta sorted"); |
320 | + kter = dee_model_insert_row_sorted_with_sizes (fix->model, row_spec, |
321 | + sized_cmp_col_0, |
322 | + "test-user-data"); |
323 | + g_assert (kter != dee_model_get_last_iter (fix->model)); |
324 | + g_assert (kter != dee_model_get_first_iter (fix->model)); |
325 | + g_assert (iter == dee_model_get_first_iter (fix->model)); |
326 | + g_assert (kter != iter); |
327 | + |
328 | + g_assert_cmpint (2, ==, dee_model_get_n_rows (fix->model)); |
329 | + g_assert (kter == dee_model_next (fix->model, iter)); |
330 | + |
331 | + /* Test insert in between rows */ |
332 | + row_spec[0] = g_variant_new_int32 (26); |
333 | + row_spec[1] = g_variant_new_string ("Sorta sorted"); |
334 | + jter = dee_model_insert_row_sorted_with_sizes (fix->model, row_spec, |
335 | + sized_cmp_col_0, |
336 | + "test-user-data"); |
337 | + g_assert (jter != dee_model_get_last_iter (fix->model)); |
338 | + g_assert (jter != dee_model_get_first_iter (fix->model)); |
339 | + g_assert (iter == dee_model_get_first_iter (fix->model)); |
340 | + g_assert (jter != iter); |
341 | + g_assert (jter != kter); |
342 | + |
343 | + g_assert (jter == dee_model_next (fix->model, iter)); |
344 | + g_assert (kter == dee_model_next (fix->model, jter)); |
345 | + g_assert (dee_model_get_last_iter (fix->model) == dee_model_next (fix->model, kter)); |
346 | + |
347 | + /* Test prepend */ |
348 | + row_spec[0] = g_variant_new_int32 (28); |
349 | + row_spec[1] = g_variant_new_string ("Sorta sorted"); |
350 | + hter = dee_model_insert_row_sorted_with_sizes (fix->model, row_spec, |
351 | + sized_cmp_col_0, |
352 | + "test-user-data"); |
353 | + g_assert (hter == dee_model_get_first_iter (fix->model)); |
354 | + g_assert (iter == dee_model_next (fix->model, hter)); |
355 | + |
356 | + g_assert_cmpint (4, ==, dee_model_get_n_rows (fix->model)); |
357 | + |
358 | + /* Test find() again now that we have data in the model */ |
359 | + DeeModelIter *result; |
360 | + row_spec[0] = g_variant_new_int32 (24); |
361 | + row_spec[1] = g_variant_new_string (""); |
362 | + result = dee_model_find_row_sorted_with_sizes (fix->model, row_spec, |
363 | + sized_cmp_col_0, |
364 | + "test-user-data", NULL); |
365 | + g_assert (result == dee_model_get_last_iter (fix->model)); |
366 | + row_spec[0] = g_variant_new_int32 (28); |
367 | + row_spec[1] = g_variant_new_string (""); |
368 | + result = dee_model_find_row_sorted_with_sizes (fix->model, row_spec, |
369 | + sized_cmp_col_0, |
370 | + "test-user-data", NULL); |
371 | + g_assert (result == hter); |
372 | + |
373 | + /* Test find(). With non-NULL was_found arg */ |
374 | + was_found = FALSE; |
375 | + row_spec[0] = g_variant_new_int32 (24); |
376 | + row_spec[1] = g_variant_new_string (""); |
377 | + result = dee_model_find_row_sorted_with_sizes (fix->model, row_spec, |
378 | + sized_cmp_col_0, |
379 | + "test-user-data", &was_found); |
380 | + g_assert (result == dee_model_get_last_iter (fix->model)); |
381 | + row_spec[0] = g_variant_new_int32 (28); |
382 | + row_spec[1] = g_variant_new_string (""); |
383 | + result = dee_model_find_row_sorted_with_sizes (fix->model, row_spec, |
384 | + sized_cmp_col_0, |
385 | + "test-user-data", &was_found); |
386 | + g_assert (was_found); |
387 | + g_assert (result == hter); |
388 | +} |
389 | + |
390 | |
391 | === modified file 'vapi/dee-1.0.vapi' |
392 | --- vapi/dee-1.0.vapi 2012-03-19 11:18:50 +0000 |
393 | +++ vapi/dee-1.0.vapi 2012-08-15 13:38:19 +0000 |
394 | @@ -208,6 +208,7 @@ |
395 | public abstract unowned Dee.ModelIter append_row ([CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_members); |
396 | public abstract void clear (); |
397 | public abstract unowned Dee.ModelIter find_row_sorted ([CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_spec, [CCode (delegate_target_pos = 2.5)] Dee.CompareRowFunc cmp_func, out bool out_was_found); |
398 | + public unowned Dee.ModelIter find_row_sorted_with_sizes ([CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_spec, [CCode (delegate_target_pos = 2.5)] Dee.CompareRowSizedFunc cmp_func, out bool out_was_found); |
399 | public unowned Dee.ModelIter find_sorted ([CCode (delegate_target_pos = 1.5)] Dee.CompareRowFunc cmp_func, out bool out_was_found, ...); |
400 | public void @get (Dee.ModelIter iter, ...); |
401 | public abstract bool get_bool (Dee.ModelIter iter, uint column); |
402 | @@ -235,6 +236,7 @@ |
403 | public abstract unowned Dee.ModelIter insert_row (uint pos, [CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_members); |
404 | public abstract unowned Dee.ModelIter insert_row_before (Dee.ModelIter iter, [CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_members); |
405 | public abstract unowned Dee.ModelIter insert_row_sorted ([CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_members, Dee.CompareRowFunc cmp_func); |
406 | + public unowned Dee.ModelIter insert_row_sorted_with_sizes ([CCode (array_length = false, array_null_terminated = true)] GLib.Variant[] row_members, Dee.CompareRowSizedFunc cmp_func); |
407 | public unowned Dee.ModelIter insert_sorted ([CCode (delegate_target_pos = 1.5)] Dee.CompareRowFunc cmp_func, ...); |
408 | public abstract bool is_first (Dee.ModelIter iter); |
409 | public abstract bool is_last (Dee.ModelIter iter); |
410 | @@ -343,6 +345,8 @@ |
411 | [CCode (cheader_filename = "dee.h", instance_pos = 2.9)] |
412 | public delegate int CompareRowFunc ([CCode (array_length = false)] GLib.Variant[] row1, [CCode (array_length = false)] GLib.Variant[] row2); |
413 | [CCode (cheader_filename = "dee.h", instance_pos = 2.9)] |
414 | + public delegate int CompareRowSizedFunc ([CCode (array_length_cname = "row1_length", array_length_pos = 1.5, array_length_type = "guint")] GLib.Variant[] row1, [CCode (array_length_cname = "row2_length", array_length_pos = 2.1, array_length_type = "guint")] GLib.Variant[] row2); |
415 | + [CCode (cheader_filename = "dee.h", instance_pos = 2.9)] |
416 | public delegate void FilterMapFunc (Dee.Model orig_model, Dee.FilterModel filter_model); |
417 | [CCode (cheader_filename = "dee.h", instance_pos = 3.9)] |
418 | public delegate bool FilterMapNotify (Dee.Model orig_model, Dee.ModelIter orig_iter, Dee.FilterModel filter_model); |
Looks, good. Just one question:
30 + # FIXME: perhaps override __eq__ on ModelIter?
is this still applicable?