test_sanim_visit.c (17173B)
1 /* Copyright (C) 2018-2026 |Méso|Star> (contact@meso-star.com) 2 * Copyright (C) 2016-2018 CNRS 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #include "sanim.h" 18 #include "test_sanim_utils.h" 19 20 #include <rsys/double33.h> 21 22 #include <rsys/hash_table.h> 23 struct transform { double transform[12]; }; 24 #define HTABLE_NAME transforms 25 #define HTABLE_KEY const struct sanim_node * 26 #define HTABLE_DATA struct transform 27 #include <rsys/hash_table.h> 28 29 static res_T 30 store_transform(const struct sanim_node* n, const double transform[12], void* data) { 31 struct htable_transforms* transforms = data; 32 struct transform tr; 33 int i; 34 for (i = 0; i < 12; i++) tr.transform[i] = transform[i]; 35 return htable_transforms_set(transforms, &n, &tr); 36 } 37 38 static void 39 check_visit 40 (struct mem_allocator allocator, 41 double in_dir[3], 42 struct my_type *root, 43 struct my_type *pivot, 44 struct my_type *leaf) 45 { 46 struct htable_transforms transforms; 47 struct transform *tr; 48 const struct sanim_node *key; 49 double transform[12]; 50 51 htable_transforms_init(&allocator, &transforms); 52 CHK(sanim_node_visit_tree( 53 &root->node, in_dir, &transforms, store_transform) == RES_OK); 54 CHK(htable_transforms_size_get(&transforms) == 3); 55 key = &leaf->node; 56 tr = htable_transforms_find(&transforms, &key); 57 CHK(tr != NULL); 58 CHK(my_type_solve_pivot(pivot, in_dir) == RES_OK); 59 CHK(my_type_get_transform(leaf, transform) == RES_OK); 60 key = &leaf->node; 61 tr = htable_transforms_find(&transforms, &key); 62 CHK(tr != NULL); 63 d34_eq_eps(tr->transform, transform, 1e-10); 64 CHK(my_type_get_transform(pivot, transform) == RES_OK); 65 key = &pivot->node; 66 tr = htable_transforms_find(&transforms, &key); 67 CHK(tr != NULL); 68 d34_eq_eps(tr->transform, transform, 1e-10); 69 CHK(my_type_get_transform(root, transform) == RES_OK); 70 key = &root->node; 71 tr = htable_transforms_find(&transforms, &key); 72 CHK(tr != NULL); 73 d34_eq_eps(tr->transform, transform, 1e-10); 74 htable_transforms_release(&transforms); 75 } 76 77 int 78 main(int argc, char** argv) 79 { 80 struct mem_allocator allocator; 81 struct my_type *t1, *t2, *t3, *target; 82 struct sanim_pivot pivot = SANIM_PIVOT_NULL; 83 struct sanim_tracking tracking = SANIM_TRACKING_NULL; 84 double transl[3], rot[3], in_dir[3], tmp[3]; 85 (void) argc, (void) argv; 86 87 mem_init_proxy_allocator(&allocator, &mem_default_allocator); 88 89 /* 90 * 1 axis pivots 91 * (in/out dirs can be off the YZ plane) 92 */ 93 94 /* 1 axis tracking sun */ 95 96 tracking.policy = TRACKING_SUN; 97 pivot.type = PIVOT_SINGLE_AXIS; 98 d3(pivot.data.pivot1.ref_normal, 0, 0, 1); 99 100 /* ref_normal not in the YZ plane */ 101 CHK(my_type_create(&allocator, &t1) == RES_OK); 102 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 103 CHK(my_type_create(&allocator, &t3) == RES_OK); 104 105 CHK(my_type_add_child(t1, t2) == RES_OK); 106 CHK(my_type_add_child(t2, t3) == RES_OK); 107 108 d3_splat(transl, +1); 109 d3(rot, 0, 0, PI / 2); 110 CHK(my_type_set_translation(t1, transl) == RES_OK); 111 CHK(my_type_set_rotations(t1, rot) == RES_OK); 112 CHK(my_type_set_translation(t2, transl) == RES_OK); 113 CHK(my_type_set_translation(t3, transl) == RES_OK); 114 115 d3(in_dir, 1, 0.2, -1); 116 check_visit(allocator, in_dir, t1, t2, t3); 117 118 CHK(my_type_ref_put(t1) == RES_OK); 119 CHK(my_type_ref_put(t2) == RES_OK); 120 CHK(my_type_ref_put(t3) == RES_OK); 121 122 /* 1 axis tracking with a fixed output dir */ 123 124 tracking.policy = TRACKING_OUT_DIR; 125 pivot.type = PIVOT_SINGLE_AXIS; 126 d3(pivot.data.pivot1.ref_normal, 0, 0, 1); 127 d3(tracking.data.out_dir.u, 1, 0, 1); 128 129 CHK(my_type_create(&allocator, &t1) == RES_OK); 130 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 131 CHK(my_type_create(&allocator, &t3) == RES_OK); 132 133 CHK(my_type_add_child(t1, t2) == RES_OK); 134 CHK(my_type_add_child(t2, t3) == RES_OK); 135 136 CHK(my_type_set_translation(t1, transl) == RES_OK); 137 CHK(my_type_set_rotations(t1, rot) == RES_OK); 138 CHK(my_type_set_translation(t2, transl) == RES_OK); 139 CHK(my_type_set_translation(t3, transl) == RES_OK); 140 141 d3(in_dir, 1, -0.3, -1); 142 check_visit(allocator, in_dir, t1, t2, t3); 143 144 CHK(my_type_ref_put(t1) == RES_OK); 145 CHK(my_type_ref_put(t2) == RES_OK); 146 CHK(my_type_ref_put(t3) == RES_OK); 147 148 /* 1 axis tracking a target point */ 149 150 tracking.policy = TRACKING_POINT; 151 pivot.type = PIVOT_SINGLE_AXIS; 152 d3(pivot.data.pivot1.ref_normal, 0, 0, 1); 153 d3(pivot.data.pivot1.ref_point, 0, 0, 0); 154 d3(tracking.data.point.target, 0, 0, 30); 155 tracking.data.point.target_is_local = 1; 156 157 CHK(my_type_create(&allocator, &t1) == RES_OK); 158 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 159 CHK(my_type_create(&allocator, &t3) == RES_OK); 160 161 CHK(my_type_add_child(t1, t2) == RES_OK); 162 CHK(my_type_add_child(t2, t3) == RES_OK); 163 164 CHK(my_type_set_translation(t1, transl) == RES_OK); 165 CHK(my_type_set_rotations(t1, rot) == RES_OK); 166 CHK(my_type_set_translation(t2, transl) == RES_OK); 167 CHK(my_type_set_translation(t3, transl) == RES_OK); 168 169 d3(in_dir, 1, 0.1, 0); 170 check_visit(allocator, in_dir, t1, t2, t3); 171 172 CHK(my_type_ref_put(t1) == RES_OK); 173 CHK(my_type_ref_put(t2) == RES_OK); 174 CHK(my_type_ref_put(t3) == RES_OK); 175 176 tracking.policy = TRACKING_POINT; 177 pivot.type = PIVOT_SINGLE_AXIS; 178 d3(pivot.data.pivot1.ref_normal, 0, 0, 1); 179 d3(pivot.data.pivot1.ref_point, 0, 0, 10 * sqrt(2)); 180 d3(tracking.data.point.target, 0, 10, 30); 181 tracking.data.point.target_is_local = 1; 182 183 CHK(my_type_create(&allocator, &t1) == RES_OK); 184 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 185 CHK(my_type_create(&allocator, &t3) == RES_OK); 186 187 CHK(my_type_add_child(t1, t2) == RES_OK); 188 CHK(my_type_add_child(t2, t3) == RES_OK); 189 190 CHK(my_type_set_translation(t1, transl) == RES_OK); 191 CHK(my_type_set_rotations(t1, rot) == RES_OK); 192 CHK(my_type_set_translation(t2, transl) == RES_OK); 193 CHK(my_type_set_translation(t3, transl) == RES_OK); 194 195 d3(in_dir, 1, 0.1, 0); 196 check_visit(allocator, in_dir, t1, t2, t3); 197 198 CHK(my_type_ref_put(t1) == RES_OK); 199 CHK(my_type_ref_put(t2) == RES_OK); 200 CHK(my_type_ref_put(t3) == RES_OK); 201 202 /* same 1 axis tracking with a non-local target point */ 203 204 tracking.policy = TRACKING_POINT; 205 pivot.type = PIVOT_SINGLE_AXIS; 206 d3(pivot.data.pivot1.ref_normal, 0, 0, 1); 207 d3(pivot.data.pivot1.ref_point, 0, 0, 10 * sqrt(2)); 208 d3(tracking.data.point.target, -10, 2, 32); 209 tracking.data.point.target_is_local = 0; 210 211 CHK(my_type_create(&allocator, &t1) == RES_OK); 212 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 213 CHK(my_type_create(&allocator, &t3) == RES_OK); 214 215 CHK(my_type_add_child(t1, t2) == RES_OK); 216 CHK(my_type_add_child(t2, t3) == RES_OK); 217 218 CHK(my_type_set_translation(t1, transl) == RES_OK); 219 CHK(my_type_set_rotations(t1, rot) == RES_OK); 220 CHK(my_type_set_translation(t2, transl) == RES_OK); 221 CHK(my_type_set_translation(t3, transl) == RES_OK); 222 223 d3(in_dir, 1, -0.5, 0); 224 check_visit(allocator, in_dir, t1, t2, t3); 225 226 CHK(my_type_ref_put(t1) == RES_OK); 227 CHK(my_type_ref_put(t2) == RES_OK); 228 CHK(my_type_ref_put(t3) == RES_OK); 229 230 tracking.policy = TRACKING_POINT; 231 pivot.type = PIVOT_SINGLE_AXIS; 232 d3(pivot.data.pivot1.ref_normal, 0, 0, 1); 233 d3(pivot.data.pivot1.ref_point, 0, 5, 5); 234 d3(tracking.data.point.target, -12, 2, -10); 235 tracking.data.point.target_is_local = 0; 236 237 CHK(my_type_create(&allocator, &t1) == RES_OK); 238 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 239 CHK(my_type_create(&allocator, &t3) == RES_OK); 240 241 CHK(my_type_add_child(t1, t2) == RES_OK); 242 CHK(my_type_add_child(t2, t3) == RES_OK); 243 244 CHK(my_type_set_translation(t1, transl) == RES_OK); 245 CHK(my_type_set_rotations(t1, rot) == RES_OK); 246 CHK(my_type_set_translation(t2, transl) == RES_OK); 247 CHK(my_type_set_translation(t3, transl) == RES_OK); 248 249 d3(in_dir, 1, 0, -1); 250 check_visit(allocator, in_dir, t1, t2, t3); 251 252 CHK(my_type_ref_put(t1) == RES_OK); 253 CHK(my_type_ref_put(t2) == RES_OK); 254 CHK(my_type_ref_put(t3) == RES_OK); 255 256 /* 1 axis tracking a node target */ 257 258 CHK(my_type_create(&allocator, &target) == RES_OK); 259 d3(tmp, 0, 0, 10 * sqrt(2)); 260 CHK(my_type_set_translation(target, tmp) == RES_OK); 261 262 d3(pivot.data.pivot1.ref_normal, 0, 0, 1); 263 d3(pivot.data.pivot1.ref_point, 0, 0, 0); 264 CHK(my_type_track_me(target, &tracking) == RES_OK); 265 266 CHK(my_type_create(&allocator, &t1) == RES_OK); 267 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 268 CHK(my_type_create(&allocator, &t3) == RES_OK); 269 270 CHK(my_type_add_child(t1, t2) == RES_OK); 271 CHK(my_type_add_child(t2, t3) == RES_OK); 272 273 CHK(my_type_set_translation(t1, transl) == RES_OK); 274 CHK(my_type_set_rotations(t1, rot) == RES_OK); 275 CHK(my_type_set_translation(t2, transl) == RES_OK); 276 CHK(my_type_set_translation(t3, transl) == RES_OK); 277 278 d3(in_dir, 1, 0.1, 0); 279 check_visit(allocator, in_dir, t1, t2, t3); 280 281 CHK(my_type_ref_put(t1) == RES_OK); 282 CHK(my_type_ref_put(t2) == RES_OK); 283 CHK(my_type_ref_put(t3) == RES_OK); 284 CHK(my_type_ref_put(target) == RES_OK); 285 286 /* 287 * 2 axis pivots 288 * (using only one axis at a time) 289 */ 290 291 /* 2 axis tracking sun */ 292 293 tracking.policy = TRACKING_SUN; 294 pivot.type = PIVOT_TWO_AXIS; 295 pivot.data.pivot2.spacing = 1; 296 d3(pivot.data.pivot2.ref_point, 0, 0, 1); 297 298 CHK(my_type_create(&allocator, &t1) == RES_OK); 299 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 300 CHK(my_type_create(&allocator, &t3) == RES_OK); 301 302 CHK(my_type_add_child(t1, t2) == RES_OK); 303 CHK(my_type_add_child(t2, t3) == RES_OK); 304 305 d3_splat(transl, +1); 306 d3(rot, 0, 0, PI / 2); 307 CHK(my_type_set_translation(t1, transl) == RES_OK); 308 CHK(my_type_set_rotations(t1, rot) == RES_OK); 309 CHK(my_type_set_translation(t2, transl) == RES_OK); 310 CHK(my_type_set_translation(t3, transl) == RES_OK); 311 312 d3(in_dir, 1, 0, -1); 313 check_visit(allocator, in_dir, t1, t2, t3); 314 315 d3(in_dir, 0, 1, 0); 316 check_visit(allocator, in_dir, t1, t2, t3); 317 318 CHK(my_type_ref_put(t1) == RES_OK); 319 CHK(my_type_ref_put(t2) == RES_OK); 320 CHK(my_type_ref_put(t3) == RES_OK); 321 322 /* 2 axis tracking sun */ 323 324 tracking.policy = TRACKING_SUN; 325 pivot.type = PIVOT_TWO_AXIS; 326 pivot.data.pivot2.spacing = 1; 327 328 CHK(my_type_create(&allocator, &t1) == RES_OK); 329 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 330 CHK(my_type_create(&allocator, &t3) == RES_OK); 331 332 CHK(my_type_add_child(t1, t2) == RES_OK); 333 CHK(my_type_add_child(t2, t3) == RES_OK); 334 335 d3_splat(transl, +1); 336 d3(rot, 0, 0, PI / 2); 337 CHK(my_type_set_translation(t1, transl) == RES_OK); 338 CHK(my_type_set_rotations(t1, rot) == RES_OK); 339 CHK(my_type_set_translation(t2, transl) == RES_OK); 340 CHK(my_type_set_translation(t3, transl) == RES_OK); 341 342 d3(in_dir, 1, 0, -1); 343 check_visit(allocator, in_dir, t1, t2, t3); 344 345 d3(in_dir, 0, 1, 0); 346 check_visit(allocator, in_dir, t1, t2, t3); 347 348 CHK(my_type_ref_put(t1) == RES_OK); 349 CHK(my_type_ref_put(t2) == RES_OK); 350 CHK(my_type_ref_put(t3) == RES_OK); 351 352 /* 2 axis tracking with a fixed output dir */ 353 354 tracking.policy = TRACKING_OUT_DIR; 355 pivot.type = PIVOT_TWO_AXIS; 356 pivot.data.pivot2.spacing = 1; 357 d3(tracking.data.out_dir.u, 0, 1, 0); 358 359 CHK(my_type_create(&allocator, &t1) == RES_OK); 360 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 361 CHK(my_type_create(&allocator, &t3) == RES_OK); 362 363 CHK(my_type_add_child(t1, t2) == RES_OK); 364 CHK(my_type_add_child(t2, t3) == RES_OK); 365 366 CHK(my_type_set_translation(t1, transl) == RES_OK); 367 CHK(my_type_set_rotations(t1, rot) == RES_OK); 368 CHK(my_type_set_translation(t2, transl) == RES_OK); 369 CHK(my_type_set_translation(t3, transl) == RES_OK); 370 371 d3(in_dir, 0, 0, -1); 372 check_visit(allocator, in_dir, t1, t2, t3); 373 374 d3(in_dir, -1, 0, 0); 375 check_visit(allocator, in_dir, t1, t2, t3); 376 377 CHK(my_type_ref_put(t1) == RES_OK); 378 CHK(my_type_ref_put(t2) == RES_OK); 379 CHK(my_type_ref_put(t3) == RES_OK); 380 381 /* 2 axis tracking a target point */ 382 383 tracking.policy = TRACKING_POINT; 384 pivot.type = PIVOT_TWO_AXIS; 385 pivot.data.pivot2.spacing = 0; 386 d3(pivot.data.pivot2.ref_point, 0, 0, 0); 387 d3(tracking.data.point.target, 30, 0, 0); 388 tracking.data.point.target_is_local = 1; 389 390 CHK(my_type_create(&allocator, &t1) == RES_OK); 391 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 392 CHK(my_type_create(&allocator, &t3) == RES_OK); 393 394 CHK(my_type_add_child(t1, t2) == RES_OK); 395 CHK(my_type_add_child(t2, t3) == RES_OK); 396 397 CHK(my_type_set_translation(t1, transl) == RES_OK); 398 CHK(my_type_set_rotations(t1, rot) == RES_OK); 399 CHK(my_type_set_translation(t2, transl) == RES_OK); 400 CHK(my_type_set_translation(t3, transl) == RES_OK); 401 402 d3(in_dir, -1, 0, 0); 403 check_visit(allocator, in_dir, t1, t2, t3); 404 405 CHK(my_type_ref_put(t1) == RES_OK); 406 CHK(my_type_ref_put(t2) == RES_OK); 407 CHK(my_type_ref_put(t3) == RES_OK); 408 409 tracking.policy = TRACKING_POINT; 410 pivot.type = PIVOT_TWO_AXIS; 411 pivot.data.pivot2.spacing = sqrt(2); 412 d3(pivot.data.pivot2.ref_point, 0, 10 * sqrt(2), 0); 413 d3(tracking.data.point.target, 30, -11, 0); 414 tracking.data.point.target_is_local = 1; 415 416 CHK(my_type_create(&allocator, &t1) == RES_OK); 417 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 418 CHK(my_type_create(&allocator, &t3) == RES_OK); 419 420 CHK(my_type_add_child(t1, t2) == RES_OK); 421 CHK(my_type_add_child(t2, t3) == RES_OK); 422 423 CHK(my_type_set_translation(t1, transl) == RES_OK); 424 CHK(my_type_set_rotations(t1, rot) == RES_OK); 425 CHK(my_type_set_translation(t2, transl) == RES_OK); 426 CHK(my_type_set_translation(t3, transl) == RES_OK); 427 428 d3(in_dir, -1, 0, 0); 429 check_visit(allocator, in_dir, t1, t2, t3); 430 431 CHK(my_type_ref_put(t1) == RES_OK); 432 CHK(my_type_ref_put(t2) == RES_OK); 433 CHK(my_type_ref_put(t3) == RES_OK); 434 435 tracking.policy = TRACKING_POINT; 436 pivot.type = PIVOT_TWO_AXIS; 437 pivot.data.pivot2.spacing = 1; 438 d3(pivot.data.pivot2.ref_point, 0, 10 * sqrt(2), 0); 439 d3(tracking.data.point.target, 0, 30, 10); 440 tracking.data.point.target_is_local = 1; 441 442 CHK(my_type_create(&allocator, &t1) == RES_OK); 443 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 444 CHK(my_type_create(&allocator, &t3) == RES_OK); 445 446 CHK(my_type_add_child(t1, t2) == RES_OK); 447 CHK(my_type_add_child(t2, t3) == RES_OK); 448 449 CHK(my_type_set_translation(t1, transl) == RES_OK); 450 CHK(my_type_set_rotations(t1, rot) == RES_OK); 451 CHK(my_type_set_translation(t2, transl) == RES_OK); 452 CHK(my_type_set_translation(t3, transl) == RES_OK); 453 454 d3(in_dir, 0, 0, -1); 455 check_visit(allocator, in_dir, t1, t2, t3); 456 457 CHK(my_type_ref_put(t1) == RES_OK); 458 CHK(my_type_ref_put(t2) == RES_OK); 459 CHK(my_type_ref_put(t3) == RES_OK); 460 461 tracking.policy = TRACKING_POINT; 462 pivot.type = PIVOT_TWO_AXIS; 463 pivot.data.pivot2.spacing = 1; 464 d3(pivot.data.pivot2.ref_point, 0, 10 * sqrt(2), 0); 465 d3(tracking.data.point.target, 0, 30, 12); 466 tracking.data.point.target_is_local = 0; 467 468 CHK(my_type_create(&allocator, &t1) == RES_OK); 469 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 470 CHK(my_type_create(&allocator, &t3) == RES_OK); 471 472 CHK(my_type_add_child(t1, t2) == RES_OK); 473 CHK(my_type_add_child(t2, t3) == RES_OK); 474 475 CHK(my_type_set_translation(t1, transl) == RES_OK); 476 CHK(my_type_set_rotations(t1, rot) == RES_OK); 477 CHK(my_type_set_translation(t2, transl) == RES_OK); 478 CHK(my_type_set_translation(t3, transl) == RES_OK); 479 480 d3(in_dir, 0, 0, -1); 481 check_visit(allocator, in_dir, t1, t2, t3); 482 483 CHK(my_type_ref_put(t1) == RES_OK); 484 CHK(my_type_ref_put(t2) == RES_OK); 485 CHK(my_type_ref_put(t3) == RES_OK); 486 487 tracking.policy = TRACKING_POINT; 488 pivot.type = PIVOT_TWO_AXIS; 489 pivot.data.pivot2.spacing = 1; 490 d3(pivot.data.pivot2.ref_point, 10, 8 * sqrt(2), 5 * sqrt(2)); 491 d3(tracking.data.point.target, 10, 12, 15); 492 tracking.data.point.target_is_local = 0; 493 494 CHK(my_type_create(&allocator, &t1) == RES_OK); 495 CHK(my_type_pivot_create(&allocator, &pivot, &tracking, &t2) == RES_OK); 496 CHK(my_type_create(&allocator, &t3) == RES_OK); 497 498 CHK(my_type_add_child(t1, t2) == RES_OK); 499 CHK(my_type_add_child(t2, t3) == RES_OK); 500 501 CHK(my_type_set_translation(t1, transl) == RES_OK); 502 CHK(my_type_set_rotations(t1, rot) == RES_OK); 503 CHK(my_type_set_translation(t2, transl) == RES_OK); 504 CHK(my_type_set_translation(t3, transl) == RES_OK); 505 506 d3(in_dir, 0, 0, -1); 507 check_visit(allocator, in_dir, t1, t2, t3); 508 509 /* release memory */ 510 CHK(my_type_ref_put(t1) == RES_OK); 511 CHK(my_type_ref_put(t2) == RES_OK); 512 CHK(my_type_ref_put(t3) == RES_OK); 513 check_memory_allocator(&allocator); 514 mem_shutdown_proxy_allocator(&allocator); 515 CHK(mem_allocated_size() == 0); 516 return 0; 517 }