/* * * Copyright 2015 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "src/core/lib/avl/avl.h" #include <stdio.h> #include <string.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> #include "src/core/lib/gpr/useful.h" #include "test/core/util/test_config.h" static int* box(int x) { int* b = static_cast<int*>(gpr_malloc(sizeof(*b))); *b = x; return b; } static long int_compare(void* int1, void* int2, void* unused) { return (*static_cast<int*>(int1)) - (*static_cast<int*>(int2)); } static void* int_copy(void* p, void* unused) { return box(*static_cast<int*>(p)); } static void destroy(void* p, void* unused) { gpr_free(p); } static const grpc_avl_vtable int_int_vtable = {destroy, int_copy, int_compare, destroy, int_copy}; static void check_get(grpc_avl avl, int key, int value) { int* k = box(key); GPR_ASSERT(*(int*)grpc_avl_get(avl, k, nullptr) == value); gpr_free(k); } static void check_negget(grpc_avl avl, int key) { int* k = box(key); GPR_ASSERT(grpc_avl_get(avl, k, nullptr) == nullptr); gpr_free(k); } static grpc_avl remove_int(grpc_avl avl, int key) { int* k = box(key); avl = grpc_avl_remove(avl, k, nullptr); gpr_free(k); return avl; } static void test_get(void) { grpc_avl avl; gpr_log(GPR_DEBUG, "test_get"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(1), box(11), nullptr); avl = grpc_avl_add(avl, box(2), box(22), nullptr); avl = grpc_avl_add(avl, box(3), box(33), nullptr); check_get(avl, 1, 11); check_get(avl, 2, 22); check_get(avl, 3, 33); check_negget(avl, 4); grpc_avl_unref(avl, nullptr); } static void test_ll(void) { grpc_avl avl; gpr_log(GPR_DEBUG, "test_ll"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(5), box(1), nullptr); avl = grpc_avl_add(avl, box(4), box(2), nullptr); avl = grpc_avl_add(avl, box(3), box(3), nullptr); GPR_ASSERT(*(int*)avl.root->key == 4); GPR_ASSERT(*(int*)avl.root->left->key == 3); GPR_ASSERT(*(int*)avl.root->right->key == 5); grpc_avl_unref(avl, nullptr); } static void test_lr(void) { grpc_avl avl; gpr_log(GPR_DEBUG, "test_lr"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(5), box(1), nullptr); avl = grpc_avl_add(avl, box(3), box(2), nullptr); avl = grpc_avl_add(avl, box(4), box(3), nullptr); GPR_ASSERT(*(int*)avl.root->key == 4); GPR_ASSERT(*(int*)avl.root->left->key == 3); GPR_ASSERT(*(int*)avl.root->right->key == 5); grpc_avl_unref(avl, nullptr); } static void test_rr(void) { grpc_avl avl; gpr_log(GPR_DEBUG, "test_rr"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(3), box(1), nullptr); avl = grpc_avl_add(avl, box(4), box(2), nullptr); avl = grpc_avl_add(avl, box(5), box(3), nullptr); GPR_ASSERT(*(int*)avl.root->key == 4); GPR_ASSERT(*(int*)avl.root->left->key == 3); GPR_ASSERT(*(int*)avl.root->right->key == 5); grpc_avl_unref(avl, nullptr); } static void test_rl(void) { grpc_avl avl; gpr_log(GPR_DEBUG, "test_rl"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(3), box(1), nullptr); avl = grpc_avl_add(avl, box(5), box(2), nullptr); avl = grpc_avl_add(avl, box(4), box(3), nullptr); GPR_ASSERT(*(int*)avl.root->key == 4); GPR_ASSERT(*(int*)avl.root->left->key == 3); GPR_ASSERT(*(int*)avl.root->right->key == 5); grpc_avl_unref(avl, nullptr); } static void test_unbalanced(void) { grpc_avl avl; gpr_log(GPR_DEBUG, "test_unbalanced"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(5), box(1), nullptr); avl = grpc_avl_add(avl, box(4), box(2), nullptr); avl = grpc_avl_add(avl, box(3), box(3), nullptr); avl = grpc_avl_add(avl, box(2), box(4), nullptr); avl = grpc_avl_add(avl, box(1), box(5), nullptr); GPR_ASSERT(*(int*)avl.root->key == 4); GPR_ASSERT(*(int*)avl.root->left->key == 2); GPR_ASSERT(*(int*)avl.root->left->left->key == 1); GPR_ASSERT(*(int*)avl.root->left->right->key == 3); GPR_ASSERT(*(int*)avl.root->right->key == 5); grpc_avl_unref(avl, nullptr); } static void test_replace(void) { grpc_avl avl; gpr_log(GPR_DEBUG, "test_replace"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(1), box(1), nullptr); avl = grpc_avl_add(avl, box(1), box(2), nullptr); check_get(avl, 1, 2); check_negget(avl, 2); grpc_avl_unref(avl, nullptr); } static void test_remove(void) { grpc_avl avl; grpc_avl avl3, avl4, avl5, avln; gpr_log(GPR_DEBUG, "test_remove"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(3), box(1), nullptr); avl = grpc_avl_add(avl, box(4), box(2), nullptr); avl = grpc_avl_add(avl, box(5), box(3), nullptr); avl3 = remove_int(grpc_avl_ref(avl, nullptr), 3); avl4 = remove_int(grpc_avl_ref(avl, nullptr), 4); avl5 = remove_int(grpc_avl_ref(avl, nullptr), 5); avln = remove_int(grpc_avl_ref(avl, nullptr), 1); grpc_avl_unref(avl, nullptr); check_negget(avl3, 3); check_get(avl3, 4, 2); check_get(avl3, 5, 3); grpc_avl_unref(avl3, nullptr); check_get(avl4, 3, 1); check_negget(avl4, 4); check_get(avl4, 5, 3); grpc_avl_unref(avl4, nullptr); check_get(avl5, 3, 1); check_get(avl5, 4, 2); check_negget(avl5, 5); grpc_avl_unref(avl5, nullptr); check_get(avln, 3, 1); check_get(avln, 4, 2); check_get(avln, 5, 3); grpc_avl_unref(avln, nullptr); } static void test_badcase1(void) { grpc_avl avl; gpr_log(GPR_DEBUG, "test_badcase1"); avl = grpc_avl_create(&int_int_vtable); avl = grpc_avl_add(avl, box(88), box(1), nullptr); avl = remove_int(avl, 643); avl = remove_int(avl, 983); avl = grpc_avl_add(avl, box(985), box(4), nullptr); avl = grpc_avl_add(avl, box(640), box(5), nullptr); avl = grpc_avl_add(avl, box(41), box(6), nullptr); avl = grpc_avl_add(avl, box(112), box(7), nullptr); avl = grpc_avl_add(avl, box(342), box(8), nullptr); avl = remove_int(avl, 1013); avl = grpc_avl_add(avl, box(434), box(10), nullptr); avl = grpc_avl_add(avl, box(520), box(11), nullptr); avl = grpc_avl_add(avl, box(231), box(12), nullptr); avl = grpc_avl_add(avl, box(852), box(13), nullptr); avl = remove_int(avl, 461); avl = grpc_avl_add(avl, box(108), box(15), nullptr); avl = grpc_avl_add(avl, box(806), box(16), nullptr); avl = grpc_avl_add(avl, box(827), box(17), nullptr); avl = remove_int(avl, 796); avl = grpc_avl_add(avl, box(340), box(19), nullptr); avl = grpc_avl_add(avl, box(498), box(20), nullptr); avl = grpc_avl_add(avl, box(203), box(21), nullptr); avl = grpc_avl_add(avl, box(751), box(22), nullptr); avl = grpc_avl_add(avl, box(150), box(23), nullptr); avl = remove_int(avl, 237); avl = grpc_avl_add(avl, box(830), box(25), nullptr); avl = remove_int(avl, 1007); avl = remove_int(avl, 394); avl = grpc_avl_add(avl, box(65), box(28), nullptr); avl = remove_int(avl, 904); avl = remove_int(avl, 123); avl = grpc_avl_add(avl, box(238), box(31), nullptr); avl = grpc_avl_add(avl, box(184), box(32), nullptr); avl = remove_int(avl, 331); avl = grpc_avl_add(avl, box(827), box(34), nullptr); check_get(avl, 830, 25); grpc_avl_unref(avl, nullptr); } static void test_stress(int amount_of_stress) { int added[1024]; int i, j; int deletions = 0; grpc_avl avl; unsigned seed = static_cast<unsigned>(time(nullptr)); gpr_log(GPR_DEBUG, "test_stress amount=%d seed=%u", amount_of_stress, seed); srand(static_cast<unsigned>(time(nullptr))); avl = grpc_avl_create(&int_int_vtable); memset(added, 0, sizeof(added)); for (i = 1; deletions < amount_of_stress; i++) { int idx = rand() % static_cast<int> GPR_ARRAY_SIZE(added); GPR_ASSERT(i); if (rand() < RAND_MAX / 2) { added[idx] = i; printf("avl = grpc_avl_add(avl, box(%d), box(%d), NULL); /* d=%d */\n", idx, i, deletions); avl = grpc_avl_add(avl, box(idx), box(i), nullptr); } else { deletions += (added[idx] != 0); added[idx] = 0; printf("avl = remove_int(avl, %d); /* d=%d */\n", idx, deletions); avl = remove_int(avl, idx); } for (j = 0; j < static_cast<int> GPR_ARRAY_SIZE(added); j++) { if (added[j] != 0) { check_get(avl, j, added[j]); } else { check_negget(avl, j); } } } grpc_avl_unref(avl, nullptr); } int main(int argc, char* argv[]) { grpc_test_init(argc, argv); test_get(); test_ll(); test_lr(); test_rr(); test_rl(); test_unbalanced(); test_replace(); test_remove(); test_badcase1(); test_stress(10); return 0; }