|
|
|
@@ -0,0 +1,96 @@ |
|
|
|
#include "arraylist.hpp" |
|
|
|
|
|
|
|
template <typename type, unsigned int bucket_size> |
|
|
|
class Bucket_Allocator { |
|
|
|
int latest_bucket; |
|
|
|
int next_index_in_latest_bucket; |
|
|
|
int bucket_count; |
|
|
|
int next_bucket_index; |
|
|
|
|
|
|
|
Array_List<type*> free_list; |
|
|
|
type** buckets; |
|
|
|
|
|
|
|
void expand() { |
|
|
|
// realloc time |
|
|
|
buckets = (type**)realloc(buckets, bucket_count * 2 * sizeof(type*)); |
|
|
|
for (int i = bucket_count; i < bucket_count * 2; ++i) { |
|
|
|
buckets[i] = (type*)malloc(bucket_size * sizeof(type)); |
|
|
|
} |
|
|
|
bucket_count *= 2; |
|
|
|
} |
|
|
|
|
|
|
|
void jump_to_next_bucket() { |
|
|
|
next_index_in_latest_bucket = 0; |
|
|
|
++next_bucket_index; |
|
|
|
if (next_bucket_index >= bucket_count) { |
|
|
|
expand(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void increment_pointers(int amount = 1) { |
|
|
|
next_index_in_latest_bucket += amount; |
|
|
|
if (next_index_in_latest_bucket >= bucket_size) { |
|
|
|
jump_to_next_bucket(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public: |
|
|
|
Bucket_Allocator(unsigned int initial_bucket_count = 1) { |
|
|
|
latest_bucket = 0; |
|
|
|
next_index_in_latest_bucket = 0; |
|
|
|
next_bucket_index = 0; |
|
|
|
bucket_count = initial_bucket_count; |
|
|
|
|
|
|
|
buckets = (type**)malloc(bucket_count * sizeof(type*)); |
|
|
|
for (int i = 0; i < bucket_count; ++i) { |
|
|
|
buckets[i] = (type*)malloc(bucket_size * sizeof(type)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
~Bucket_Allocator() { |
|
|
|
for (int i = 0; i < bucket_count; ++i) { |
|
|
|
free(buckets[i]); |
|
|
|
} |
|
|
|
::free(buckets); |
|
|
|
} |
|
|
|
|
|
|
|
type* allocate(unsigned int amount = 1) { |
|
|
|
type* ret; |
|
|
|
if (amount == 0) return nullptr; |
|
|
|
if (amount == 1) { |
|
|
|
if (free_list.next_index != 0) { |
|
|
|
return free_list.data[--free_list.next_index]; |
|
|
|
} |
|
|
|
ret = buckets[next_bucket_index]+next_index_in_latest_bucket; |
|
|
|
increment_pointers(1); |
|
|
|
return ret; |
|
|
|
} |
|
|
|
if (amount > bucket_size) |
|
|
|
return nullptr; |
|
|
|
if ((bucket_size - next_index_in_latest_bucket) >= 4) { |
|
|
|
// if the current bucket is ahs enough free space |
|
|
|
ret = buckets[next_bucket_index]+(next_index_in_latest_bucket); |
|
|
|
increment_pointers(amount); |
|
|
|
return ret; |
|
|
|
} else { |
|
|
|
// the current bucket does not have enough free space |
|
|
|
// add all remainding slots to free list |
|
|
|
while (next_index_in_latest_bucket < bucket_size) { |
|
|
|
free_list.append(buckets[next_bucket_index]+next_index_in_latest_bucket); |
|
|
|
++next_index_in_latest_bucket; |
|
|
|
} |
|
|
|
jump_to_next_bucket(); |
|
|
|
return allocate(amount); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void free(type* obj) { |
|
|
|
free_list.append(obj); |
|
|
|
} |
|
|
|
|
|
|
|
void reset() { |
|
|
|
latest_bucket = 0; |
|
|
|
next_index_in_latest_bucket = 0; |
|
|
|
next_bucket_index = 0; |
|
|
|
} |
|
|
|
}; |