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 }