1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2022 Intel Corporation. All rights reserved.
4  */
5 
6 #ifndef DSP_FW_FW_ARRAY_H_
7 #define DSP_FW_FW_ARRAY_H_
8 
9 #include <stdint.h>
10 #include <stddef.h>
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 /*! Wrapper for buffer descriptor. */
17 typedef struct byte_array {
18 	/*! Pointer to buffer begin. */
19 	uint8_t    *data;
20 	/*! Size of buffer (in number of elements, typically bytes). */
21 	size_t      size;
22 } byte_array_t;
23 
array_get_data(const byte_array_t * ba)24 static inline uint8_t *array_get_data(const byte_array_t *ba)
25 {
26 	return (uint8_t *)ba->data;
27 }
28 
array_get_data_end(const byte_array_t * ba)29 static inline uint8_t *array_get_data_end(const byte_array_t *ba)
30 {
31 	return array_get_data(ba) + ba->size;
32 }
33 
34 
array_get_size(const byte_array_t * ba)35 static inline size_t array_get_size(const byte_array_t *ba)
36 {
37 	return ba->size;
38 }
39 
array_alloc_from(byte_array_t * ba,size_t required_size)40 static inline uint8_t *array_alloc_from(byte_array_t *ba,
41 					size_t required_size)
42 {
43 	/* TODO: add alignment */
44 	/* TODO: validate inputs */
45 	/* TODO: move this to more appropriate file */
46 
47 	uint8_t *cached_data = array_get_data(ba);
48 
49 	ba->data += required_size;
50 	ba->size -= required_size;
51 
52 	return cached_data;
53 }
54 #ifdef __cplusplus
55 } /* extern "C" */
56 #endif
57 
58 #ifdef __cplusplus
59 /* clang-format off */
60 #define assert(cond)
61 
array_get_data(const byte_array_t & ba)62 static inline uint8_t *array_get_data(const byte_array_t &ba)
63 {
64 	return (uint8_t *)ba.data;
65 }
66 
array_get_size(const byte_array_t & ba)67 static inline size_t array_get_size(const byte_array_t &ba)
68 {
69 	return ba.size;
70 }
71 
72 namespace dsp_fw
73 {
74 /*!
75  *  Provides a safe wrapper around array allocated in continuous memory.
76  *  Size of the array specified by the client is checked on any attempt
77  *  to access the array data.
78  *
79  * \note Wrapper does not take over ownership of the array. The array
80  * must be deallocated elsewhere by its proper owner.
81  *
82  * \note All copy operations are shallow bit copies of the array.
83  * The array is expected to keep built-in types or pointers, so
84  * there is no assignment operator called for each copied entry.
85  *
86  * \note Array (especially Array<uint8_t>/ByteArray) can be casted to
87  * byte_array_t as there are binary compatible
88  */
89 template < class T >
90 class Array /*: public byte_array*/
91 {
92 public:
93 
94 /*!
95  * Default ctor to provide two-stage initialization completed by Init() call.
96  */
Array()97 Array()
98 {
99 	data_ = NULL;
100 	size_ = 0;
101 }
102 
103 /*!
104  * Constructs the object and initializes pointer and size to the provided
105  * values.
106  *
107  * \param ptr - Pointer to the array.
108  * \param size - Size of the array pointed by the ptr.
109  */
Array(T * ptr,size_t size)110 Array(T * ptr, size_t size)
111 {
112 	data_ = (T *)ptr;
113 	size_ = size;
114 }
115 
116 /*!
117  *  Completes two-stage object initialization when initialized by the default
118  *  ctor.
119  *
120  * \param ptr - Pointer to the array.
121  * \param size - Size of the array pointed by the ptr.
122  */
Init(T * ptr,size_t size)123 void Init(T *ptr, size_t size)
124 {
125 	data_ = (T *)ptr;
126 	size_ = size;
127 }
128 
129 /*!
130  * Completes two-stage object initialization when initialized by the default
131  * ctor.
132  *
133  * \param ptr - Pointer to the array.
134  * \param end - Pointer to the end of the array.
135  */
InitWithRange(T * ptr,T * ptr_end)136 void InitWithRange(T *ptr, T *ptr_end)
137 {
138 	assert(ptr_end >= ptr);
139 	data_ = (T *)ptr;
140 	size_ = ptr_end - ptr;
141 }
142 
143 /*!
144  * Detaches the wrapper from the array object. Provided for the sake of
145  * completeness since array lifetime is not bound to the wrapper lifetime.
146  */
Detach(void)147 void Detach(void) { data_ = NULL; size_ = 0; }
148 /*!
149  * Retrieves the size of the array.
150  *
151  * \return Size of the array. It may be zero if the wrapper is not fully
152  *         initialized.
153  */
size(void)154 size_t size(void) const { return size_; }
155 /*!
156  * Retrieves allocated size of buffer in bytes.
157  */
alloc_size(void)158 size_t alloc_size(void) const { return size()*sizeof(T); }
159 /*!
160  * Resizes the array.
161  */
Resize(size_t new_size)162 void Resize(size_t new_size) { size_ = new_size; }
163 /*!
164  * Retrieves address of the array (const version).
165  * \return Address of the array. It may be null if the wrapper is not fully
166  * initialized.
167  */
data(void)168 const T *data(void) const { return (const T *)data_; }
169 /*!
170  * Retrieves address of the array (modifiable version).
171  *
172  * \return Address of the array. It may be null if the wrapper is not fully
173  * initialized.
174  */
data(void)175 T *data(void) { return (T *)data_; }
176 /*!
177  * Retrieves address of end of the array (const version).
178  * \return Address of the array.
179  */
data_end(void)180 const T *data_end(void) const { return data() + size_; }
181 /*!
182  * Retrieves address of end of the array (modifiable version).
183  * \return Address of end of the array.
184  */
data_end(void)185 T *data_end(void) { return data() + size_; }
186 /*!
187  * Safe (in debug) operator to access element of the array (const version).
188  *
189  * \param idx Index of the element to be accessed.
190  * \return Reference to the element.
191  */
192 const T & operator[](size_t idx) const {
193 	/*assert(idx < size()); //TODO: no exceptions, release err handling req */
194 	return data()[idx];
195 }
196 
197 /*!
198  * Safe (in debug) operator to access element of the array (modifiable version).
199  *
200  * \param idx Index of the element to be accessed.
201  * \return Reference to the element.
202  */
203 T & operator[](size_t idx) {
204 	/*assert(idx < size()); //TODO: no exceptions, release err handling req */
205 	return data()[idx];
206 }
207 
208 /*!
209  * Safe copy-from operation that verifies size of source and this.
210  *
211  * \param src Address of the source array to be copied into this.
212  * \param srcSize Size of the source array.
213  * \param dst_offset Offset in the destination array to start copying data at
214  * (expressed in number of items).
215  */
216 void copyFrom(const T *src, size_t srcSize, size_t dst_offset = 0)
217 {
218 	assert(data() != NULL);
219 	assert(size() > dst_offset);
220 	assert((size() - dst_offset) >= srcSize);
221 	memcpy_s(data() + dst_offset, alloc_size() - dst_offset * sizeof(T),
222 		src, srcSize * sizeof(T));
223 }
224 
225 /*!
226  * Safe copy-from operation that verifies size of source and this.
227  *
228  * \param src The source array to be copied into this.
229  * \param dst_offset Offset in the destination array to start copying data at
230  * (expressed in number of items).
231  */
232 void copyFrom(const Array < T > &src, size_t dst_offset = 0)
233 {
234 	assert(data() != 0);
235 	assert(size() > dst_offset);
236 	assert((size() - dst_offset) >= src.size());
237 	memcpy_s(data() + dst_offset, alloc_size() - dst_offset * sizeof(T),
238 		src.data(), src.alloc_size());
239 }
240 
241 /*!
242  * Safe copy-to operation that verifies size of the destination and this.
243  * \param dst Address of the destination array to be overwritten by this.
244  * \param dstSize Size of the destination array.
245  */
copyTo(T * dst,size_t dstSize)246 void copyTo(T *dst, size_t dstSize) const {
247 	assert(data() != 0);
248 	assert(size() <= dstSize);
249 	memcpy_s(dst, dstSize * sizeof(T), data(), alloc_size());
250 }
251 
252 /*!
253  * Safe copy-to operation that verifies size of the destination and this.
254  * \param dst The destination array to be overwritten by this.
255  */
copyTo(Array<T> & dst)256 void copyTo(Array < T > &dst) const {
257 	assert(data() != 0);
258 	assert(size() <= dst.size());
259 	memcpy_s(dst.data(), dst.alloc_size(), data(), alloc_size());
260 }
261 
262 /*!
263  * Copies as much as specified size starting from specified offset.
264  * \param dst Destination buffer.
265  * \param copy_size Number of items to be copied.
266  * \param src_offset Offset in the source buffer (in number of items).
267  */
268 void copyFragmentTo(Array < T > &dst, size_t copy_size, size_t src_offset = 0) const {
269 	assert(data() != 0);
270 	assert((src_offset + copy_size) <= size());
271 	assert(copy_size <= dst.size());
272 	memcpy_s(dst.data(), dst.alloc_size(), data() + src_offset, copy_size * sizeof(T));
273 }
274 
275 /*!
276  * Safe cast of the content of the array to the specified type (modifiable
277  * version).
278  * \return Pointer to the requested type if array is large enough to be
279  *        casted, NULL otherwise.
280  */
281 template < class TC >
dataAs(void)282 TC *dataAs(void)
283 {
284 	if (alloc_size() < sizeof(TC)) {
285 		assert(false);
286 		return NULL;
287 	}
288 	return reinterpret_cast < TC * > (data());
289 }
290 
291 template < class TC >
dataAsArray(size_t size)292 TC *dataAsArray(size_t size)
293 {
294 	if (alloc_size() < sizeof(TC)*size) {
295 		assert(false);
296 		return NULL;
297 	}
298 	return reinterpret_cast < TC * > (data());
299 }
300 
301 /*!
302  * Safe cast of the content of the array to the specified type (const version).
303  * \return Pointer to the requested type if array is large enough to be
304  * casted, NULL otherwise.
305  */
306 template < class TC >
dataAs(void)307 const TC *dataAs(void) const {
308 	if (alloc_size() < sizeof(TC)) {
309 		assert(false);
310 		return NULL;
311 	}
312 	return reinterpret_cast < const TC * > (data());
313 }
314 
315 /*!
316  * Inserts object of specified type into the buffer.
317  * Use this explicit call instead of operator=(TC) or stream-like <<.
318  */
319 template < class TC >
setDataAs(const TC & d)320 void setDataAs(const TC & d)
321 {
322 	TC *t = dataAs < TC > ();
323 
324 	if (t == NULL) {
325 		assert(false);
326 		return;
327 	}
328 	*t = d; /* using operator=, not shallow copy */
329 	Resize(sizeof(TC));
330 }
331 
332 /*!
333  * Safe zero-memory on the underlying buffer.
334  */
clear(void)335 void clear(void)
336 {
337 	memset(data(), 0x00, alloc_size());
338 }
339 
Swap(Array<T> * array)340 void Swap(Array < T > *array)
341 {
342 	Array < T > temp(*array);
343 	array->data_ = data_;
344 	array->size_ = size_;
345 	this->data_ = temp.data_;
346 	this->size_ = temp.size_;
347 }
348 
Swap(Array<T> & array)349 void Swap(Array < T > &array)
350 {
351 	Array < T > temp(array);
352 	array.data_ = data_;
353 	array.size_ = size_;
354 	this->data_ = temp.data_;
355 	this->size_ = temp.size_;
356 }
357 private:
358 	T *data_;
359 	size_t size_;
360 };
361 
362 /*!
363  * Predefined type of array of bytes.
364  */
365 typedef Array < uint8_t > ByteArray;
366 
367 /*!
368  * Predefined type of array of dwords.
369  */
370 typedef Array < uint32_t > DwordArray;
371 
372 } /* end of namespace dsp_fw */
373 
374 #endif /* __cplusplus */
375 /* clang-format on */
376 #endif /* #ifndef DSP_FW_FW_ARRAY_H_ */
377