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