Changes in / [9d6f011:70969f8]


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

Legend:

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

    r9d6f011 r70969f8  
    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, differing only 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, other than 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.
     2570Figure~\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}.
    25712571The benchmark test is similar for C and \CC.
    2572 The 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.
     2572The 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.
    25732573
    25742574\begin{figure}
    25752575\begin{cfa}[xleftmargin=3\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2576 int main() {
     2576int main( int argc, char * argv[] ) {
    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( short, char ) max = { 0h, '\0' }, val = { 42h, 'a' };
    2586         stack( pair( short, char ) ) sp, tp;
     2585        pair( _Bool, char ) max = { (_Bool)0, '\0' }, val = { (_Bool)1, 'a' };
     2586        stack( pair( _Bool, 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(short, char) x = pop( tp ); if ( x > max ) max = x; )
     2591        REPEAT_TIMED( "pop_pair", N, pair(_Bool, 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 Note 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.
     2602For 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.
     2603Note, the C benchmark uses unchecked casts as there is no runtime mechanism to perform such checks, while \CFA and \CC provide type-safety statically.
    26032604
    26042605Figure~\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.
    26052606The graph plots the median of 5 consecutive runs of each program, with an initial warm-up run omitted.
    2606 All code is compiled at \texttt{-O2} by gcc or g++ 6.3.0, with all \CC code compiled as \CCfourteen.
     2607All code is compiled at \texttt{-O2} by gcc or g++ 6.2.0, with all \CC code compiled as \CCfourteen.
    26072608The 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.
    26082609
     
    26222623                                                                        & \CT{C}        & \CT{\CFA}     & \CT{\CC}      & \CT{\CCV}             \\ \hline
    26232624maximum memory usage (MB)                       & 10001         & 2502          & 2503          & 11253                 \\
    2624 source code size (lines)                        & 187           & 186           & 133           & 303                   \\
    2625 redundant type annotations (lines)      & 25            & 0                     & 2                     & 16                    \\
    2626 binary size (KB)                                        & 14            & 257           & 14            & 37                    \\
     2625source code size (lines)                        & 247           & 222           & 165           & 339                   \\
     2626redundant type annotations (lines)      & 39            & 2                     & 2                     & 15                    \\
     2627binary size (KB)                                        & 14            & 229           & 18            & 38                    \\
    26272628\end{tabular}
    26282629\end{table}
    26292630
    26302631The 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;
    2631 this inefficiency is exacerbated by the second level of generic types in the pair benchmarks.
    2632 By 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.
     2632this inefficiency is exacerbated by the second level of generic types in the pair-based benchmarks.
     2633By 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.
    26332634\CCV is slower than C largely due to the cost of runtime type-checking of down-casts (implemented with @dynamic_cast@);
    2634 The outlier in the graph for \CFA, pop @pair@, results from the complexity of the generated-C polymorphic code.
    2635 The gcc compiler is unable to optimize some dead code and condense nested calls; a compiler designed for \CFA could easily perform these optimizations.
     2635There are two outliers in the graph for \CFA: all prints and pop of @pair@.
     2636Both 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.
     2637A compiler designed for \CFA could easily perform these optimizations.
    26362638Finally, the binary size for \CFA is larger because of static linking with the \CFA libraries.
    26372639
    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.
     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.
    26392641On 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.
    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;
     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;
    26412643with their omission, the \CCV line count is similar to C.
    26422644We 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.
     
    26442646Raw line-count, however, is a fairly rough measure of code complexity;
    26452647another important factor is how much type information the programmer must manually specify, especially where that information is not checked by the compiler.
    2646 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 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@).
     2648Such 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@).
    26472649To 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.
    26482650The \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.
    2649 The \CFA benchmark was able to eliminate all redundant type annotations through use of the polymorphic @alloc@ function discussed in Section~\ref{sec:libraries}.
     2651The 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).
     2652These 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
    26502654
    26512655\section{Related Work}
     2656
    26522657
    26532658\subsection{Polymorphism}
     
    27302735user defined: D, Objective-C
    27312736
     2737
    27322738\section{Conclusion and Future Work}
    27332739
     
    27772783\CFA
    27782784\begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt]
     2785forall( otype T ) struct stack_node;
     2786forall( otype T ) struct stack {
     2787        stack_node(T) * head;
     2788};
    27792789forall( otype T ) struct stack_node {
    27802790        T value;
    27812791        stack_node(T) * next;
    27822792};
    2783 forall( otype T ) struct stack { stack_node(T) * head; };
    2784 forall( otype T ) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
    2785 forall( otype T ) void ?{}( stack(T) & s, stack(T) t ) {
     2793forall( otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; }
     2794forall( otype T) void ?{}( stack(T) & s, stack(T) t ) {
    27862795        stack_node(T) ** crnt = &s.head;
    27872796        for ( stack_node(T) * next = t.head; next; next = next->next ) {
    2788                 *crnt = alloc();
    2789                 ((*crnt)->value){ next->value };
    2790                 crnt = &(*crnt)->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;
    27912802        }
    27922803        *crnt = 0;
     
    28002811forall( otype T ) void ^?{}( stack(T) & s) { clear( s ); }
    28012812forall( otype T ) _Bool empty( const stack(T) & s ) { return s.head == 0; }
    2802 forall( 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 }
    2807 forall( 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 }
    2815 forall( otype T ) void clear( stack(T) & s ) with( s ) {
    2816         for ( stack_node(T) * next = head; next; ) {
     2813forall( 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}
     2818forall( 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}
     2825forall( otype T ) void clear( stack(T) & s ) {
     2826        for ( stack_node(T) * next = s.head; next; ) {
    28172827                stack_node(T) * crnt = next;
    28182828                next = crnt->next;
    2819                 ^(*crnt){};
    2820                 free(crnt);
     2829                delete( crnt );
    28212830        }
    2822         head = 0;
     2831        s.head = 0;
    28232832}
    28242833\end{cfa}
     
    28272836\CC
    28282837\begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2829 template<typename T> struct stack {
     2838template<typename T> class stack {
    28302839        struct node {
    28312840                T value;
     
    28342843        };
    28352844        node * head;
    2836         void copy(const stack<T> & o) {
     2845        void copy(const stack<T>& o) {
    28372846                node ** crnt = &head;
    28382847                for ( node * next = o.head;; next; next = next->next ) {
     
    28422851                *crnt = nullptr;
    28432852        }
     2853  public:
    28442854        stack() : head(nullptr) {}
    2845         stack(const stack<T> & o) { copy(o); }
     2855        stack(const stack<T>& o) { copy(o); }
    28462856        stack(stack<T> && o) : head(o.head) { o.head = nullptr; }
    28472857        ~stack() { clear(); }
    2848         stack & operator= (const stack<T> & o) {
     2858        stack & operator= (const stack<T>& o) {
    28492859                if ( this == &o ) return *this;
    28502860                clear();
     
    28852895        struct stack_node * next;
    28862896};
    2887 struct stack { struct stack_node* head; };
    28882897struct stack new_stack() { return (struct stack){ NULL }; /***/ }
    28892898void copy_stack(struct stack * s, const struct stack * t, void * (*copy)(const void *)) {
     
    28912900        for ( struct stack_node * next = t->head; next; next = next->next ) {
    28922901                *crnt = malloc(sizeof(struct stack_node)); /***/
    2893                 (*crnt)->value = copy(next->value);
     2902                **crnt = (struct stack_node){ copy(next->value) }; /***/
    28942903                crnt = &(*crnt)->next;
    28952904        }
    2896         *crnt = NULL;
     2905        *crnt = 0;
    28972906}
    28982907_Bool stack_empty(const struct stack * s) { return s->head == NULL; }
     
    29232932\CCV
    29242933\begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt]
    2925 struct 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;
     2934stack::node::node( const object & v, node * n ) : value( v.new_copy() ), next( n ) {}
     2935void 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;
    29392940        }
    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;
     2941        *crnt = nullptr;
     2942}
     2943stack::stack() : head(nullptr) {}
     2944stack::stack(const stack & o) { copy(o); }
     2945stack::stack(stack && o) : head(o.head) { o.head = nullptr; }
     2946stack::~stack() { clear(); }
     2947stack & stack::operator= (const stack & o) {
     2948        if ( this == &o ) return *this;
     2949        clear();
     2950        copy(o);
     2951        return *this;
     2952}
     2953stack & stack::operator= (stack && o) {
     2954        if ( this == &o ) return *this;
     2955        head = o.head;
     2956        o.head = nullptr;
     2957        return *this;
     2958}
     2959bool stack::empty() const { return head == nullptr; }
     2960void stack::push(const object & value) { head = new node{ value, head }; /***/ }
     2961ptr<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}
     2968void stack::clear() {
     2969        for ( node * next = head; next; ) {
     2970                node * crnt = next;
     2971                next = crnt->next;
     2972                delete crnt;
    29492973        }
    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 };
     2974        head = nullptr;
     2975}
    29742976\end{cfa}
    29752977
  • doc/papers/general/evaluation/c-bench.c

    r9d6f011 r70969f8  
    55#include "c-stack.h"
    66
     7_Bool* new_bool( _Bool b ) {
     8        _Bool* q = malloc(sizeof(_Bool)); /***/
     9        *q = b;
     10        return q;
     11}
     12
    713char* new_char( char c ) {
    814        char* q = malloc(sizeof(char)); /***/
    915        *q = c;
    10         return q;
    11 }
    12 
    13 short* new_short( short s ) {
    14         short* q = malloc(sizeof(short)); /***/
    15         *q = s;
    1616        return q;
    1717}
     
    2323}
    2424
     25void* copy_bool( const void* p ) { return new_bool( *(const _Bool*)p ); } /***/
    2526void* copy_char( const void* p ) { return new_char( *(const char*)p ); } /***/
    26 void* 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_short_char( const void* p ) { return copy_pair( p, copy_short, copy_char ); } /***/
    29 void free_pair_short_char( void* p ) { free_pair( p, free, free ); } /***/
     28void* copy_pair_bool_char( const void* p ) { return copy_pair( p, copy_bool, copy_char ); } /***/
     29void free_pair_bool_char( void* p ) { free_pair( p, free, free ); } /***/
     30
     31int 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}
    3034
    3135int cmp_char( const void* a, const void* b ) { /***/
    3236        return *(const char*)a == *(const char*)b ? 0 : *(const char*)a < *(const char*)b ? -1 : 1;
    33 }
    34 
    35 int 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_short(0), new_char('\0') ),
    52                 * valp = new_pair( new_short(42), new_char('a') );
     51        struct pair * maxp = new_pair( new_bool(0), new_char('\0') ),
     52                * valp = new_pair( new_bool(1), new_char('a') );
    5353        struct stack sp = new_stack(), tp;
    5454
    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 ); /***/ )
     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 ); /***/ )
    5858        REPEAT_TIMED( "pop_pair", N,
    5959                struct pair * xp = pop_stack( &tp );
    60                 if ( cmp_pair( xp, maxp, cmp_short, cmp_char /***/ ) > 0 ) {
    61                         free_pair_short_char( maxp ); /***/
     60                if ( cmp_pair( xp, maxp, cmp_bool, cmp_char /***/ ) > 0 ) {
     61                        free_pair_bool_char( maxp ); /***/
    6262                        maxp = xp;
    6363                } else {
    64                         free_pair_short_char( xp ); /***/
     64                        free_pair_bool_char( xp ); /***/
    6565                } )
    66         free_pair_short_char( maxp ); /***/
    67         free_pair_short_char( valp ); /***/
     66        free_pair_bool_char( maxp ); /***/
     67        free_pair_bool_char( valp ); /***/
    6868}
  • doc/papers/general/evaluation/c-stack.c

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

    r9d6f011 r70969f8  
    33#include "cfa-pair.h"
    44
    5 int main() {
     5int main( int argc, char * argv[] ) {
    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, int x = pop( ti ); if ( x > max ) max = x; )
     12        REPEAT_TIMED( "pop_int", N,
     13                int x = pop( ti ); if ( x > max ) max = x; )
    1314
    14         pair( short, char ) max = { 0h, '\0' }, val = { 42h, 'a' };
    15         stack( pair( short, char ) ) sp, tp;
     15        pair( _Bool, char ) max = { (_Bool)0 /***/, '\0' }, val = { (_Bool)1 /***/, 'a' };
     16        stack( pair( _Bool, char ) ) sp, tp;
    1617
    1718        REPEAT_TIMED( "push_pair", N, push( sp, val ); )
    18         TIMED( "copy_pair", tp{ sp }; )
     19        TIMED( "copy_pair", tp = sp; )
    1920        TIMED( "clear_pair", clear( sp ); )
    20         REPEAT_TIMED( "pop_pair", N, pair(short, char) x = pop( tp ); if ( x > max ) max = x; )
     21        REPEAT_TIMED( "pop_pair", N,
     22                pair(_Bool, char) x = pop( tp ); if ( x > max ) max = x; )
    2123}
  • doc/papers/general/evaluation/cfa-stack.c

    r9d6f011 r70969f8  
    1212        stack_node(T) ** crnt = &s.head;
    1313        for ( stack_node(T) * next = t.head; next; next = next->next ) {
    14                 *crnt = alloc();
    15                 ((*crnt)->value){ next->value };
     14                stack_node(T)* new_node = (stack_node(T)*)malloc(); /***/
     15                (*new_node){ next->value };
     16                *crnt = new_node;
    1617                crnt = &(*crnt)->next;
    1718        }
     
    3031forall(otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; }
    3132
    32 forall(otype T) void push( stack(T) & s, T value ) with( s ) {
    33         stack_node(T)* n = alloc();
    34         (*n){ value, head };
    35         head = n;
     33forall(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;
    3637}
    3738
    38 forall(otype T) T pop( stack(T) & s ) with( s ) {
    39         stack_node(T) * n = head;
    40         head = n->next;
    41         T x = n->value;
     39forall(otype T) T pop( stack(T) & s ) {
     40        stack_node(T) * n = s.head;
     41        s.head = n->next;
     42        T v = n->value;
    4243        ^(*n){};
    4344        free( n );
    44         return x;
     45        return v;
    4546}
    4647
    47 forall(otype T) void clear( stack(T) & s ) with( s ) {
    48         for ( stack_node(T) * next = head; next; ) {
     48forall(otype T) void clear( stack(T) & s ) {
     49        for ( stack_node(T) * next = s.head; next; ) {
    4950                stack_node(T) * crnt = next;
    5051                next = crnt->next;
     
    5253                free(crnt);
    5354        }
    54         head = 0;
     55        s.head = 0;
    5556}
  • doc/papers/general/evaluation/cpp-bench.cpp

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

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

    r9d6f011 r70969f8  
    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

    r9d6f011 r70969f8  
    6767};
    6868
     69class boolean : public ordered, public printable {
     70        bool x;
     71public:
     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
    6992class character : public ordered, public printable {
    7093        char x;
     
    93116};
    94117
    95 class short_integer : public ordered, public printable {
    96         short x;
    97 public:
    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
     141class c_string : public printable {
     142        static constexpr const char* empty = "";
     143        const char* s;
     144public:
     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; }
    139160};
    140161
     
    167188                return y->as<ordered>().cmp( that.y->as<ordered>() ); /***/
    168189        }
    169         int cmp(const ordered& that) const override { return cmp( that.as<pair>() ); } /***/
     190        int cmp(const ordered& that) const override { return cmp( that.as<pair>() ); }
    170191
    171192        void print(std::ostream& out) const override {
  • doc/papers/general/evaluation/timing.dat

    r9d6f011 r70969f8  
    11"400 million repetitions"       "C"     "\\CFA{}"       "\\CC{}"        "\\CC{obj}"
    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
     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
Note: See TracChangeset for help on using the changeset viewer.