72869c387893bf2a661fc4bf741831073508f5c0
[alexxy/gromacs.git] / src / gromacs / legacyheaders / smalloc.h
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * Gromacs Runs On Most of All Computer Systems
34  */
35
36 #ifndef _smalloc_h
37 #define _smalloc_h
38
39 #include <stdlib.h>
40
41 /*
42  * Memory allocation routines in gromacs:
43  *
44  * If an allocation fails, the program is halted by means of the
45  * fatal_error routine, which outputs source file and line number
46  * and the name of the variable involved.
47  *
48  * Macro's which can be used:
49  *
50  * snew(ptr,nelem)
51  *    Allocates memory for nelem elements and returns this in ptr.
52  *    The allocated memory is initialized to zeros.
53  *
54  * srenew(ptr,nelem)
55  *    Reallocates memory for nelem elements and returns this in ptr.
56  *
57  * smalloc(ptr,size)
58  *    Allocates memory for size bytes and returns this in ptr.
59  *
60  * scalloc(ptr,nelem,elsize)
61  *    Allocates memory for nelem elements of size elsize and returns
62  *    this in ptr.
63  *
64  * srealloc(ptr,size)
65  *    Reallocates memory for size bytes and returns this in ptr.
66  *
67  * sfree(ptr)
68  *    Frees memory referenced by ptr.
69  *
70  * snew_aligned(ptr,nelem,alignment)
71  *    Allocates memory for nelem elements and returns this in ptr.
72  *    The allocated memory is initialized to zeroes.
73  *    alignment=n will constrain ptr to be n-byte aligned.
74  *    This pointer should only be freed with sfree_aligned, since
75  *    it may not be the value returned by the underlying malloc.
76  *
77  * sfree_aligned(ptr)
78  *    Frees aligned memory referenced by ptr.
79  *
80  ****************************************************************************
81  *
82  * Functions which are used by the macro's:
83  *
84  * extern void *save_malloc(char *name,char *file,int line,int size);
85  *    Like alloc, returns a pointer to the allocated space, uses name, file
86  *    and line to generate an error message when allocation failed.
87  *
88  * extern void *save_calloc(char *name,char *file,int line,
89  *                          size_t nelem,size_t elsize);
90  *    Like calloc, returns a pointer to the allocated space, uses name, file
91  *    and line to generate an error message when allocation failed.
92  *
93  * extern void *save_realloc(char *name,char *file,int line,
94  *                           void *ptr,size_t size);
95  *    Like realloc, returns a pointer to the allocated space, uses name, file
96  *    and line to generate an error message when allocation failed.
97  *    If ptr equals NULL, malloc is called in stead of realloc, in this way
98  *    it is possible to combine first and later allocations.
99  *
100  * extern void save_free(char *name,char *file,int line, void *ptr);
101  *    Like free, uses name, file and line to generate an error message when
102  *    the free failed.
103  *
104  * extern size_t maxavail();
105  *    Returns the maximum available allocation unit, by applying a binary
106  *    search on the largest block of memory available. After allocation
107  *    it invokes free to restore the original state. So it is important
108  *    that free can undo the effect of a malloc.
109  *
110  * extern size_t memavail();
111  *    Returns the total of available allocation unit, by applying maxavail
112  *    until no space is left, it then frees all allocated space and returns
113  *    the sum of the previously allocated space. As mentioned with maxavail,
114  *    it is important that free can undo the effect of a malloc.
115  *
116  * extern void *save_malloc_aligned(char *name,char *file,int line,size_t size,size_t alignment);
117  *    Like alloc, returns a pointer to the allocated space, uses name, file
118  *    and line to generate an error message when allocation failed.
119  *    The returned pointer will be n-byte aligned, where n=alignment.
120  *    The pointer should only be freed with a call to save_free.
121  *
122  * extern void save_free_aligned(char *name,char *file,int line, void *ptr);
123  *    Like free, uses name, file and line to generate an error message when
124  *    the free failed. This function is intended to be called for
125  *    pointers allocated with save_malloc_aligned, and may not work
126  *    on normal pointers.
127  */
128
129 #ifdef __cplusplus
130 extern "C" {
131 #endif
132
133 void *save_malloc(const char *name, const char *file, int line, size_t size);
134 void *save_calloc(const char *name, const char *file, int line,
135                   size_t nelem, size_t elsize);
136 void *save_realloc(const char *name, const char *file, int line,
137                    void *ptr, size_t nelem, size_t elsize);
138 void save_free(const char *name, const char *file, int line, void *ptr);
139 size_t maxavail(void);
140 size_t memavail(void);
141
142 /* Aligned-memory counterparts */
143
144 void *save_malloc_aligned(const char *name, const char *file, int line,
145                           unsigned nelem, size_t elsize, size_t alignment);
146 void *save_calloc_aligned(const char *name, const char *file, int line,
147                           unsigned nelem, size_t elsize, size_t alignment);
148 void save_free_aligned(const char *name, const char *file, int line, void *ptr);
149
150 #ifdef __cplusplus
151 }
152
153 /* Use of sizeof(T) in _snew() and _srenew() can cause obscure bugs if
154  * several files define distinct data structures with identical names and
155  * allocate memory for them using the macros below.  Note that by the standard,
156  * such declarations cause undefined behavior.
157  * The C versions work fine in such cases, but when compiled with a C++
158  * compiler (and if the compiler does not inline the calls), the linker cannot
159  * tell that data structures with identical names are actually different and
160  * links calls to these template functions incorrectly, which can result in
161  * allocation of an incorrect amount of memory if the element size is computed
162  * within the function.
163  *
164  * This could be solved by passing the size as a parameter, but this has other
165  * issues: it provokes warnings from cppcheck for some invokations.
166  * Even with the size passed as a parameter, incorrect linkage will occur.
167  * When converting files to C++, locally declared structs should be enclosed in
168  * anonymous namespaces or some other means taken to ensure they are unique.
169  */
170 template <typename T> inline
171 void _snew(const char *name, const char *file, int line,
172            T * &ptr, size_t nelem)
173 {
174     ptr = (T *)save_calloc(name, file, line, nelem, sizeof(T));
175 }
176 template <typename T> inline
177 void _srenew(const char *name, const char *file, int line,
178              T * &ptr, size_t nelem)
179 {
180     ptr = (T *)save_realloc(name, file, line, ptr, nelem, sizeof(T));
181 }
182 template <typename T> inline
183 void _smalloc(const char *name, const char *file, int line, T * &ptr, size_t size)
184 {
185     ptr = (T *)save_malloc(name, file, line, size);
186 }
187 template <typename T> inline
188 void _srealloc(const char *name, const char *file, int line, T * &ptr, size_t size)
189 {
190     ptr = (T *)save_realloc(name, file, line, ptr, size, sizeof(char));
191 }
192 template <typename T> inline
193 void _snew_aligned(const char *name, const char *file, int line,
194                    T * &ptr, size_t nelem, size_t alignment)
195 {
196     ptr = (T *)save_calloc_aligned(name, file, line, nelem, sizeof(T), alignment);
197 }
198
199 #define snew(ptr, nelem) _snew(#ptr, __FILE__, __LINE__, (ptr), (nelem))
200 #define srenew(ptr, nelem) _srenew(#ptr, __FILE__, __LINE__, (ptr), (nelem))
201 #define smalloc(ptr, size) _smalloc(#ptr, __FILE__, __LINE__, (ptr), (size))
202 #define srealloc(ptr, size) _srealloc(#ptr, __FILE__, __LINE__, (ptr), (size))
203 #define snew_aligned(ptr, nelem, alignment) _snew_aligned(#ptr, __FILE__, __LINE__, (ptr), (nelem), alignment)
204
205 #else /* __cplusplus */
206
207 /* These macros work in C, not in C++ */
208 #define snew(ptr, nelem) (ptr) = save_calloc(#ptr, __FILE__, __LINE__, \
209                                              (nelem), sizeof(*(ptr)))
210 #define srenew(ptr, nelem) (ptr) = save_realloc(#ptr, __FILE__, __LINE__, \
211                                                 (ptr), (nelem), sizeof(*(ptr)))
212 #define smalloc(ptr, size) (ptr) = save_malloc(#ptr, __FILE__, __LINE__, size)
213 #define scalloc(ptr, nelem, elsize) \
214     (ptr) = save_calloc(#ptr, __FILE__, __LINE__, nelem, elsize)
215 #define srealloc(ptr, size) (ptr) = save_realloc(#ptr, __FILE__, __LINE__, \
216                                                  (ptr), size, 1)
217 #define snew_aligned(ptr, nelem, alignment) (ptr) = save_calloc_aligned(#ptr, __FILE__, __LINE__, (nelem), sizeof(*(ptr)), alignment)
218 #endif /* __cplusplus */
219
220 #define sfree(ptr) save_free(#ptr, __FILE__, __LINE__, (ptr))
221
222 /* call this ONLY with a pointer obtained through snew_aligned or
223    smalloc_aligned: */
224 #define sfree_aligned(ptr) save_free_aligned(#ptr, __FILE__, __LINE__, (ptr))
225
226 #ifdef __cplusplus
227
228 #include "../utility/common.h"
229
230 namespace gmx
231 {
232
233 /*! \brief
234  * Stripped-down version of scoped_ptr that uses sfree().
235  *
236  * Currently only implements constructor from a pointer value and destructor;
237  * other operations can be added if they become necessary.
238  *
239  * This is currently in smalloc.h, as this header also declares sfree().
240  * If more flexible guards/smart pointers are needed for C pointers, this class
241  * should be moved to a separate header under src/gromacs/utility/ together
242  * with that more flexible implementation.
243  * Currently, boost::shared_ptr is used in a few locations, but is not suitable
244  * for all cases.  A scoped_ptr with deleter support would be a general enough
245  * implementation for all uses.  C++11 unique_ptr has this, but for non-C++11
246  * suppoer we need something else.
247  *
248  * Methods in this class do not throw.
249  */
250 class scoped_ptr_sfree
251 {
252     public:
253         /*! \brief
254          * Initializes a scoped_ptr that frees \p ptr on scope exit.
255          *
256          * \param[in] ptr  Pointer to use for initialization.
257          */
258         explicit scoped_ptr_sfree(void *ptr) : ptr_(ptr) {}
259         //! Frees the pointer passed to the constructor.
260         ~scoped_ptr_sfree() { sfree(ptr_); }
261
262     private:
263         void                   *ptr_;
264
265         GMX_DISALLOW_COPY_AND_ASSIGN(scoped_ptr_sfree);
266 };
267
268 }      // namespace gmx
269 #endif /* __cplusplus */
270
271 #endif /* _smalloc_h */