Browse code

Improve documentation. Add tests. Move objc related stuff to mulle-objc. Rename some functions.

Nat! authored on 10/10/2016 19:01:48
Showing 9 changed files
... ...
@@ -1,19 +1,18 @@
1 1
 # mulle-vararg
2 2
 
3
-The variable argument passing scheme used in the MetaABI of mulle-objc.
4
-Written in C (C11).
3
+A variable argument passing scheme used written in C (C11).
5 4
 
6 5
 ## How it works
7 6
 
8 7
 ### Remember the C argument promotion rules
9 8
 
10
-1. char and short to int/unsigned int 
9
+1. char and short to int/unsigned int
11 10
 2. float to double
12 11
 
13 12
 ### The arguments are layed out struct-like
14 13
 
15 14
 A method like `stringWithFormat:(NSString *) format, ...`
16
-which is called like this 
15
+which is called like this
17 16
 
18 17
 ```
19 18
 [NSString stringWithFormat:@"%d %f %lld", (char) 'x', (float) 0.2, 1848LL];
... ...
@@ -25,7 +24,7 @@ could access the arguments as if they were embedded in a struct like this
25 25
 struct
26 26
 {
27 27
    NSString  *format;
28
-   struct 
28
+   struct
29 29
    {
30 30
       int         value1;
31 31
       double      value2;
... ...
@@ -1,3 +1,13 @@
1
+## 0.5
2
+
3
+* renamed function `mulle_align` to `mulle_address_align`
4
+* renamed function `mulle_align_pointer` to `mulle_pointer_align`
5
+* renamed function `mulle_vararg_count` to `mulle_vararg_count_pointers`
6
+* moved **id** macros to mulle-objc
7
+* wrote some documentation
8
+* added a test
9
+
10
+
1 11
 ## 0.4
2 12
 
3 13
 * i386 has some crazy alignment rules. So alignment has to be calculated
... ...
@@ -11,7 +21,7 @@
11 11
 ## 0.2
12 12
 
13 13
 * fixed catastrophic miscalculation
14
-   
14
+
15 15
 ## 0.1
16 16
 
17 17
 * added versioning
18 18
new file mode 100755
... ...
@@ -0,0 +1,68 @@
0
+#! /bin/sh
1
+#
2
+# Generate a formula for mulle-thread
3
+#
4
+PROJECT=MulleVararg  # ruby requires camel-case
5
+TARGET=mulle-vararg
6
+HOMEPAGE="http://www.mulle-kybernetik.com/software/git/${TARGET}"
7
+DESC="Variable arguments using offset() and sizeof()"
8
+
9
+VERSION="$1"
10
+[ $# -eq 0 ] || shift
11
+ARCHIVEURL="${1:-http://www.mulle-kybernetik.com/software/git/${TARGET}/tarball/$VERSION}"
12
+[ $# -eq 0 ] || shift
13
+
14
+set -e
15
+
16
+[ "$VERSION" = "" ] && exit 1
17
+[ "$ARCHIVEURL" = "" ] && exit 1
18
+
19
+
20
+TMPARCHIVE="/tmp/${TARGET}-${VERSION}-archive"
21
+
22
+if [ ! -f "${TMPARCHIVE}" ]
23
+then
24
+   curl -L -o "${TMPARCHIVE}" "${ARCHIVEURL}"
25
+   if [ $? -ne 0 -o ! -f "${TMPARCHIVE}" ]
26
+   then
27
+      echo "Download failed" >&2
28
+      exit 1
29
+   fi
30
+else
31
+   echo "using cached file ${TMPARCHIVE} instead of downloading again" >&2
32
+fi
33
+
34
+#
35
+# anything less than 17 KB is wrong
36
+#
37
+size="`du -k "${TMPARCHIVE}" | awk '{ print $ 1}'`"
38
+if [ $size -lt 17 ]
39
+then
40
+   echo "Archive truncated or missing" >&2
41
+   cat "${TMPARCHIVE}" >&2
42
+   rm "${TMPARCHIVE}"
43
+   exit 1
44
+fi
45
+
46
+HASH="`shasum -p -a 256 "${TMPARCHIVE}" | awk '{ print $1 }'`"
47
+
48
+cat <<EOF
49
+class ${PROJECT} < Formula
50
+  homepage "${HOMEPAGE}"
51
+  desc "${DESC}"
52
+  url "${ARCHIVEURL}"
53
+  version "${VERSION}"
54
+  sha256 "${HASH}"
55
+
56
+  depends_on 'mulle-c11'
57
+  depends_on 'mulle-build' => :build
58
+
59
+  def install
60
+     system "mulle-install", "-e", "--prefix", "#{prefix}"
61
+  end
62
+
63
+  test do
64
+  end
65
+end
66
+# FORMULA ${TARGET}.rb
67
+EOF
0 68
new file mode 100755
... ...
@@ -0,0 +1,79 @@
0
+#! /bin/sh
1
+
2
+NAME="mulle-vararg"  # not the ruby name
3
+HEADER="src/mulle_vararg.h"
4
+VERSIONNAME="MULLE_VARARG_VERSION"
5
+ORIGIN=public
6
+
7
+RBFILE="${NAME}.rb"
8
+HOMEBREWTAP="../homebrew-software"
9
+
10
+
11
+get_version()
12
+{
13
+   local filename
14
+
15
+   filename="$1"
16
+   fgrep "${VERSIONNAME}" "${filename}" | \
17
+   sed 's|(\([0-9]*\) \<\< [0-9]*)|\1|g' | \
18
+   sed 's|^.*(\(.*\))|\1|' | \
19
+   sed 's/ | /./g'
20
+}
21
+
22
+VERSION="`get_version ${HEADER}`"
23
+TAG="${1:-${VERSION}}"
24
+
25
+
26
+directory="`mulle-bootstrap library-path 2> /dev/null`"
27
+[ ! -d "${directory}" ] && echo "failed to locate mulle-bootstrap library" >&2 && exit 1
28
+
29
+PATH="${directory}:$PATH"
30
+
31
+. "mulle-bootstrap-logging.sh"
32
+
33
+
34
+git_must_be_clean()
35
+{
36
+   local name
37
+   local clean
38
+
39
+   name="${1:-${PWD}}"
40
+
41
+   if [ ! -d .git ]
42
+   then
43
+      fail "\"${name}\" is not a git repository"
44
+   fi
45
+
46
+   clean=`git status -s --untracked-files=no`
47
+   if [ "${clean}" != "" ]
48
+   then
49
+      fail "repository \"${name}\" is tainted"
50
+   fi
51
+}
52
+
53
+
54
+[ ! -d "${HOMEBREWTAP}" ] && fail "failed to locate \"${HOMEBREWTAP}\""
55
+
56
+set -e
57
+
58
+git_must_be_clean
59
+
60
+branch="`git rev-parse --abbrev-ref HEAD`"
61
+
62
+git push "${ORIGIN}" "${branch}"
63
+
64
+# seperate step, as it's tedious to remove tag when
65
+# previous push fails
66
+
67
+git tag "${TAG}"
68
+git push "${ORIGIN}" "${branch}" --tags
69
+
70
+./bin/generate-brew-formula.sh "${VERSION}" > "${HOMEBREWTAP}/${RBFILE}"
71
+(
72
+   cd "${HOMEBREWTAP}" ;
73
+   git add "${RBFILE}" ;
74
+   git commit -m "${TAG} release of ${NAME}" "${RBFILE}" ;
75
+   git push origin master
76
+)
77
+
78
+git checkout "${branch}"
0 79
new file mode 100644
... ...
@@ -0,0 +1,267 @@
0
+# mulle-vararg API
1
+
2
+Familiarize yourself with [stdarg](//wikipedia.org/wiki/Stdarg.h) first,
3
+because **mulle-vararg** is very similiar. The main difference is, that
4
+in stdarg you specify the type as a parameter to `va_next`, whereas in
5
+**mulle-vararg** you need to call different macros depending on type.
6
+
7
+> Attention: **mulle-valist** is not compatible with **valist**
8
+
9
+
10
+Here is an example. A structure is defined with two fields, **a** and **b**.
11
+`mulle_vararg_start` is initialized with **a**. It will now use the
12
+first value *AFTER* **a** as the first variable argument.
13
+
14
+So this code will effectively output `18`.
15
+
16
+```
17
+#include <mulle_vararg/mulle_vararg.h>
18
+#include <stdio.h>
19
+
20
+
21
+struct
22
+{
23
+   void  *a;
24
+   char  b;
25
+} value =
26
+{
27
+   -1848,
28
+   18
29
+};
30
+
31
+
32
+int   main( void)
33
+{
34
+   mulle_vararg_list   list;
35
+
36
+   mulle_vararg_start( list, value.a);
37
+
38
+   printf( "%d\n", mulle_vararg_next_integer( list, char));
39
+
40
+   mulle_vararg_end( list);
41
+   return( 0);
42
+}
43
+```
44
+
45
+## Types
46
+
47
+Type                | Description
48
+--------------------|------------------------------------------------
49
+`mulle_vararg_list` | The variable argument storage.
50
+
51
+
52
+
53
+## Macros
54
+
55
+
56
+### mulle_vararg_copy - copy varargs
57
+
58
+`mulle_vararg_copy( dst, src)`
59
+
60
+Copy `mulle_vararg_list` **src** to **dst**. Use this if you want to iterate
61
+a second time over a `mulle_vararg_list` argument.
62
+
63
+
64
+#### mulle_vararg_end - end varargs
65
+
66
+`mulle_vararg_end( args)`
67
+
68
+Marks the end of the use of **args** `mulle_vararg_list` variable.
69
+
70
+
71
+#### mulle_vararg_next_fp - next floating point value
72
+
73
+`mulle_vararg_next_fp( args, type)`
74
+
75
+Use it for all floating point types, like float, double, long double.
76
+
77
+
78
+Example:
79
+
80
+```
81
+mulle_vararg_next_fp( args, float);
82
+```
83
+
84
+
85
+#### mulle_vararg_next_integer - next integer value
86
+
87
+`mulle_vararg_next_integer( args, type)`
88
+
89
+Use it for all integer types, like char, short, int, long, long long and their
90
+unsigned variants.
91
+
92
+Example:
93
+
94
+```
95
+mulle_vararg_next_integer( args, unsigned short);
96
+```
97
+
98
+
99
+#### mulle_vararg_next_pointer - next pointer value
100
+
101
+`mulle_vararg_next_pointer( args, type)`
102
+
103
+Use it for all pointer types.
104
+
105
+Example:
106
+
107
+```
108
+mulle_vararg_next_pointer( args, int *);
109
+```
110
+
111
+
112
+#### mulle_vararg_next_struct - next struct value
113
+
114
+`mulle_vararg_next_struct( args, type)`
115
+
116
+Use it for all struct types.
117
+
118
+Example:
119
+
120
+```
121
+struct x_t
122
+{
123
+   int a;
124
+   int b;
125
+} x;
126
+
127
+x = mulle_vararg_next_struct( args, struct x_t);
128
+```
129
+
130
+
131
+#### _mulle_vararg_next_struct - next address of struct
132
+
133
+`_mulle_vararg_next_struct( args, type)`
134
+
135
+Use it for all struct types. The struct will not be copied, but
136
+instead you get a reference into the varargs. This is obviously more
137
+risky!
138
+
139
+Example:
140
+
141
+```
142
+struct x_t
143
+{
144
+   int a;
145
+   int b;
146
+} *x;   // pointer
147
+
148
+x = mulle_vararg_next_struct( args, struct x_t);
149
+```
150
+
151
+
152
+#### mulle_vararg_next_union - next union value
153
+
154
+`mulle_vararg_next_union( args, type)`
155
+
156
+Use it for all union types.
157
+
158
+Example:
159
+
160
+```
161
+union x_t
162
+{
163
+   int a;
164
+   int b;
165
+} x;
166
+
167
+x = mulle_vararg_next_union( args, union x_t);
168
+```
169
+
170
+#### _mulle_vararg_next_union - get address of next union
171
+
172
+`_mulle_vararg_next_union( args, type)`
173
+
174
+Use it for all union types. The union will not be copied, but
175
+instead you get a reference into the varargs. This is obviously more
176
+risky!
177
+
178
+Example:
179
+
180
+```
181
+union x_t
182
+{
183
+   int a;
184
+   int b;
185
+} *x;   // pointer
186
+
187
+x = mulle_vararg_next_union( args, struct x_t);
188
+```
189
+
190
+
191
+
192
+#### mulle_vararg_start - start varargs
193
+
194
+`mulle_vararg_start( args, ap)`
195
+
196
+**args** is a `mulle_vararg_list` variable. **ap** is the last non-variable
197
+argument.
198
+
199
+
200
+## Functions
201
+
202
+
203
+####  mulle_address_align - align an address
204
+
205
+`uintptr_t   mulle_address_align( uintptr_t p, unsigned int alignment)`
206
+
207
+Pass in an address **p** and an alignment **alignment**. `mulle_address_align`
208
+will return the aligned address.
209
+
210
+e.g. `mulle_address_align( 0x11, 0x10)` will return `0x20`
211
+
212
+
213
+####  mulle_pointer_align - align a pointer
214
+
215
+`void   *mulle_pointer_align( void *p, unsigned int alignment)`
216
+
217
+Pass in a pointer **p** and an alignment **alignment**. `mulle_align_pointer`
218
+will return the aligned pointer.
219
+
220
+
221
+####  mulle_vararg_count_pointers - count null terminated vararg pointers
222
+
223
+`size_t   mulle_vararg_count_pointers( mulle_vararg_list args, void *p)`
224
+
225
+The interface is a bit weird but practical. You give it a variable argument
226
+list and the first pointer of that list of pointers. The function assumes that
227
+all subsequent variable arguments are also of pointer type. It will then
228
+compute the number of non-NULL pointers including *p**.
229
+
230
+Example:
231
+
232
+```
233
+#include <mulle_vararg/mulle_vararg.h>
234
+#include <stdio.h>
235
+
236
+
237
+struct pointer_32_t
238
+{
239
+   void  *pointers[ 32];
240
+};
241
+
242
+
243
+static size_t   count( struct pointer_32_t *array)
244
+{
245
+   mulle_vararg_list   list;
246
+   size_t              n;
247
+
248
+   mulle_vararg_start( list, array->pointers[ 0]);
249
+
250
+   n = mulle_vararg_count_pointers( list, array->pointers[ 0]);
251
+
252
+   mulle_vararg_end( list);
253
+   return( n);
254
+}
255
+
256
+
257
+int main()
258
+{
259
+   struct pointer_32_t   array = { (void *) 0x1848, (void *) 0x1849, NULL };
260
+
261
+   printf( "%ld\n", (long) count( &array));  // will print 2
262
+}
263
+```
264
+
265
+
266
+
... ...
@@ -15,7 +15,7 @@
15 15
 
16 16
 
17 17
 MULLE_C_CONST_RETURN
18
-static inline uintptr_t   mulle_align( uintptr_t p, unsigned int alignment)
18
+static inline uintptr_t   mulle_address_align( uintptr_t p, unsigned int alignment)
19 19
 {
20 20
    intptr_t   misalignment;
21 21
 
... ...
@@ -30,9 +30,9 @@ static inline uintptr_t   mulle_align( uintptr_t p, unsigned int alignment)
30 30
 
31 31
 
32 32
 MULLE_C_CONST_RETURN
33
-static inline void   *mulle_align_pointer( void *p, unsigned int alignment)
33
+static inline void   *mulle_pointer_align( void *p, unsigned int alignment)
34 34
 {
35
-   return( (void *) mulle_align( (uintptr_t) p, alignment));
35
+   return( (void *) mulle_address_align( (uintptr_t) p, alignment));
36 36
 }
37 37
 
38 38
 
... ...
@@ -11,7 +11,7 @@
11 11
 
12 12
 #include "mulle_align.h"
13 13
 
14
-#define MULLE_VARARG_VERSION  ((0 << 20) | (4 << 8) | 0)
14
+#define MULLE_VARARG_VERSION  ((0 << 20) | (5 << 8) | 0)
15 15
 
16 16
 
17 17
 /*
... ...
@@ -62,10 +62,7 @@ do                                             \
62 62
 while( 0)
63 63
 
64 64
 
65
-
66
-
67 65
 // use this for integer types
68
-
69 66
 static inline char  *_mulle_vararg_int_aligned_pointer( mulle_vararg_list *args, size_t size, unsigned int align)
70 67
 {
71 68
    char   *q;
... ...
@@ -76,7 +73,7 @@ static inline char  *_mulle_vararg_int_aligned_pointer( mulle_vararg_list *args,
76 76
       align = alignof( struct{ int x; });  // weirdness for i386
77 77
    }
78 78
 
79
-   q       = mulle_align_pointer( args->p, align);
79
+   q       = mulle_pointer_align( args->p, align);
80 80
    args->p = &q[ size];
81 81
    return( q);
82 82
 }
... ...
@@ -92,28 +89,30 @@ static inline char  *_mulle_vararg_aligned_pointer( mulle_vararg_list *args, uns
92 92
 {
93 93
    char   *q;
94 94
 
95
-   q       = mulle_align_pointer( args->p, align);
95
+   q       = mulle_pointer_align( args->p, align);
96 96
    args->p = &q[ sizeof( void *)];
97 97
    return( q);
98 98
 }
99 99
 
100 100
 
101
-// use this for all pointer and id types
101
+// use this for all pointer types
102 102
 #define mulle_vararg_next_pointer( args, type)  \
103 103
    (*(type *) _mulle_vararg_aligned_pointer( &args, alignof( struct{ type x; })))
104 104
 
105
-// use this for objects types
106
-#define mulle_vararg_next( args)                \
107
-   mulle_vararg_next_pointer( args, id)
108
-
109
-// synonym
110
-#define mulle_vararg_next_object( args, type)    \
111
-   mulle_vararg_next_pointer( args, type)
112
-
113 105
 
114 106
 // use this for all struct types
107
+#define _mulle_vararg_next_struct( args, type)  \
108
+   ((type *) _mulle_vararg_aligned_pointer( &args, alignof( struct{ type x; })))
109
+
115 110
 #define mulle_vararg_next_struct( args, type)    \
116
-   (*(type *) _mulle_vararg_aligned_pointer( &args, alignof( struct{ type x; })))
111
+   (*_mulle_vararg_next_struct( args, type))
112
+
113
+// use this for all union types
114
+#define _mulle_vararg_next_union( args, type)    \
115
+   ((type *) _mulle_vararg_aligned_pointer( &args, alignof( struct{ type x; })))
116
+
117
+#define mulle_vararg_next_union( args, type)    \
118
+   (*_mulle_vararg_next_union( args, type))
117 119
 
118 120
 
119 121
 static inline char  *_mulle_vararg_double_aligned_pointer( mulle_vararg_list *args, size_t size, unsigned int align)
... ...
@@ -126,7 +125,7 @@ static inline char  *_mulle_vararg_double_aligned_pointer( mulle_vararg_list *ar
126 126
       align = alignof( struct{ double x; });  // weirdness for i386
127 127
    }
128 128
 
129
-   q       = mulle_align_pointer( args->p, align);
129
+   q       = mulle_pointer_align( args->p, align);
130 130
    args->p = &q[ size];
131 131
    return( q);
132 132
 }
... ...
@@ -139,27 +138,25 @@ static inline char  *_mulle_vararg_double_aligned_pointer( mulle_vararg_list *ar
139 139
       : *(type *) _mulle_vararg_double_aligned_pointer( &args, sizeof( type), alignof( struct{ type x; })))
140 140
 
141 141
 
142
-
143
-
144
-#define mulle_vararg_copy( dst, src)         \
145
-do                                           \
146
-{                                            \
147
-   dst = src;                                \
148
-}                                            \
142
+#define mulle_vararg_copy( dst, src)  \
143
+do                                    \
144
+{                                     \
145
+   dst = src;                         \
146
+}                                     \
149 147
 while( 0)
150 148
 
151 149
 #define mulle_vararg_end( args)
152 150
 
153 151
 
154
-// only works for objects and pointers
152
+// only works with pointers
155 153
 
156
-static inline size_t    mulle_vararg_count( mulle_vararg_list args, void *object)
154
+static inline size_t   mulle_vararg_count_pointers( mulle_vararg_list args, void *first)
157 155
 {
158 156
    size_t   count;
159 157
    void     *p;
160 158
 
161 159
    count = 0;
162
-   p     = object;
160
+   p     = first;
163 161
    while( p)
164 162
    {
165 163
       ++count;
... ...
@@ -169,4 +166,5 @@ static inline size_t    mulle_vararg_count( mulle_vararg_list args, void *object
169 169
    return( count);
170 170
 }
171 171
 
172
+
172 173
 #endif /* mulle_vararg_h */
173 174
new file mode 100644
... ...
@@ -0,0 +1,31 @@
0
+#include <mulle_vararg/mulle_vararg.h>
1
+#include <stdio.h>
2
+
3
+
4
+struct pointer_32_t
5
+{
6
+   void  *pointers[ 32];
7
+};
8
+
9
+
10
+static size_t   count( struct pointer_32_t *array)
11
+{
12
+   mulle_vararg_list   list;
13
+   size_t              n;
14
+
15
+   mulle_vararg_start( list, array->pointers[ 0]);
16
+
17
+   n = mulle_vararg_count_pointers( list, array->pointers[ 0]);
18
+
19
+   mulle_vararg_end( list);
20
+   return( n);
21
+}
22
+
23
+
24
+int main()
25
+{
26
+   struct pointer_32_t   array = { (void *) 0x1848, (void *) 0x1849, NULL };
27
+
28
+   printf( "%ld\n", (long) count( &array));
29
+   return( 0);
30
+}
0 31
new file mode 100644
... ...
@@ -0,0 +1 @@
0
+2