aboutsummaryrefslogtreecommitdiff
path: root/framework/include/libmetal/utilities.h
blob: e60f34575a081d2c8dd075950a2fe13f18c4ee92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*
 * @file	utilities.h
 * @brief	Utility routines for libmetal.
 */

#ifndef __METAL_UTILITIES__H__
#define __METAL_UTILITIES__H__

#include <stdint.h>
#include <limits.h>
#include <assert.h>

#ifdef __cplusplus
extern "C" {
#endif

/** \defgroup utilities Simple Utilities
 *  @{ */

/** Marker for unused function arguments/variables. */
#define metal_unused(x)	do { (x) = (x); } while (0)

/** Figure out number of elements in an array. */
#define metal_dim(x)	(sizeof(x) / sizeof(x[0]))

/** Minimum of two numbers (warning: multiple evaluation!).  */
#define metal_min(x, y)	((x) < (y) ? (x) : (y))

/** Maximum of two numbers (warning: multiple evaluation!).  */
#define metal_max(x, y)	((x) > (y) ? (x) : (y))

/** Sign of a number [-1, 0, or 1] (warning: multiple evaluation!).  */
#define metal_sign(x)	((x) < 0 ? -1 : ((x) > 0 ? 1 : 0))

/** Align 'size' down to a multiple of 'align' (must be a power of two). */
#define metal_align_down(size, align)			\
	((size) & ~((align) - 1))

/** Align 'size' up to a multiple of 'align' (must be a power of two). */
#define metal_align_up(size, align)			\
	metal_align_down((size) + (align) - 1, align)

/** Divide (and round down). */
#define metal_div_round_down(num, den)			\
	((num) / (den))

/** Divide (and round up). */
#define metal_div_round_up(num, den)			\
	metal_div_round_down((num) + (den) - 1, (den))

/** Align 'ptr' down to a multiple of 'align' (must be a power of two). */
#define metal_ptr_align_down(ptr, align)		\
	(void *)(metal_align_down((uintptr_t)(ptr), (uintptr_t)(align)))

/** Align 'ptr' up to a multiple of 'align' (must be a power of two). */
#define metal_ptr_align_up(ptr, align)			\
	(void *)(metal_align_up((uintptr_t)(ptr), (uintptr_t)(align)))

/** Compute offset of a field within a structure. */
#define metal_offset_of(structure, member)		\
	((uintptr_t) &(((structure *) 0)->member))

/** Compute pointer to a structure given a pointer to one of its fields. */
#define metal_container_of(ptr, structure, member)	\
	(void *)((uintptr_t)(ptr) - metal_offset_of(structure, member))

#define METAL_BITS_PER_ULONG	(CHAR_BIT * sizeof(unsigned long))

#define metal_bit(bit)		(1UL << (bit))

#define metal_bitmap_longs(x)	metal_div_round_up((x), METAL_BITS_PER_ULONG)

static inline void metal_bitmap_set_bit(unsigned long *bitmap, int bit)
{
	bitmap[bit / METAL_BITS_PER_ULONG] |=
		metal_bit(bit & (METAL_BITS_PER_ULONG - 1));
}

static inline int metal_bitmap_is_bit_set(unsigned long *bitmap, int bit)
{
	return ((bitmap[bit / METAL_BITS_PER_ULONG] &
		metal_bit(bit & (METAL_BITS_PER_ULONG - 1))) == 0) ? 0 : 1;
}

static inline void metal_bitmap_clear_bit(unsigned long *bitmap, int bit)
{
	bitmap[bit / METAL_BITS_PER_ULONG] &=
		~metal_bit(bit & (METAL_BITS_PER_ULONG - 1));
}

static inline int metal_bitmap_is_bit_clear(unsigned long *bitmap, int bit)
{
	return !metal_bitmap_is_bit_set(bitmap, bit);
}

static inline unsigned int
metal_bitmap_next_set_bit(unsigned long *bitmap, unsigned int start,
			  unsigned int max)
{
	unsigned int bit;
	for (bit = start;
	     bit < max && !metal_bitmap_is_bit_set(bitmap, bit);
	     bit ++)
		;
	return bit;
}

#define metal_bitmap_for_each_set_bit(bitmap, bit, max)			\
	for ((bit) = metal_bitmap_next_set_bit((bitmap), 0, (max));	\
	     (bit) < (max);						\
	     (bit) = metal_bitmap_next_set_bit((bitmap), (bit + 1), (max)))

static inline unsigned int
metal_bitmap_next_clear_bit(unsigned long *bitmap, unsigned int start,
			    unsigned int max)
{
	unsigned int bit;
	for (bit = start;
	     bit < max && !metal_bitmap_is_bit_clear(bitmap, bit);
	     bit ++)
		;
	return bit;
}

#define metal_bitmap_for_each_clear_bit(bitmap, bit, max)		\
	for ((bit) = metal_bitmap_next_clear_bit((bitmap), 0, (max));	\
	     (bit) < (max);						\
	     (bit) = metal_bitmap_next_clear_bit((bitmap), (bit + 1), (max)))

static inline unsigned long metal_log2(unsigned long in)
{
	unsigned long result;

	assert((in & (in - 1)) == 0);

	for (result = 0; (1UL << result) < in; result ++)
		;
	return result;
}

/** @} */

#ifdef __cplusplus
}
#endif

#endif /* __METAL_UTILITIES__H__ */