1 /*
2 * Copyright (C) 2018-2019 Alexander Borisov
3 *
4 * Author: Alexander Borisov <borisov@lexbor.com>
5 */
6
7 #include "lexbor/core/dobject.h"
8
9
10 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
11 #include <sanitizer/asan_interface.h>
12 #endif
13
14
15 lexbor_dobject_t *
lexbor_dobject_create(void)16 lexbor_dobject_create(void)
17 {
18 return lexbor_calloc(1, sizeof(lexbor_dobject_t));
19 }
20
21 lxb_status_t
lexbor_dobject_init(lexbor_dobject_t * dobject,size_t chunk_size,size_t struct_size)22 lexbor_dobject_init(lexbor_dobject_t *dobject,
23 size_t chunk_size, size_t struct_size)
24 {
25 lxb_status_t status;
26
27 if (dobject == NULL) {
28 return LXB_STATUS_ERROR_OBJECT_IS_NULL;
29 }
30
31 if (chunk_size == 0 || struct_size == 0) {
32 return LXB_STATUS_ERROR_WRONG_ARGS;
33 }
34
35 /* Set params */
36 dobject->allocated = 0UL;
37 dobject->struct_size = struct_size;
38
39 /* Init memory */
40 dobject->mem = lexbor_mem_create();
41
42 status = lexbor_mem_init(dobject->mem,
43 lexbor_mem_align(chunk_size * dobject->struct_size));
44 if (status) {
45 return status;
46 }
47
48 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
49 ASAN_POISON_MEMORY_REGION(dobject->mem->chunk->data,
50 dobject->mem->chunk->size);
51 #endif
52
53 /* Array */
54 dobject->cache = lexbor_array_create();
55
56 status = lexbor_array_init(dobject->cache, chunk_size);
57 if (status)
58 return status;
59
60 return LXB_STATUS_OK;
61 }
62
63 void
lexbor_dobject_clean(lexbor_dobject_t * dobject)64 lexbor_dobject_clean(lexbor_dobject_t *dobject)
65 {
66 if (dobject != NULL) {
67 dobject->allocated = 0UL;
68
69 lexbor_mem_clean(dobject->mem);
70 lexbor_array_clean(dobject->cache);
71 }
72 }
73
74 lexbor_dobject_t *
lexbor_dobject_destroy(lexbor_dobject_t * dobject,bool destroy_self)75 lexbor_dobject_destroy(lexbor_dobject_t *dobject, bool destroy_self)
76 {
77 if (dobject == NULL)
78 return NULL;
79
80 dobject->mem = lexbor_mem_destroy(dobject->mem, true);
81 dobject->cache = lexbor_array_destroy(dobject->cache, true);
82
83 if (destroy_self == true) {
84 return lexbor_free(dobject);
85 }
86
87 return dobject;
88 }
89
90 void *
lexbor_dobject_alloc(lexbor_dobject_t * dobject)91 lexbor_dobject_alloc(lexbor_dobject_t *dobject)
92 {
93 void *data;
94
95 if (lexbor_array_length(dobject->cache) != 0) {
96 dobject->allocated++;
97
98 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
99 data = lexbor_array_pop(dobject->cache);
100 ASAN_UNPOISON_MEMORY_REGION(data, dobject->struct_size);
101
102 return data;
103 #else
104 return lexbor_array_pop(dobject->cache);
105 #endif
106 }
107
108 data = lexbor_mem_alloc(dobject->mem, dobject->struct_size);
109 if (data == NULL) {
110 return NULL;
111 }
112
113 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
114 ASAN_UNPOISON_MEMORY_REGION(data, dobject->struct_size);
115 #endif
116
117 dobject->allocated++;
118
119 return data;
120 }
121
122 void *
lexbor_dobject_calloc(lexbor_dobject_t * dobject)123 lexbor_dobject_calloc(lexbor_dobject_t *dobject)
124 {
125 void *data = lexbor_dobject_alloc(dobject);
126
127 if (data != NULL) {
128 memset(data, 0, dobject->struct_size);
129 }
130
131 return data;
132 }
133
134 void *
lexbor_dobject_free(lexbor_dobject_t * dobject,void * data)135 lexbor_dobject_free(lexbor_dobject_t *dobject, void *data)
136 {
137 if (data == NULL) {
138 return NULL;
139 }
140
141 #if defined(LEXBOR_HAVE_ADDRESS_SANITIZER)
142 ASAN_POISON_MEMORY_REGION(data, dobject->struct_size);
143 #endif
144
145 if (lexbor_array_push(dobject->cache, data) == LXB_STATUS_OK) {
146 dobject->allocated--;
147 return NULL;
148 }
149
150 return data;
151 }
152
153 void *
lexbor_dobject_by_absolute_position(lexbor_dobject_t * dobject,size_t pos)154 lexbor_dobject_by_absolute_position(lexbor_dobject_t *dobject, size_t pos)
155 {
156 size_t chunk_idx, chunk_pos, i;
157 lexbor_mem_chunk_t *chunk;
158
159 if (pos >= dobject->allocated) {
160 return NULL;
161 }
162
163 chunk = dobject->mem->chunk_first;
164 chunk_pos = pos * dobject->struct_size;
165 chunk_idx = chunk_pos / dobject->mem->chunk_min_size;
166
167 for (i = 0; i < chunk_idx; i++) {
168 chunk = chunk->next;
169 }
170
171 return &chunk->data[chunk_pos % chunk->size];
172 }
173
174 /*
175 * No inline functions for ABI.
176 */
177 size_t
lexbor_dobject_allocated_noi(lexbor_dobject_t * dobject)178 lexbor_dobject_allocated_noi(lexbor_dobject_t *dobject)
179 {
180 return lexbor_dobject_allocated(dobject);
181 }
182
183 size_t
lexbor_dobject_cache_length_noi(lexbor_dobject_t * dobject)184 lexbor_dobject_cache_length_noi(lexbor_dobject_t *dobject)
185 {
186 return lexbor_dobject_cache_length(dobject);
187 }
188