/* * Copyright (c) 2020 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #define RANDOM_COUNT 256 // Returns a random 32 bit integer static uint32_t random_32() { uint32_t result = rand(); return result; } // Returns a random 64 bit integer thats not 0 or ~0 static uint64_t random_64() { return (uint64_t)random_32() | ((uint64_t)random_32() << 32); } static bool array_contains(uint32_t *array, int size, uint32_t entry) { for (int i = 0; i < size; i++) { if(array[i] == entry) { return true; } } return false; } // Returns a random 32 bit integer thats not in the array static uint32_t random_32_not_in_array(uint32_t *array, int size) { uint32_t candidate; do { candidate = random_32(); } while (array_contains(array, size, candidate)); return candidate; } #define RUN_MAP_RANDOM(MAP, KEY_CONV) \ { \ T_LOG("Start run map for " #MAP); \ \ uint32_t keys[RANDOM_COUNT]; \ void *vals[RANDOM_COUNT]; \ \ os_map_init(&MAP, NULL); \ \ /* Insert random values for sequential keys to the map */ \ for (int i = 0; i < RANDOM_COUNT; i++) { \ uint32_t key = random_32_not_in_array(keys, i); \ void *val = (void *)random_64(); \ T_LOG("Inserting 0x%x, 0x%llx", key, (unsigned long long)val); \ os_map_insert(&MAP, KEY_CONV(key), val); \ keys[i] = key; \ vals[i] = val; \ } \ \ /* Find all the values */ \ for (int i = 0; i < RANDOM_COUNT; i++) { \ uint32_t key = keys[i]; \ void *expected_val = vals[i]; \ void *actual_val = os_map_find(&MAP, KEY_CONV(key)); \ if (expected_val == actual_val) { \ T_PASS("Found 0x%x, 0x%llx", key, \ (unsigned long long)expected_val); \ } else { \ T_FAIL("Incorrect find for 0x%x, Expected 0x%llx but got 0x%llx", \ key, (unsigned long long)expected_val, \ (unsigned long long)actual_val); \ } \ } \ \ /* Find some nonexistant values */ \ for (int i = 0; i < RANDOM_COUNT; i++) { \ uint32_t key = random_32_not_in_array(keys, RANDOM_COUNT); \ void *val = os_map_find(&MAP, KEY_CONV(key)); \ if (val == NULL) { \ T_PASS("Did not find value for nonexistant key 0x%x", \ key); \ } else { \ T_FAIL("Found value for nonexistant key 0x%x (0x%llx)", \ key, (unsigned long long)val); \ } \ } \ \ /* Remove half of the values */ \ for (int i = 0; i < RANDOM_COUNT; i+=2) { \ uint32_t key = keys[i]; \ os_map_delete(&MAP, KEY_CONV(key)); \ vals[i] == NULL; \ } \ \ /* Find the half that are still there */ \ for (int i = 1; i < RANDOM_COUNT; i+=2) { \ uint32_t key = keys[i]; \ void *expected_val = vals[i]; \ void *actual_val = os_map_find(&MAP, KEY_CONV(key)); \ if (expected_val == actual_val) { \ T_PASS("Found 0x%x, 0x%llx", key, \ (unsigned long long)expected_val); \ } else { \ T_FAIL("Incorrect find for 0x%x, Expected 0x%llx but got 0x%llx", \ key, (unsigned long long)expected_val, \ (unsigned long long)actual_val); \ } \ } \ \ /* Find the half that aren't there */ \ for (int i = 0; i < RANDOM_COUNT; i+=2) { \ uint32_t key = keys[i]; \ void *val = os_map_find(&MAP, KEY_CONV(key)); \ if (val == NULL) { \ T_PASS("Did not find value for nonexistant key 0x%x", \ key); \ } else { \ T_FAIL("Found value for nonexistant key 0x%x (0x%llx)", \ key, (unsigned long long)val); \ } \ } \ \ os_map_destroy(&MAP); \ } uint64_t key_conv_32_to_64(uint32_t key) { return (uint64_t)key | ((uint64_t)key << 32); } uint32_t key_conv_32_to_32(uint32_t key) { return key; } const char *key_conv_32_to_string(uint32_t key) { // TODO: Make this not leak char *output; assert(asprintf(&output, "0x%x", key) > 0); return (const char *)output; } T_DECL(map_random_64, "Make sure 64 bit map works for a bunch of random entries", T_META("owner", "Core Darwin Daemons & Tools")) { os_map_64_t random_64_map; RUN_MAP_RANDOM(random_64_map, key_conv_32_to_64); } T_DECL(map_random_32, "Make sure 32 bit map works for a bunch of random entries", T_META("owner", "Core Darwin Daemons & Tools")) { os_map_32_t random_32_map; RUN_MAP_RANDOM(random_32_map, key_conv_32_to_32); } T_DECL(map_random_string, "Make sure string map works for a bunch of random entries", T_META("owner", "Core Darwin Daemons & Tools"), T_META_CHECK_LEAKS(false)) { os_map_str_t random_s_map; RUN_MAP_RANDOM(random_s_map, key_conv_32_to_string); }