Changes in / [70969f8:9d6f011]


Ignore:
Location:
doc/papers/general
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • doc/papers/general/Paper.tex

    r70969f8 r9d6f011  
    553553struct litres {};
    554554
    555 forall( dtype U) scalar(U) ?+?( scalar(U) a, scalar(U) b ) {
     555forall( dtype U ) scalar(U) ?+?( scalar(U) a, scalar(U) b ) {
    556556        return (scalar(U)){ a.value + b.value };
    557557}
     
    25662566In fact, \CFA's features for generic programming can enable faster runtime execution than idiomatic @void *@-based C code.
    25672567This claim is demonstrated through a set of generic-code-based micro-benchmarks in C, \CFA, and \CC (see stack implementations in Appendix~\ref{sec:BenchmarkStackImplementation}).
    2568 Since all these languages share a subset essentially comprising standard C, maximal-performance benchmarks would show little runtime variance, other than in length and clarity of source code.
     2568Since all these languages share a subset essentially comprising standard C, maximal-performance benchmarks would show little runtime variance, differing only in length and clarity of source code.
    25692569A more illustrative benchmark measures the costs of idiomatic usage of each language's features.
    2570 Figure~\ref{fig:BenchmarkTest} shows the \CFA benchmark tests for a generic stack based on a singly linked-list, a generic pair-data-structure, and a variadic @print@ function similar to that in Section~\ref{sec:variadic-tuples}.
     2570Figure~\ref{fig:BenchmarkTest} shows the \CFA benchmark tests for a generic stack based on a singly linked-list.
    25712571The benchmark test is similar for C and \CC.
    2572 The experiment uses element types @int@ and @pair(_Bool, char)@, and pushes $N=40M$ elements on a generic stack, copies the stack, clears one of the stacks, finds the maximum value in the other stack, and prints $N/2$ (to reduce graph height) constants.
     2572The experiment uses element types @int@ and @pair(short, char)@, and pushes $N=40M$ elements on a generic stack, copies the stack, clears one of the stacks, and finds the maximum value in the other stack.
    25732573
    25742574\begin{figure}
    25752575\begin{cfa}[xleftmargin=3\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2576 int main( int argc, char * argv[] ) {
     2576int main() {
    25772577        int max = 0, val = 42;
    25782578        stack( int ) si, ti;
    25792579
    25802580        REPEAT_TIMED( "push_int", N, push( si, val ); )
    2581         TIMED( "copy_int", ti = si; )
     2581        TIMED( "copy_int", ti{ si }; )
    25822582        TIMED( "clear_int", clear( si ); )
    25832583        REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; )
    25842584
    2585         pair( _Bool, char ) max = { (_Bool)0, '\0' }, val = { (_Bool)1, 'a' };
    2586         stack( pair( _Bool, char ) ) sp, tp;
     2585        pair( short, char ) max = { 0h, '\0' }, val = { 42h, 'a' };
     2586        stack( pair( short, char ) ) sp, tp;
    25872587
    25882588        REPEAT_TIMED( "push_pair", N, push( sp, val ); )
    2589         TIMED( "copy_pair", tp = sp; )
     2589        TIMED( "copy_pair", tp{ sp }; )
    25902590        TIMED( "clear_pair", clear( sp ); )
    2591         REPEAT_TIMED( "pop_pair", N, pair(_Bool, char) x = pop( tp ); if ( x > max ) max = x; )
     2591        REPEAT_TIMED( "pop_pair", N, pair(short, char) x = pop( tp ); if ( x > max ) max = x; )
    25922592}
    25932593\end{cfa}
     
    26002600hence runtime checks are necessary to safely down-cast objects.
    26012601The most notable difference among the implementations is in memory layout of generic types: \CFA and \CC inline the stack and pair elements into corresponding list and pair nodes, while C and \CCV lack such a capability and instead must store generic objects via pointers to separately-allocated objects.
    2602 For the print benchmark, idiomatic printing is used: the C and \CFA variants used @stdio.h@, while the \CC and \CCV variants used @iostream@; preliminary tests show this distinction has negligible runtime impact.
    2603 Note, the C benchmark uses unchecked casts as there is no runtime mechanism to perform such checks, while \CFA and \CC provide type-safety statically.
     2602Note that the C benchmark uses unchecked casts as there is no runtime mechanism to perform such checks, while \CFA and \CC provide type-safety statically.
    26042603
    26052604Figure~\ref{fig:eval} and Table~\ref{tab:eval} show the results of running the benchmark in Figure~\ref{fig:BenchmarkTest} and its C, \CC, and \CCV equivalents.
    26062605The graph plots the median of 5 consecutive runs of each program, with an initial warm-up run omitted.
    2607 All code is compiled at \texttt{-O2} by gcc or g++ 6.2.0, with all \CC code compiled as \CCfourteen.
     2606All code is compiled at \texttt{-O2} by gcc or g++ 6.3.0, with all \CC code compiled as \CCfourteen.
    26082607The benchmarks are run on an Ubuntu 16.04 workstation with 16 GB of RAM and a 6-core AMD FX-6300 CPU with 3.5 GHz maximum clock frequency.
    26092608
     
    26232622                                                                        & \CT{C}        & \CT{\CFA}     & \CT{\CC}      & \CT{\CCV}             \\ \hline
    26242623maximum memory usage (MB)                       & 10001         & 2502          & 2503          & 11253                 \\
    2625 source code size (lines)                        & 247           & 222           & 165           & 339                   \\
    2626 redundant type annotations (lines)      & 39            & 2                     & 2                     & 15                    \\
    2627 binary size (KB)                                        & 14            & 229           & 18            & 38                    \\
     2624source code size (lines)                        & 187           & 186           & 133           & 303                   \\
     2625redundant type annotations (lines)      & 25            & 0                     & 2                     & 16                    \\
     2626binary size (KB)                                        & 14            & 257           & 14            & 37                    \\
    26282627\end{tabular}
    26292628\end{table}
    26302629
    26312630The C and \CCV variants are generally the slowest with the largest memory footprint, because of their less-efficient memory layout and the pointer-indirection necessary to implement generic types;
    2632 this inefficiency is exacerbated by the second level of generic types in the pair-based benchmarks.
    2633 By contrast, the \CFA and \CC variants run in roughly equivalent time for both the integer and pair of @_Bool@ and @char@ because the storage layout is equivalent, with the inlined libraries (\ie no separate compilation) and greater maturity of the \CC compiler contributing to its lead.
     2631this inefficiency is exacerbated by the second level of generic types in the pair benchmarks.
     2632By contrast, the \CFA and \CC variants run in roughly equivalent time for both the integer and pair of @short@ and @char@ because the storage layout is equivalent, with the inlined libraries (\ie no separate compilation) and greater maturity of the \CC compiler contributing to its lead.
    26342633\CCV is slower than C largely due to the cost of runtime type-checking of down-casts (implemented with @dynamic_cast@);
    2635 There are two outliers in the graph for \CFA: all prints and pop of @pair@.
    2636 Both of these cases result from the complexity of the C-generated polymorphic code, so that the gcc compiler is unable to optimize some dead code and condense nested calls.
    2637 A compiler designed for \CFA could easily perform these optimizations.
     2634The outlier in the graph for \CFA, pop @pair@, results from the complexity of the generated-C polymorphic code.
     2635The gcc compiler is unable to optimize some dead code and condense nested calls; a compiler designed for \CFA could easily perform these optimizations.
    26382636Finally, the binary size for \CFA is larger because of static linking with the \CFA libraries.
    26392637
    2640 \CFA is also competitive in terms of source code size, measured as a proxy for programmer effort. The line counts in Table~\ref{tab:eval} include implementations of @pair@ and @stack@ types for all four languages for purposes of direct comparison, though it should be noted that \CFA and \CC have pre-written data structures in their standard libraries that programmers would generally use instead. Use of these standard library types has minimal impact on the performance benchmarks, but shrinks the \CFA and \CC benchmarks to 73 and 54 lines, respectively.
     2638\CFA is also competitive in terms of source code size, measured as a proxy for programmer effort. The line counts in Table~\ref{tab:eval} include implementations of @pair@ and @stack@ types for all four languages for purposes of direct comparison, though it should be noted that \CFA and \CC have pre-written data structures in their standard libraries that programmers would generally use instead. Use of these standard library types has minimal impact on the performance benchmarks, but shrinks the \CFA and \CC benchmarks to 39 and 42 lines, respectively.
    26412639On the other hand, C does not have a generic collections-library in its standard distribution, resulting in frequent reimplementation of such collection types by C programmers.
    2642 \CCV does not use the \CC standard template library by construction, and in fact includes the definition of @object@ and wrapper classes for @bool@, @char@, @int@, and @const char *@ in its line count, which inflates this count somewhat, as an actual object-oriented language would include these in the standard library;
     2640\CCV does not use the \CC standard template library by construction, and in fact includes the definition of @object@ and wrapper classes for @char@, @short@, and @int@ in its line count, which inflates this count somewhat, as an actual object-oriented language would include these in the standard library;
    26432641with their omission, the \CCV line count is similar to C.
    26442642We justify the given line count by noting that many object-oriented languages do not allow implementing new interfaces on library types without subclassing or wrapper types, which may be similarly verbose.
     
    26462644Raw line-count, however, is a fairly rough measure of code complexity;
    26472645another important factor is how much type information the programmer must manually specify, especially where that information is not checked by the compiler.
    2648 Such unchecked type information produces a heavier documentation burden and increased potential for runtime bugs, and is much less common in \CFA than C, with its manually specified function pointers arguments and format codes, or \CCV, with its extensive use of un-type-checked downcasts (\eg @object@ to @integer@ when popping a stack, or @object@ to @printable@ when printing the elements of a @pair@).
     2646Such unchecked type information produces a heavier documentation burden and increased potential for runtime bugs, and is much less common in \CFA than C, with its manually specified function pointer arguments and format codes, or \CCV, with its extensive use of un-type-checked downcasts (\eg @object@ to @integer@ when popping a stack, or @object@ to @printable@ when printing the elements of a @pair@).
    26492647To quantify this, the ``redundant type annotations'' line in Table~\ref{tab:eval} counts the number of lines on which the type of a known variable is re-specified, either as a format specifier, explicit downcast, type-specific function, or by name in a @sizeof@, struct literal, or @new@ expression.
    26502648The \CC benchmark uses two redundant type annotations to create a new stack nodes, while the C and \CCV benchmarks have several such annotations spread throughout their code.
    2651 The two instances in which the \CFA benchmark still uses redundant type specifiers are to cast the result of a polymorphic @malloc@ call (the @sizeof@ argument is inferred by the compiler).
    2652 These uses are similar to the @new@ expressions in \CC, though the \CFA compiler's type resolver should shortly render even these type casts superfluous.
    2653 
     2649The \CFA benchmark was able to eliminate all redundant type annotations through use of the polymorphic @alloc@ function discussed in Section~\ref{sec:libraries}.
    26542650
    26552651\section{Related Work}
    2656 
    26572652
    26582653\subsection{Polymorphism}
     
    27352730user defined: D, Objective-C
    27362731
    2737 
    27382732\section{Conclusion and Future Work}
    27392733
     
    27832777\CFA
    27842778\begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2785 forall( otype T ) struct stack_node;
    2786 forall( otype T ) struct stack {
    2787         stack_node(T) * head;
    2788 };
    27892779forall( otype T ) struct stack_node {
    27902780        T value;
    27912781        stack_node(T) * next;
    27922782};
    2793 forall( otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
    2794 forall( otype T) void ?{}( stack(T) & s, stack(T) t ) {
     2783forall( otype T ) struct stack { stack_node(T) * head; };
     2784forall( otype T ) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
     2785forall( otype T ) void ?{}( stack(T) & s, stack(T) t ) {
    27952786        stack_node(T) ** crnt = &s.head;
    27962787        for ( stack_node(T) * next = t.head; next; next = next->next ) {
    2797                 stack_node(T) * new_node = ((stack_node(T)*)malloc());
    2798                 (*new_node){ next->value }; /***/
    2799                 *crnt = new_node;
    2800                 stack_node(T) * acrnt = *crnt;
    2801                 crnt = &acrnt->next;
     2788                *crnt = alloc();
     2789                ((*crnt)->value){ next->value };
     2790                crnt = &(*crnt)->next;
    28022791        }
    28032792        *crnt = 0;
     
    28112800forall( otype T ) void ^?{}( stack(T) & s) { clear( s ); }
    28122801forall( otype T ) _Bool empty( const stack(T) & s ) { return s.head == 0; }
    2813 forall( otype T ) void push( stack(T) & s, T value ) {
    2814         stack_node(T) * new_node = ((stack_node(T)*)malloc());
    2815         (*new_node){ value, s.head }; /***/
    2816         s.head = new_node;
    2817 }
    2818 forall( otype T ) T pop( stack(T) & s ) {
    2819         stack_node(T) * n = s.head;
    2820         s.head = n->next;
    2821         T v = n->value;
    2822         delete( n );
    2823         return v;
    2824 }
    2825 forall( otype T ) void clear( stack(T) & s ) {
    2826         for ( stack_node(T) * next = s.head; next; ) {
     2802forall( otype T ) void push( stack(T) & s, T value ) with( s ) {
     2803        stack_node(T) * n = alloc();
     2804        (*n){ value, head };
     2805        head = n;
     2806}
     2807forall( otype T ) T pop( stack(T) & s ) with( s ) {
     2808        stack_node(T) * n = head;
     2809        head = n->next;
     2810        T x = n->value;
     2811        ^(*n){};
     2812        free( n );
     2813        return x;
     2814}
     2815forall( otype T ) void clear( stack(T) & s ) with( s ) {
     2816        for ( stack_node(T) * next = head; next; ) {
    28272817                stack_node(T) * crnt = next;
    28282818                next = crnt->next;
    2829                 delete( crnt );
     2819                ^(*crnt){};
     2820                free(crnt);
    28302821        }
    2831         s.head = 0;
     2822        head = 0;
    28322823}
    28332824\end{cfa}
     
    28362827\CC
    28372828\begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2838 template<typename T> class stack {
     2829template<typename T> struct stack {
    28392830        struct node {
    28402831                T value;
     
    28432834        };
    28442835        node * head;
    2845         void copy(const stack<T>& o) {
     2836        void copy(const stack<T> & o) {
    28462837                node ** crnt = &head;
    28472838                for ( node * next = o.head;; next; next = next->next ) {
     
    28512842                *crnt = nullptr;
    28522843        }
    2853   public:
    28542844        stack() : head(nullptr) {}
    2855         stack(const stack<T>& o) { copy(o); }
     2845        stack(const stack<T> & o) { copy(o); }
    28562846        stack(stack<T> && o) : head(o.head) { o.head = nullptr; }
    28572847        ~stack() { clear(); }
    2858         stack & operator= (const stack<T>& o) {
     2848        stack & operator= (const stack<T> & o) {
    28592849                if ( this == &o ) return *this;
    28602850                clear();
     
    28952885        struct stack_node * next;
    28962886};
     2887struct stack { struct stack_node* head; };
    28972888struct stack new_stack() { return (struct stack){ NULL }; /***/ }
    28982889void copy_stack(struct stack * s, const struct stack * t, void * (*copy)(const void *)) {
     
    29002891        for ( struct stack_node * next = t->head; next; next = next->next ) {
    29012892                *crnt = malloc(sizeof(struct stack_node)); /***/
    2902                 **crnt = (struct stack_node){ copy(next->value) }; /***/
     2893                (*crnt)->value = copy(next->value);
    29032894                crnt = &(*crnt)->next;
    29042895        }
    2905         *crnt = 0;
     2896        *crnt = NULL;
    29062897}
    29072898_Bool stack_empty(const struct stack * s) { return s->head == NULL; }
     
    29322923\CCV
    29332924\begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2934 stack::node::node( const object & v, node * n ) : value( v.new_copy() ), next( n ) {}
    2935 void stack::copy(const stack & o) {
    2936         node ** crnt = &head;
    2937         for ( node * next = o.head; next; next = next->next ) {
    2938                 *crnt = new node{ *next->value };
    2939                 crnt = &(*crnt)->next;
     2925struct stack {
     2926        struct node {
     2927                ptr<object> value;
     2928                node* next;
     2929                node( const object & v, node * n ) : value( v.new_copy() ), next( n ) {}
     2930        };
     2931        node* head;
     2932        void copy(const stack & o) {
     2933                node ** crnt = &head;
     2934                for ( node * next = o.head; next; next = next->next ) {
     2935                        *crnt = new node{ *next->value }; /***/
     2936                        crnt = &(*crnt)->next;
     2937                }
     2938                *crnt = nullptr;
    29402939        }
    2941         *crnt = nullptr;
    2942 }
    2943 stack::stack() : head(nullptr) {}
    2944 stack::stack(const stack & o) { copy(o); }
    2945 stack::stack(stack && o) : head(o.head) { o.head = nullptr; }
    2946 stack::~stack() { clear(); }
    2947 stack & stack::operator= (const stack & o) {
    2948         if ( this == &o ) return *this;
    2949         clear();
    2950         copy(o);
    2951         return *this;
    2952 }
    2953 stack & stack::operator= (stack && o) {
    2954         if ( this == &o ) return *this;
    2955         head = o.head;
    2956         o.head = nullptr;
    2957         return *this;
    2958 }
    2959 bool stack::empty() const { return head == nullptr; }
    2960 void stack::push(const object & value) { head = new node{ value, head }; /***/ }
    2961 ptr<object> stack::pop() {
    2962         node * n = head;
    2963         head = n->next;
    2964         ptr<object> x = std::move(n->value);
    2965         delete n;
    2966         return x;
    2967 }
    2968 void stack::clear() {
    2969         for ( node * next = head; next; ) {
    2970                 node * crnt = next;
    2971                 next = crnt->next;
    2972                 delete crnt;
     2940        stack() : head(nullptr) {}
     2941        stack(const stack & o) { copy(o); }
     2942        stack(stack && o) : head(o.head) { o.head = nullptr; }
     2943        ~stack() { clear(); }
     2944        stack & operator= (const stack & o) {
     2945                if ( this == &o ) return *this;
     2946                clear();
     2947                copy(o);
     2948                return *this;
    29732949        }
    2974         head = nullptr;
    2975 }
     2950        stack & operator= (stack && o) {
     2951                if ( this == &o ) return *this;
     2952                head = o.head;
     2953                o.head = nullptr;
     2954                return *this;
     2955        }
     2956        bool empty() const { return head == nullptr; }
     2957        void push(const object & value) { head = new node{ value, head }; /***/ }
     2958        ptr<object> pop() {
     2959                node * n = head;
     2960                head = n->next;
     2961                ptr<object> x = std::move(n->value);
     2962                delete n;
     2963                return x;
     2964        }
     2965        void clear() {
     2966                for ( node * next = head; next; ) {
     2967                        node * crnt = next;
     2968                        next = crnt->next;
     2969                        delete crnt;
     2970                }
     2971                head = nullptr;
     2972        }
     2973};
    29762974\end{cfa}
    29772975
  • doc/papers/general/evaluation/c-bench.c

    r70969f8 r9d6f011  
    55#include "c-stack.h"
    66
    7 _Bool* new_bool( _Bool b ) {
    8         _Bool* q = malloc(sizeof(_Bool)); /***/
    9         *q = b;
     7char* new_char( char c ) {
     8        char* q = malloc(sizeof(char)); /***/
     9        *q = c;
    1010        return q;
    1111}
    1212
    13 char* new_char( char c ) {
    14         char* q = malloc(sizeof(char)); /***/
    15         *q = c;
     13short* new_short( short s ) {
     14        short* q = malloc(sizeof(short)); /***/
     15        *q = s;
    1616        return q;
    1717}
     
    2323}
    2424
    25 void* copy_bool( const void* p ) { return new_bool( *(const _Bool*)p ); } /***/
    2625void* copy_char( const void* p ) { return new_char( *(const char*)p ); } /***/
     26void* copy_short( const void* p ) { return new_short( *(const short*)p ); } /***/
    2727void* copy_int( const void* p ) { return new_int( *(const int*)p ); } /***/
    28 void* copy_pair_bool_char( const void* p ) { return copy_pair( p, copy_bool, copy_char ); } /***/
    29 void free_pair_bool_char( void* p ) { free_pair( p, free, free ); } /***/
    30 
    31 int cmp_bool( const void* a, const void* b ) { /***/
    32         return *(const _Bool*)a == *(const _Bool*)b ? 0 : *(const _Bool*)a < *(const _Bool*)b ? -1 : 1;
    33 }
     28void* copy_pair_short_char( const void* p ) { return copy_pair( p, copy_short, copy_char ); } /***/
     29void free_pair_short_char( void* p ) { free_pair( p, free, free ); } /***/
    3430
    3531int cmp_char( const void* a, const void* b ) { /***/
    3632        return *(const char*)a == *(const char*)b ? 0 : *(const char*)a < *(const char*)b ? -1 : 1;
     33}
     34
     35int cmp_short( const void* a, const void* b ) { /***/
     36        return *(const short*)a == *(const short*)b ? 0 : *(const short*)a < *(const short*)b ? -1 : 1;
    3737}
    3838
     
    4949                free(xi); )
    5050
    51         struct pair * maxp = new_pair( new_bool(0), new_char('\0') ),
    52                 * valp = new_pair( new_bool(1), new_char('a') );
     51        struct pair * maxp = new_pair( new_short(0), new_char('\0') ),
     52                * valp = new_pair( new_short(42), new_char('a') );
    5353        struct stack sp = new_stack(), tp;
    5454
    55         REPEAT_TIMED( "push_pair", N, push_stack( &sp, copy_pair_bool_char( valp ) ); )
    56         TIMED( "copy_pair", copy_stack( &tp, &sp, copy_pair_bool_char ); /***/ )
    57         TIMED( "clear_pair", clear_stack( &sp, free_pair_bool_char ); /***/ )
     55        REPEAT_TIMED( "push_pair", N, push_stack( &sp, copy_pair_short_char( valp ) ); )
     56        TIMED( "copy_pair", copy_stack( &tp, &sp, copy_pair_short_char ); /***/ )
     57        TIMED( "clear_pair", clear_stack( &sp, free_pair_short_char ); /***/ )
    5858        REPEAT_TIMED( "pop_pair", N,
    5959                struct pair * xp = pop_stack( &tp );
    60                 if ( cmp_pair( xp, maxp, cmp_bool, cmp_char /***/ ) > 0 ) {
    61                         free_pair_bool_char( maxp ); /***/
     60                if ( cmp_pair( xp, maxp, cmp_short, cmp_char /***/ ) > 0 ) {
     61                        free_pair_short_char( maxp ); /***/
    6262                        maxp = xp;
    6363                } else {
    64                         free_pair_bool_char( xp ); /***/
     64                        free_pair_short_char( xp ); /***/
    6565                } )
    66         free_pair_bool_char( maxp ); /***/
    67         free_pair_bool_char( valp ); /***/
     66        free_pair_short_char( maxp ); /***/
     67        free_pair_short_char( valp ); /***/
    6868}
  • doc/papers/general/evaluation/c-stack.c

    r70969f8 r9d6f011  
    1313        for ( struct stack_node* next = t->head; next; next = next->next ) {
    1414                *crnt = malloc(sizeof(struct stack_node)); /***/
    15                 **crnt = (struct stack_node){ copy(next->value) }; /***/
     15                (*crnt)->value = copy(next->value);
    1616                crnt = &(*crnt)->next;
    1717        }
    18         *crnt = 0;
     18        *crnt = NULL;
    1919}
    2020
  • doc/papers/general/evaluation/cfa-bench.c

    r70969f8 r9d6f011  
    33#include "cfa-pair.h"
    44
    5 int main( int argc, char * argv[] ) {
     5int main() {
    66        int max = 0, val = 42;
    77        stack( int ) si, ti;
    88
    99        REPEAT_TIMED( "push_int", N, push( si, val ); )
    10         TIMED( "copy_int", ti = si; )
     10        TIMED( "copy_int", ti{ si }; )
    1111        TIMED( "clear_int", clear( si ); )
    12         REPEAT_TIMED( "pop_int", N,
    13                 int x = pop( ti ); if ( x > max ) max = x; )
     12        REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; )
    1413
    15         pair( _Bool, char ) max = { (_Bool)0 /***/, '\0' }, val = { (_Bool)1 /***/, 'a' };
    16         stack( pair( _Bool, char ) ) sp, tp;
     14        pair( short, char ) max = { 0h, '\0' }, val = { 42h, 'a' };
     15        stack( pair( short, char ) ) sp, tp;
    1716
    1817        REPEAT_TIMED( "push_pair", N, push( sp, val ); )
    19         TIMED( "copy_pair", tp = sp; )
     18        TIMED( "copy_pair", tp{ sp }; )
    2019        TIMED( "clear_pair", clear( sp ); )
    21         REPEAT_TIMED( "pop_pair", N,
    22                 pair(_Bool, char) x = pop( tp ); if ( x > max ) max = x; )
     20        REPEAT_TIMED( "pop_pair", N, pair(short, char) x = pop( tp ); if ( x > max ) max = x; )
    2321}
  • doc/papers/general/evaluation/cfa-stack.c

    r70969f8 r9d6f011  
    1212        stack_node(T) ** crnt = &s.head;
    1313        for ( stack_node(T) * next = t.head; next; next = next->next ) {
    14                 stack_node(T)* new_node = (stack_node(T)*)malloc(); /***/
    15                 (*new_node){ next->value };
    16                 *crnt = new_node;
     14                *crnt = alloc();
     15                ((*crnt)->value){ next->value };
    1716                crnt = &(*crnt)->next;
    1817        }
     
    3130forall(otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; }
    3231
    33 forall(otype T) void push( stack(T) & s, T value ) {
    34         stack_node(T)* new_node = (stack_node(T)*)malloc(); /***/
    35         (*new_node){ value, s.head };
    36         s.head = new_node;
     32forall(otype T) void push( stack(T) & s, T value ) with( s ) {
     33        stack_node(T)* n = alloc();
     34        (*n){ value, head };
     35        head = n;
    3736}
    3837
    39 forall(otype T) T pop( stack(T) & s ) {
    40         stack_node(T) * n = s.head;
    41         s.head = n->next;
    42         T v = n->value;
     38forall(otype T) T pop( stack(T) & s ) with( s ) {
     39        stack_node(T) * n = head;
     40        head = n->next;
     41        T x = n->value;
    4342        ^(*n){};
    4443        free( n );
    45         return v;
     44        return x;
    4645}
    4746
    48 forall(otype T) void clear( stack(T) & s ) {
    49         for ( stack_node(T) * next = s.head; next; ) {
     47forall(otype T) void clear( stack(T) & s ) with( s ) {
     48        for ( stack_node(T) * next = head; next; ) {
    5049                stack_node(T) * crnt = next;
    5150                next = crnt->next;
     
    5352                free(crnt);
    5453        }
    55         s.head = 0;
     54        head = 0;
    5655}
  • doc/papers/general/evaluation/cpp-bench.cpp

    r70969f8 r9d6f011  
    1313        REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop() ); )
    1414
    15         pair<bool, char> maxp = { false, '\0' }, valp = { true, 'a' };
    16         stack<pair<bool, char>> sp, tp;
     15        pair<short, char> maxp = { 0, '\0' }, valp = { 42, 'a' };
     16        stack<pair<short, char>> sp, tp;
    1717       
    1818        REPEAT_TIMED( "push_pair", N, sp.push( valp ); )
  • doc/papers/general/evaluation/cpp-vbench.cpp

    r70969f8 r9d6f011  
    1313        REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop()->as<integer>() ); /***/ )
    1414
    15         ptr<pair> maxp = make<pair>( make<boolean>(false), make<character>('\0') );
    16         pair valp{ make<boolean>(true), make<character>('a') };
     15        ptr<pair> maxp = make<pair>( make<short_integer>(0), make<character>('\0') );
     16        pair valp{ make<short_integer>(42), make<character>('a') };
    1717        stack sp, tp;
    1818       
  • doc/papers/general/evaluation/cpp-vstack.cpp

    r70969f8 r9d6f011  
    77        node** crnt = &head;
    88        for ( node* next = o.head; next; next = next->next ) {
    9                 *crnt = new node{ *next->value };
     9                *crnt = new node{ *next->value }; /***/
    1010                crnt = &(*crnt)->next;
    1111        }
  • doc/papers/general/evaluation/object.hpp

    r70969f8 r9d6f011  
    6767};
    6868
    69 class boolean : public ordered, public printable {
    70         bool x;
    71 public:
    72         boolean() = default;
    73         boolean(bool x) : x(x) {}
    74         boolean(const boolean&) = default;
    75         boolean(boolean&&) = default;
    76         ptr<object> new_inst() const override { return make<boolean>(); }
    77         ptr<object> new_copy() const override { return make<boolean>(*this); }
    78         boolean& operator= (const boolean& that) {
    79                 x = that.x;
    80                 return *this;   
    81         }
    82         object& operator= (const object& that) override { return *this = that.as<boolean>(); } /***/
    83         boolean& operator= (boolean&&) = default;
    84         ~boolean() override = default;
    85 
    86         int cmp(const boolean& that) const { return x == that.x ? 0 : x == false ? -1 : 1; }
    87         int cmp(const ordered& that) const override { return cmp( that.as<boolean>() ); } /***/
    88 
    89         void print(std::ostream& out) const override { out << (x ? "true" : "false"); }
    90 };
    91 
    9269class character : public ordered, public printable {
    9370        char x;
     
    11693};
    11794
     95class short_integer : public ordered, public printable {
     96        short x;
     97public:
     98        short_integer() = default;
     99        short_integer(short x) : x(x) {}
     100        short_integer(const short_integer&) = default;
     101        short_integer(short_integer&&) = default;
     102        ptr<object> new_inst() const override { return make<short_integer>(); }
     103        ptr<object> new_copy() const override { return make<short_integer>(*this); }
     104        short_integer& operator= (const short_integer& that) {
     105                x = that.x;
     106                return *this;   
     107        }
     108        object& operator= (const object& that) override { return *this = that.as<short_integer>(); } /***/
     109        short_integer& operator= (short_integer&&) = default;
     110        ~short_integer() override = default;
     111
     112        int cmp(const short_integer& that) const { return x == that.x ? 0 : x < that.x ? -1 : 1; }
     113        int cmp(const ordered& that) const override { return cmp( that.as<short_integer>() ); } /***/
     114
     115        void print(std::ostream& out) const override { out << x; }
     116};
     117
    118118class integer : public ordered, public printable {
    119119        int x;
     
    137137
    138138        void print(std::ostream& out) const override { out << x; }
    139 };
    140 
    141 class c_string : public printable {
    142         static constexpr const char* empty = "";
    143         const char* s;
    144 public:
    145         c_string() : s(empty) {}
    146         c_string(const char* s) : s(s) {}
    147         c_string(const c_string&) = default;
    148         c_string(c_string&&) = default;
    149         ptr<object> new_inst() const override { return make<c_string>(); }
    150         ptr<object> new_copy() const override { return make<c_string>(s); }
    151         c_string& operator= (const c_string& that) {
    152                 s = that.s;
    153                 return *this;
    154         }
    155         object& operator= (const object& that) override { return *this = that.as<c_string>(); } /***/
    156         c_string& operator= (c_string&&) = default;
    157         ~c_string() override = default;
    158 
    159         void print(std::ostream& out) const override { out << s; }
    160139};
    161140
     
    188167                return y->as<ordered>().cmp( that.y->as<ordered>() ); /***/
    189168        }
    190         int cmp(const ordered& that) const override { return cmp( that.as<pair>() ); }
     169        int cmp(const ordered& that) const override { return cmp( that.as<pair>() ); } /***/
    191170
    192171        void print(std::ostream& out) const override {
  • doc/papers/general/evaluation/timing.dat

    r70969f8 r9d6f011  
    11"400 million repetitions"       "C"     "\\CFA{}"       "\\CC{}"        "\\CC{obj}"
    2 "push\nint"     2976    2225    1522    3266
    3 "copy\nnt"      2932    7072    1526    3110
    4 "clear\nint"    1380    731     750     1488
    5 "pop\nint"      1444    1196    756     5156
    6 "push\npair"    3695    2257    953     6840
    7 "copy\npair"    6034    6650    994     7224
    8 "clear\npair"   2832    848     742     3297
    9 "pop\npair"     3009    5348    797     25235
    10 
     2"push\nint"     3002    2459    1520    3305
     3"copy\nint"     2985    2057    1521    3152
     4"clear\nint"    1374    827     718     1469
     5"pop\nint"      1416    1221    717     5467
     6"push\npair"    4214    2752    946     6826
     7"copy\npair"    6127    2105    993     7330
     8"clear\npair"   2881    885     711     3564
     9"pop\npair"     3046    5434    783     26538
Note: See TracChangeset for help on using the changeset viewer.