1 /******************************************************************************* 2 3 A utility for allocating and managing malloc allocated arrays. 4 5 The module contains functions which aids in creating arrays whose buffer 6 is allocated by malloc(). 7 8 Note: 9 - Don't manually modify the length of the arrays returned by this module or 10 pass it to any method which modifies the length of the array. 11 12 To resize an array, call the resize() method. To deallocate an array, call 13 the deallocate() method. 14 15 Copyright: 16 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 17 All rights reserved. 18 19 License: 20 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 21 Alternatively, this file may be distributed under the terms of the Tango 22 3-Clause BSD License (see LICENSE_BSD.txt for details). 23 24 *******************************************************************************/ 25 26 module ocean.util.container.MallocArray; 27 28 29 import ocean.core.ExceptionDefinitions; // onOutOfMemoryError; 30 import core.stdc.stdlib; // malloc, free, realloc; 31 import core.stdc.string; // memmove; 32 33 34 /******************************************************************************* 35 36 Allocate an array of the given type and length whose buffer is allocated by 37 malloc(). 38 39 Params: 40 Item = the type of items making up the array 41 num_elements = the number of array elements to allocate 42 43 Returns: 44 the malloc allocated array 45 46 *******************************************************************************/ 47 48 public Item[] allocate (Item) (size_t num_elements) 49 { 50 if (num_elements is 0) 51 return null; 52 53 auto allocated_mem = malloc(num_elements * Item.sizeof); 54 if (allocated_mem is null) 55 onOutOfMemoryError(); 56 57 auto arr = (cast(Item*)allocated_mem)[0 .. num_elements]; 58 arr[] = Item.init; 59 return arr; 60 } 61 62 /******************************************************************************* 63 64 Resize an array whose buffer was allocated by malloc(). 65 66 It's safe to pass an array whose current length is 0, the array would 67 be allocated. 68 69 It's also safe to specify the new_length of an array to be 0, the array 70 would be deallocated. 71 72 Params: 73 Item = the type of items making up the array 74 arr_to_resize = the array that should be resized 75 new_length = the new length that the item should be resize to 76 77 *******************************************************************************/ 78 79 public void resize (Item) (ref Item[] arr_to_resize, size_t new_length) 80 { 81 if (new_length is 0) 82 { 83 deallocate(arr_to_resize); 84 return; 85 } 86 87 auto old_length = arr_to_resize.length; 88 if (old_length == new_length) 89 return; 90 91 auto allocated_mem = realloc(arr_to_resize.ptr, Item.sizeof * new_length); 92 if (allocated_mem is null) 93 onOutOfMemoryError(); 94 95 arr_to_resize = (cast(Item*)allocated_mem)[0 .. new_length]; 96 if (old_length < new_length) 97 { 98 // Init newly allocated items 99 arr_to_resize[old_length..new_length] = Item.init; 100 } 101 } 102 103 /******************************************************************************* 104 105 Deallocate an array whose buffer was allocated by malloc(). 106 107 Params: 108 Item = the type of items making up the array 109 arr_to_deallocate = the array to deallocate 110 111 *******************************************************************************/ 112 113 public void deallocate (Item) (ref Item[] arr_to_deallocate) 114 { 115 free(arr_to_deallocate.ptr); 116 arr_to_deallocate = null; 117 } 118 119 120 /******************************************************************************* 121 122 Basic functionalities tests 123 124 *******************************************************************************/ 125 126 version (unittest) 127 { 128 import ocean.core.Test; 129 void testFunctions (T) () 130 { 131 auto t = allocate!(T)(1); 132 test!("==")(t.length, 1); 133 // Test whether the allocated array was inited. 134 test!("==")(t[0], T.init); 135 136 t.resize(2); 137 test!("!=")(t, (T[]).init); 138 test!("==")(t.length, 2); 139 // Test whether the expanded array part was inited. 140 test!("==")(t[1], T.init); 141 142 t.resize(0); 143 test!("==")(t, (T[]).init); 144 145 t = allocate!(T)(100); 146 test!("!=")(t, (T[]).init); 147 test!("==")(t.length, 100); 148 149 t.deallocate(); 150 test!("==")(t, (T[]).init); 151 152 t.resize(1); 153 test!("==")(t.length, 1); 154 } 155 } 156 157 unittest 158 { 159 testFunctions!(int)(); 160 161 // Test initiating the template with an empty struct 162 struct TestEmptyStruct 163 { 164 } 165 testFunctions!(TestEmptyStruct)(); 166 167 // Test initiating the template with a populated struct with non-default 168 // init values 169 struct TestStruct 170 { 171 float num = 5; 172 } 173 testFunctions!(TestStruct)(); 174 }