Extending test-client-custom-summary to try e_book_client_get_contacts_uids()
[platform/upstream/evolution-data-server.git] / camel / camel-mempool.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU Lesser General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
18  *
19  */
20
21 #include "camel-mempool.h"
22
23 #include <string.h>
24
25 typedef struct _MemPoolNode {
26         struct _MemPoolNode *next;
27
28         gint free;
29 } MemPoolNode;
30
31 typedef struct _MemPoolThresholdNode {
32         struct _MemPoolThresholdNode *next;
33 } MemPoolThresholdNode;
34
35 #define ALIGNED_SIZEOF(t)       ((sizeof (t) + G_MEM_ALIGN - 1) & -G_MEM_ALIGN)
36
37 struct _CamelMemPool {
38         gint blocksize;
39         gint threshold;
40         guint align;
41         struct _MemPoolNode *blocks;
42         struct _MemPoolThresholdNode *threshold_blocks;
43 };
44
45 /**
46  * camel_mempool_new:
47  * @blocksize: The base blocksize to use for all system alocations.
48  * @threshold: If the allocation exceeds the threshold, then it is
49  * allocated separately and stored in a separate list.
50  * @flags: Alignment options: CAMEL_MEMPOOL_ALIGN_STRUCT uses native
51  * struct alignment, CAMEL_MEMPOOL_ALIGN_WORD aligns to 16 bits (2 bytes),
52  * and CAMEL_MEMPOOL_ALIGN_BYTE aligns to the nearest byte.  The default
53  * is to align to native structures.
54  *
55  * Create a new mempool header.  Mempools can be used to efficiently
56  * allocate data which can then be freed as a whole.
57  *
58  * Mempools can also be used to efficiently allocate arbitrarily
59  * aligned data (such as strings) without incurring the space overhead
60  * of aligning each allocation (which is not required for strings).
61  *
62  * However, each allocation cannot be freed individually, only all
63  * or nothing.
64  *
65  * Returns:
66  *
67  * Since: 2.32
68  **/
69 CamelMemPool *
70 camel_mempool_new (gint blocksize,
71                    gint threshold,
72                    CamelMemPoolFlags flags)
73 {
74         CamelMemPool *pool;
75
76         pool = g_slice_new0 (CamelMemPool);
77         if (threshold >= blocksize)
78                 threshold = blocksize * 2 / 3;
79         pool->blocksize = blocksize;
80         pool->threshold = threshold;
81         pool->blocks = NULL;
82         pool->threshold_blocks = NULL;
83
84         switch (flags & CAMEL_MEMPOOL_ALIGN_MASK) {
85         case CAMEL_MEMPOOL_ALIGN_STRUCT:
86         default:
87                 pool->align = G_MEM_ALIGN - 1;
88                 break;
89         case CAMEL_MEMPOOL_ALIGN_WORD:
90                 pool->align = 2 - 1;
91                 break;
92         case CAMEL_MEMPOOL_ALIGN_BYTE:
93                 pool->align = 1 - 1;
94         }
95         return pool;
96 }
97
98 /**
99  * camel_mempool_alloc:
100  * @pool: a #CamelMemPool
101  * @size:
102  *
103  * Allocate a new data block in the mempool.  Size will
104  * be rounded up to the mempool's alignment restrictions
105  * before being used.
106  *
107  * Since: 2.32
108  **/
109 gpointer
110 camel_mempool_alloc (CamelMemPool *pool,
111                      register gint size)
112 {
113         size = (size + pool->align) & (~(pool->align));
114         if (size >= pool->threshold) {
115                 MemPoolThresholdNode *n;
116
117                 n = g_malloc (ALIGNED_SIZEOF (*n) + size);
118                 n->next = pool->threshold_blocks;
119                 pool->threshold_blocks = n;
120                 return (gchar *) n + ALIGNED_SIZEOF (*n);
121         } else {
122                 register MemPoolNode *n;
123
124                 n = pool->blocks;
125                 if (n && n->free >= size) {
126                         n->free -= size;
127                         return (gchar *) n + ALIGNED_SIZEOF (*n) + n->free;
128                 }
129
130                 /* maybe we could do some sort of the free blocks based on size, but
131                  * it doubt its worth it at all */
132
133                 n = g_malloc (ALIGNED_SIZEOF (*n) + pool->blocksize);
134                 n->next = pool->blocks;
135                 pool->blocks = n;
136                 n->free = pool->blocksize - size;
137                 return (gchar *) n + ALIGNED_SIZEOF (*n) + n->free;
138         }
139 }
140
141 /**
142  * camel_mempool_strdup:
143  * @pool: a #CamelMemPool
144  * @str:
145  *
146  * Since: 2.32
147  **/
148 gchar *
149 camel_mempool_strdup (CamelMemPool *pool,
150                       const gchar *str)
151 {
152         gchar *out;
153
154         out = camel_mempool_alloc (pool, strlen (str) + 1);
155         strcpy (out, str);
156
157         return out;
158 }
159
160 /**
161  * camel_mempool_flush:
162  * @pool: a #CamelMemPool
163  * @freeall: free all system allocated blocks as well
164  *
165  * Flush used memory and mark allocated blocks as free.
166  *
167  * If @freeall is %TRUE, then all allocated blocks are free'd
168  * as well.  Otherwise only blocks above the threshold are
169  * actually freed, and the others are simply marked as empty.
170  *
171  * Since: 2.32
172  **/
173 void
174 camel_mempool_flush (CamelMemPool *pool,
175                      gint freeall)
176 {
177         MemPoolThresholdNode *tn, *tw;
178         MemPoolNode *pw, *pn;
179
180         tw = pool->threshold_blocks;
181         while (tw) {
182                 tn = tw->next;
183                 g_free (tw);
184                 tw = tn;
185         }
186         pool->threshold_blocks = NULL;
187
188         if (freeall) {
189                 pw = pool->blocks;
190                 while (pw) {
191                         pn = pw->next;
192                         g_free (pw);
193                         pw = pn;
194                 }
195                 pool->blocks = NULL;
196         } else {
197                 pw = pool->blocks;
198                 while (pw) {
199                         pw->free = pool->blocksize;
200                         pw = pw->next;
201                 }
202         }
203 }
204
205 /**
206  * camel_mempool_destroy:
207  * @pool: a #CamelMemPool
208  *
209  * Free all memory associated with a mempool.
210  *
211  * Since: 2.32
212  **/
213 void
214 camel_mempool_destroy (CamelMemPool *pool)
215 {
216         if (pool) {
217                 camel_mempool_flush (pool, 1);
218                 g_slice_free (CamelMemPool, pool);
219         }
220 }