ufdt_prop_dict.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Copyright (C) 2016 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "ufdt_prop_dict.h"
  17. #include "libfdt.h"
  18. #include "libufdt_sysdeps.h"
  19. #define UFDT_PROP_DICT_INIT_SZ 4
  20. /* Empirical values for hash functions. */
  21. #define HASH_BASE 13131
  22. #define DICT_LIMIT_NUM 2
  23. #define DICT_LIMIT_DEN 3
  24. static int _ufdt_prop_dict_str_hash(const char *str) {
  25. int res = 0;
  26. for (; *str != '\0'; str++) {
  27. res *= HASH_BASE;
  28. res += *str;
  29. }
  30. return res;
  31. }
  32. static const struct fdt_property **_ufdt_prop_dict_find_index_by_name(
  33. const struct ufdt_prop_dict *dict, const char *name) {
  34. /* size should be 2^k for some k */
  35. int hash = _ufdt_prop_dict_str_hash(name);
  36. int size = dict->mem_size;
  37. int idx = hash & (size - 1);
  38. /* If collision, use linear probing to find idx in the hash table */
  39. for (int i = 0; i < size; i++) {
  40. const struct fdt_property **prop_ptr = &dict->props[idx];
  41. const struct fdt_property *prop = *prop_ptr;
  42. if (prop == NULL) return prop_ptr;
  43. const char *prop_name = fdt_string(dict->fdtp, fdt32_to_cpu(prop->nameoff));
  44. if (dto_strcmp(prop_name, name) == 0) return prop_ptr;
  45. idx = (idx + 1) & (size - 1);
  46. }
  47. return NULL;
  48. }
  49. static const struct fdt_property **_ufdt_prop_dict_find_index(
  50. struct ufdt_prop_dict *dict, const struct fdt_property *prop) {
  51. const char *name = fdt_string(dict->fdtp, fdt32_to_cpu(prop->nameoff));
  52. return _ufdt_prop_dict_find_index_by_name(dict, name);
  53. }
  54. int _ufdt_prop_dict_construct_int(struct ufdt_prop_dict *dict, void *fdtp,
  55. int size) {
  56. const size_t entry_size = sizeof(const struct fdt_property *);
  57. const struct fdt_property **props =
  58. (const struct fdt_property **)dto_malloc(size * entry_size);
  59. if (props == NULL) return -1;
  60. dto_memset(props, 0, size * entry_size);
  61. dict->mem_size = size;
  62. dict->num_used = 0;
  63. dict->fdtp = fdtp;
  64. dict->props = props;
  65. return 0;
  66. }
  67. int ufdt_prop_dict_construct(struct ufdt_prop_dict *dict, void *fdtp) {
  68. return _ufdt_prop_dict_construct_int(dict, fdtp, UFDT_PROP_DICT_INIT_SZ);
  69. }
  70. void ufdt_prop_dict_destruct(struct ufdt_prop_dict *dict) {
  71. if (dict == NULL) return;
  72. dto_free(dict->props);
  73. }
  74. static int _ufdt_prop_dict_enlarge_if_needed(struct ufdt_prop_dict *dict) {
  75. if (dict == NULL) return -1;
  76. /* Enlarge if the used number over than DICT_LIMIT_NUM / DICT_LIMIT_DEN */
  77. if (dict->num_used * DICT_LIMIT_DEN <= dict->mem_size * DICT_LIMIT_NUM) {
  78. return 0;
  79. }
  80. int new_size = dict->mem_size * 2;
  81. struct ufdt_prop_dict temp_dict;
  82. _ufdt_prop_dict_construct_int(&temp_dict, dict->fdtp, new_size);
  83. for (int i = 0; i < dict->mem_size; i++) {
  84. const struct fdt_property *prop = dict->props[i];
  85. if (prop == NULL) continue;
  86. const struct fdt_property **new_prop_ptr =
  87. _ufdt_prop_dict_find_index(&temp_dict, prop);
  88. if (new_prop_ptr == NULL) {
  89. dto_error("ufdt_prop_dict: failed to find new index when enlarging.\n");
  90. ufdt_prop_dict_destruct(&temp_dict);
  91. return -1;
  92. }
  93. *new_prop_ptr = prop;
  94. }
  95. dto_free(dict->props);
  96. dict->mem_size = new_size;
  97. dict->props = temp_dict.props;
  98. return 0;
  99. }
  100. int ufdt_prop_dict_add(struct ufdt_prop_dict *dict,
  101. const struct fdt_property *prop) {
  102. const struct fdt_property **prop_ptr = _ufdt_prop_dict_find_index(dict, prop);
  103. if (prop_ptr == NULL) {
  104. dto_error("ufdt_prop_dict: failed to find new index when adding.\n");
  105. return -1;
  106. }
  107. if (*prop_ptr == NULL) dict->num_used++;
  108. *prop_ptr = prop;
  109. return _ufdt_prop_dict_enlarge_if_needed(dict);
  110. }
  111. const struct fdt_property *ufdt_prop_dict_find(const struct ufdt_prop_dict *dict,
  112. const char *name) {
  113. const struct fdt_property **prop_ptr =
  114. _ufdt_prop_dict_find_index_by_name(dict, name);
  115. return prop_ptr ? *prop_ptr : NULL;
  116. }