Subversion Repositories dashGPS

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 mjames 1
#ifndef _ARR_DESC_H_
2
#define _ARR_DESC_H_
3
 
4
/*--------------------------------------------------------------------------------*/
5
/* Includes */
6
/*--------------------------------------------------------------------------------*/
7
#include <stdint.h>
8
#include <string.h>             /* memset() */
9
#include "../util/util.h"       /* CONCAT() */
10
 
11
/*--------------------------------------------------------------------------------*/
12
/* Type Definitions */
13
/*--------------------------------------------------------------------------------*/
14
 
15
/**
16
 *  Array-descriptor struct.
17
 */
18
typedef struct ARR_DESC_struct
19
{
20
    void *  data_ptr;                /* Pointer to the array contents. */
21
    int32_t element_count;           /* Number of current elements. */
22
    int32_t element_size;            /* Size of current elements in bytes. */
23
    int32_t underlying_size;         /* Size of underlying array in bytes. */
24
} ARR_DESC_t;
25
 
26
/*--------------------------------------------------------------------------------*/
27
/* Macros and Defines */
28
/*--------------------------------------------------------------------------------*/
29
 
30
/**
31
 *  Prefix of the array variable's name when creating an array and an array
32
 *  descriptor at the same time.
33
 */
34
#define ARR_DESC_ARR_PREFIX ARR_DESC_ARR_
35
 
36
/**
37
 *  Evaluate to the array variable's name when creating an array and an array
38
 *  descriptor at the same time.
39
 */
40
#define ARR_DESC_ARR_NAME(name)                 \
41
    CONCAT(ARR_DESC_ARR_PREFIX, name)
42
 
43
/**
44
 *  Define an #ARR_DESC_t by itself.
45
 *
46
 *  @note The user must supply an array to store the data used by the
47
 *  #ARR_DESC_t.
48
 */
49
#define ARR_DESC_INTERNAL_DEFINE(name, data_ptr,                \
50
                                 element_count, element_size)   \
51
    ARR_DESC_t name = {                                         \
52
        data_ptr,                                               \
53
        element_count,                                          \
54
        element_size,                                           \
55
        element_count * element_size                            \
56
    }                                                           \
57
 
58
/**
59
 *  Define both an array and an #ARR_DESC_t that describes it.
60
 *
61
 *  @note Use the #CURLY() macro for the content field; it provides the curly
62
 *  braces necessary for an array initialization.
63
 */
64
#define ARR_DESC_DEFINE(type, name, element_count, content)             \
65
    type ARR_DESC_ARR_NAME(name)[element_count] = content;              \
66
    ARR_DESC_INTERNAL_DEFINE(name,                                      \
67
                             &ARR_DESC_ARR_NAME(name),                  \
68
                             element_count,                             \
69
                             sizeof(type)) /* Note the lacking semicolon */
70
 
71
/**
72
 *  Create a #ARR_DESC_t which refers to a subset of the data in another.
73
 *
74
 *  The new #ARR_DESC_t shares the same underlying array as the aliased
75
 *  #ARR_DESC_t, but only describes a subset of the originals values.
76
 */
77
#define ARR_DESC_DEFINE_SUBSET(name, original, element_cnt)         \
78
    ARR_DESC_INTERNAL_DEFINE(name,                                  \
79
                             &ARR_DESC_ARR_NAME(original),          \
80
                             element_cnt,                           \
81
                             sizeof(ARR_DESC_ARR_NAME(original)[0]) \
82
        ) /* Note the lacking semicolon */
83
 
84
/**
85
 *  Creat an #ARR_DESC_t which points to the data in an existing array.
86
 *
87
 *  @param start_idx Offset in array_ptr of first element.
88
 *  @param element_cnt Number of elements to include in the #ARR_DESC_t.
89
 *
90
 *  @example
91
 *
92
 *  float my_floats[4] = {0.0f, 1.0f, 2.0f, 3.0f};
93
 *
94
 *  ARR_DESC_DEFINE_USING_ARR(my_arr_desc, my_floats, 1, 3);
95
 *
96
 *  printf("Element 0: %f\n", ARR_DESC_ELT(float, 0, &my_arr_desc));
97
 *  printf("Element 1: %f\n", ARR_DESC_ELT(float, 1, &my_arr_desc));
98
 *
99
 *  Outputs:
100
 *
101
 *  Element 0: 1.000000
102
 *  Element 1: 2.000000
103
 *
104
 *  @warning There are no checks in place to catch invalid start indices; This
105
 *  is left to the user.
106
 */
107
#define ARR_DESC_DEFINE_USING_ARR(type, name, array_ptr, start_idx, element_cnt) \
108
    ARR_DESC_INTERNAL_DEFINE(                                           \
109
        name,                                                           \
110
        (type *) (array_ptr + start_idx),                               \
111
        element_cnt,                                                    \
112
        sizeof(type)                                                    \
113
        ) /* Note the lacking semicolon*/
