src/mulle_vararg.h
9d2b30f8
 //
 //  mulle_vararg.h
 //  mulle-objc-runtime
 //
 //  Created by Nat! on 29.10.15.
 //  Copyright © 2015 Mulle kybernetiK. All rights reserved.
 //
 
 #ifndef mulle_vararg_h__
 #define mulle_vararg_h__
 
 #include "mulle_align.h"
 
7cca94f9
 #define MULLE_VARARG_VERSION  ((0 << 20) | (5 << 8) | 3)
9d2b30f8
 
 
 /*
  * -print:(NSString *) format, ...
  * [print:@"%d",  0.1]
  *
  * 32 bit:
  * struct vararg
  * {
  *    NSString *X;    // assume .align 2
  *    double    Y;    // assume .align 8
  * }
  *
  * 00: XXXXXXXX
  * 04: 00000000
  * 08: YYYYYYYY
  * 0A: YYYYYYYY
  *
  * -addIfTrue:(BOOL) flag a:(float) a, ...
  * [addIfTrue:YES a:0.2, 0.3]
  *
  * 32 bit:
  * struct vararg
  * {
  *    BOOL      X;
  *    float     Y;    // assume .align 4
  *    double    Z;    // assume .align 8
  * }
  *
  * 00: XX000000
  * 04: YYYYYYYY
  * 08: ZZZZZZZZ
  * 0A: ZZZZZZZZ
  */
 typedef struct
 {
    void   *p;
 }  mulle_vararg_list;
 
 
 
 #define mulle_vararg_start( args, ap)          \
 do                                             \
 {                                              \
    args.p = &ap;                               \
    args.p = &((char *) args.p)[ sizeof( ap) < sizeof( int) ? sizeof( int) : sizeof( ap)];  \
 }                                              \
 while( 0)
 
 
 // use this for integer types
7a7a4c0c
 static inline char  *_mulle_vararg_int_aligned_pointer( mulle_vararg_list *args, size_t size, unsigned int align)
 {
    char   *q;
aa271def
 
7a7a4c0c
    if( size < sizeof( int))
    {
       size  = sizeof( int);
56d8fe79
       align = alignof( struct{ int x; });  // weirdness for i386
7a7a4c0c
    }
aa271def
 
6065160a
    q       = mulle_pointer_align( args->p, align);
7a7a4c0c
    args->p = &q[ size];
    return( q);
 }
aa271def
 
7a7a4c0c
 
5ce9d6a3
 #define mulle_vararg_next_integer( args, type)                                                                \
    (sizeof( type) < sizeof( int)                                                                              \
       ? (type) *(int *) _mulle_vararg_int_aligned_pointer( &args, sizeof( type), alignof( struct{ type x; })) \
       : *(type *) _mulle_vararg_int_aligned_pointer( &args, sizeof( type), alignof( struct{ type x; })))
7a7a4c0c
 
 
 static inline char  *_mulle_vararg_aligned_pointer( mulle_vararg_list *args, unsigned int align)
 {
    char   *q;
aa271def
 
6065160a
    q       = mulle_pointer_align( args->p, align);
7a7a4c0c
    args->p = &q[ sizeof( void *)];
    return( q);
 }
9d2b30f8
 
 
6065160a
 // use this for all pointer types
5cc6a810
 #define mulle_vararg_next_pointer( args, type)  \
5ce9d6a3
    (*(type *) _mulle_vararg_aligned_pointer( &args, alignof( struct{ type x; })))
7a7a4c0c
 
9d2b30f8
 
 // use this for all struct types
6065160a
 #define _mulle_vararg_next_struct( args, type)  \
    ((type *) _mulle_vararg_aligned_pointer( &args, alignof( struct{ type x; })))
 
5cc6a810
 #define mulle_vararg_next_struct( args, type)    \
6065160a
    (*_mulle_vararg_next_struct( args, type))
 
 // use this for all union types
 #define _mulle_vararg_next_union( args, type)    \
    ((type *) _mulle_vararg_aligned_pointer( &args, alignof( struct{ type x; })))
 
 #define mulle_vararg_next_union( args, type)    \
    (*_mulle_vararg_next_union( args, type))
7a7a4c0c
 
 
 static inline char  *_mulle_vararg_double_aligned_pointer( mulle_vararg_list *args, size_t size, unsigned int align)
 {
    char   *q;
aa271def
 
7a7a4c0c
    if( size < sizeof( double))
    {
       size  = sizeof( double);
56d8fe79
       align = alignof( struct{ double x; });  // weirdness for i386
7a7a4c0c
    }
aa271def
 
6065160a
    q       = mulle_pointer_align( args->p, align);
7a7a4c0c
    args->p = &q[ size];
    return( q);
 }
9d2b30f8
 
 
 // need separate routine for FP arguments, as float promotes to double
5ce9d6a3
 #define mulle_vararg_next_fp( args, type)                                                                           \
    (sizeof( type) < sizeof( double)                                                                                 \
       ? (type) *(double *) _mulle_vararg_double_aligned_pointer( &args, sizeof( type), alignof( struct{ type x; })) \
       : *(type *) _mulle_vararg_double_aligned_pointer( &args, sizeof( type), alignof( struct{ type x; })))
7a7a4c0c
 
 
6065160a
 #define mulle_vararg_copy( dst, src)  \
 do                                    \
 {                                     \
    dst = src;                         \
 }                                     \
9d2b30f8
 while( 0)
 
 #define mulle_vararg_end( args)
 
 
6065160a
 // only works with pointers
9d2b30f8
 
6065160a
 static inline size_t   mulle_vararg_count_pointers( mulle_vararg_list args, void *first)
9d2b30f8
 {
    size_t   count;
    void     *p;
 
    count = 0;
6065160a
    p     = first;
9d2b30f8
    while( p)
    {
       ++count;
       p = mulle_vararg_next_pointer( args, void *);
    }
aa271def
 
9d2b30f8
    return( count);
 }
aa271def
 
6065160a
 
9d2b30f8
 #endif /* mulle_vararg_h */