Dict.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "memory/Allocator.h"
  16. #include "benc/Dict.h"
  17. #include "benc/String.h"
  18. #include <stddef.h>
  19. int32_t Dict_size(const Dict* dictionary)
  20. {
  21. if (dictionary != NULL) {
  22. struct Dict_Entry* entry = *dictionary;
  23. int32_t i;
  24. for (i = 0; entry != NULL; i++) {
  25. entry = entry->next;
  26. }
  27. return i;
  28. }
  29. return 0;
  30. }
  31. static Object* lookupObject(const Dict* dictionary, const String* key)
  32. {
  33. if (dictionary == NULL || key == NULL) {
  34. return NULL;
  35. }
  36. const struct Dict_Entry* curr = *dictionary;
  37. while (curr != NULL) {
  38. if (String_equals(key, curr->key)) {
  39. return curr->val;
  40. }
  41. curr = curr->next;
  42. }
  43. /* key not found */
  44. return NULL;
  45. }
  46. /** @see Object.h */
  47. int64_t* Dict_getInt(const Dict* dictionary, const String* key)
  48. {
  49. Object* obj = lookupObject(dictionary, key);
  50. if (obj == NULL || obj->type != Object_INTEGER) {
  51. return NULL;
  52. }
  53. return &(obj->as.number);
  54. }
  55. /** @see Object.h */
  56. String* Dict_getString(const Dict* dictionary, const String* key)
  57. {
  58. Object* obj = lookupObject(dictionary, key);
  59. if (obj == NULL || obj->type != Object_STRING) {
  60. return NULL;
  61. }
  62. return obj->as.string;
  63. }
  64. /** @see Object.h */
  65. Dict* Dict_getDict(const Dict* dictionary, const String* key)
  66. {
  67. Object* obj = lookupObject(dictionary, key);
  68. if (obj == NULL || obj->type != Object_DICT) {
  69. return NULL;
  70. }
  71. return obj->as.dictionary;
  72. }
  73. /** @see Object.h */
  74. List* Dict_getList(const Dict* dictionary, const String* key)
  75. {
  76. Object* obj = lookupObject(dictionary, key);
  77. if (obj == NULL || obj->type != Object_LIST) {
  78. return NULL;
  79. }
  80. return obj->as.list;
  81. }
  82. /** @see Object.h */
  83. Dict* Dict_new(struct Allocator* allocator)
  84. {
  85. return Allocator_calloc(allocator, sizeof(Dict), 1);
  86. }
  87. /**
  88. * Put a key:value pair into a dictionary.
  89. * NOTE: This will not copy the given object,
  90. * only add a pointer to it in the dictionary.
  91. * If dictionary is NULL then a new dictionary will be created and returned.
  92. *
  93. * @param dictionary this must be a bencoded dictionary or NULL, if NULL then a new dictionary
  94. is made.
  95. * @param key the reference key to use for putting the entry in the dictionary.
  96. * @param value the value to insert with the key.
  97. * @param allocator the means to get memory for storing the dictionary entry wrapper.
  98. * @return if the dictionary parameter is NULL then this will be the newly created dictionary.
  99. * Otherwise: if the key already exists in the dictionary then the value which was
  100. * displaced by the put, if not then NULL.
  101. */
  102. static Object* putObject(Dict* dictionary,
  103. const String* key,
  104. Object* value,
  105. struct Allocator* allocator)
  106. {
  107. struct Dict_Entry** prev_p = dictionary;
  108. struct Dict_Entry* current = *dictionary;
  109. while (current != NULL) {
  110. int cmp = String_compare(key, current->key);
  111. if (cmp < 0) {
  112. break;
  113. } else if (cmp == 0) {
  114. Object* out = current->val;
  115. current->val = value;
  116. return out;
  117. }
  118. prev_p = &(current->next);
  119. current = current->next;
  120. }
  121. struct Dict_Entry* entry = Allocator_malloc(allocator, sizeof(struct Dict_Entry));
  122. entry->key = (String*) key; // need to drop the const :(
  123. entry->val = value;
  124. entry->next = current;
  125. *prev_p = entry;
  126. return NULL;
  127. }
  128. /** @see Object.h */
  129. Object* Dict_putInt(Dict* dictionary,
  130. const String* key,
  131. int64_t value,
  132. struct Allocator* allocator)
  133. {
  134. Object* v = Allocator_clone(allocator, (&(Object) {
  135. .type = Object_INTEGER,
  136. .as.number = value
  137. }));
  138. return putObject(dictionary, key, v, allocator);
  139. }
  140. /** @see Object.h */
  141. Object* Dict_putString(Dict* dictionary,
  142. const String* key,
  143. String* value,
  144. struct Allocator* allocator)
  145. {
  146. if (key == NULL || value == NULL) {
  147. return NULL;
  148. }
  149. Object* v = Allocator_clone(allocator, (&(Object) {
  150. .type = Object_STRING,
  151. .as.string = value
  152. }));
  153. return putObject(dictionary, key, v, allocator);
  154. }
  155. /** @see Object.h */
  156. Object* Dict_putList(Dict* dictionary,
  157. const String* key,
  158. List* value,
  159. struct Allocator* allocator)
  160. {
  161. if (key == NULL || value == NULL) {
  162. return NULL;
  163. }
  164. Object* v = Allocator_clone(allocator, (&(Object) {
  165. .type = Object_LIST,
  166. /* Lists and dictionaries are double pointers so they have to be loaded. */
  167. .as.list = value
  168. }));
  169. return putObject(dictionary, key, v, allocator);
  170. }
  171. Object* Dict_putDict(Dict* dictionary,
  172. const String* key,
  173. Dict* value,
  174. struct Allocator* allocator)
  175. {
  176. if (key == NULL || value == NULL) {
  177. return NULL;
  178. }
  179. Object* v = Allocator_clone(allocator, (&(Object) {
  180. .type = Object_DICT,
  181. /* Lists and dictionaries are double pointers so they have to be loaded. */
  182. .as.dictionary = value
  183. }));
  184. return putObject(dictionary, key, v, allocator);
  185. }
  186. /** @see Object.h */
  187. int32_t Dict_remove(Dict* dictionary, const String* key)
  188. {
  189. struct Dict_Entry** prev_p = dictionary;
  190. struct Dict_Entry* current = *dictionary;
  191. while (current != NULL) {
  192. if (String_equals(key, current->key)) {
  193. *prev_p = current->next;
  194. return 1;
  195. }
  196. prev_p = &(current->next);
  197. current = current->next;
  198. }
  199. return 0;
  200. }