114
 
115
/**
116
 *  Declare an #ARR_DESC_t object.
117
 */
118
#define ARR_DESC_DECLARE(name)                              \
119
    extern ARR_DESC_t name /* Note the lacking semicolon */
120
 
121
/**
122
 *  Evaluate to the number of bytes stored in the #ARR_DESC_t.
123
 */
124
#define ARR_DESC_BYTES(arr_desc_ptr)                                \
125
    ((arr_desc_ptr)->element_count * (arr_desc_ptr)->element_size)
126
 
127
/**
128
 *  Set the contents of #ARR_DESC_t to value.
129
 */
130
#define ARR_DESC_MEMSET(arr_desc_ptr, value, bytes)     \
131
    do                                                  \
132
    {                                                   \
133
        memset((arr_desc_ptr)->data_ptr,                \
134
               value,                                   \
135
               BOUND(0,                                 \
136
                     (arr_desc_ptr)->underlying_size,   \
137
                     bytes)                             \
138
            );                                          \
139
    } while (0)
140
 
141
/**
142
 *  Perform a memcpy of 'bytes' bytes from the source #ARR_DESC_t to the
143
 *  destination #ARR_DESC_t.
144
 */
145
#define ARR_DESC_MEMCPY(arr_desc_dest_ptr, arr_desc_src_ptr, bytes) \
146
    do                                                              \
147
    {                                                               \
148
        memcpy((arr_desc_dest_ptr)->data_ptr,                       \
149
               (arr_desc_src_ptr)->data_ptr,                        \
150
               BOUND(0,                                             \
151
                     (arr_desc_dest_ptr)->underlying_size,          \
152
                     bytes));                                       \
153
    } while (0)
154
 
155
/**
156
 *  Evaluate to true if the source #ARR_DESC_t contents will fit into the
157
 *  destination #ARR_DESC_t and false otherwise.
158
 */
159
#define ARR_DESC_COPYABLE(arr_desc_dest_ptr, arr_desc_src_ptr)  \
160
      (ARR_DESC_BYTES(arr_desc_src_ptr) <=                      \
161
       (arr_desc_dest_ptr)->underlying_size)
162
 
163
/**
164
 *  Copy all the data from the source #ARR_DESC_t to the destination
165
 *  #ARR_DESC_t.
166
 *
167
 *  @note If the destination #ARR_DESC_t is too small to fit the source data the
168
 *  copy is aborted and nothing happens.
169
 */
170
#define ARR_DESC_COPY(arr_desc_dest_ptr, arr_desc_src_ptr)      \
171
    do                                                          \
172
    {                                                           \
173
        if (ARR_DESC_COPYABLE(arr_desc_dest_ptr,                 \
174
                             arr_desc_src_ptr))                 \
175
        {                                                       \
176
            ARR_DESC_MEMCPY(arr_desc_dest_ptr,                  \
177
                            arr_desc_src_ptr,                   \
178
                            ARR_DESC_BYTES(arr_desc_src_ptr));  \
179
            /* Update the properties*/                          \
180
            (arr_desc_dest_ptr)->element_count =                \
181
                (arr_desc_src_ptr)->element_count;              \
182
            (arr_desc_dest_ptr)->element_size =                 \
183
                (arr_desc_src_ptr)->element_size;               \
184
        }                                                       \
185
    } while (0)
186
 
187
/**
188
 *  Compare the data in two #ARR_DESC_t structs for the specified number of
189
 *  bytes.
190
 */
191
#define ARR_DESC_MEMCMP(arr_desc_ptr_a, arr_desc_ptr_b, bytes)  \
192
        memcmp((arr_desc_ptr_a)->data_ptr,                      \
193
            (arr_desc_ptr_b)->data_ptr,                         \
194
               bytes) /* Note the lacking semicolon */          \
195
 
196
/**
197
 *  Zero out the contents of the #ARR_DESC_t.
198
 */
199
#define ARR_DESC_ZERO(arr_desc_ptr)             \
200
        ARR_DESC_MEMSET(arr_desc_ptr,           \
201
                        0,                      \
202
                        (arr_desc_ptr)->underlying_size)
203
 
204
/**
205
 *  Evaluate to the data address in #ARR_DESC_t at offset.
206
 */
207
#define ARR_DESC_DATA_ADDR(type, arr_desc_ptr, offset)  \
208
        ((void*)(((type *)                              \
209
                  ((arr_desc_ptr)->data_ptr))           \
210
                 + offset))
211
 
212
/**
213
 *  Evaluate to the element in #ARR_DESC_t with type at idx.
214
 */
215
#define ARR_DESC_ELT(type, idx, arr_desc_ptr)           \
216
        (*((type *) ARR_DESC_DATA_ADDR(type,            \
217
                                       arr_desc_ptr,    \
218
                                       idx)))
219
 
220
#endif /* _ARR_DESC_H_ */