Changes in / [70969f8:9d6f011]
- Location:
- doc/papers/general
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/papers/general/Paper.tex
r70969f8 r9d6f011 553 553 struct litres {}; 554 554 555 forall( dtype U ) scalar(U) ?+?( scalar(U) a, scalar(U) b ) {555 forall( dtype U ) scalar(U) ?+?( scalar(U) a, scalar(U) b ) { 556 556 return (scalar(U)){ a.value + b.value }; 557 557 } … … 2566 2566 In fact, \CFA's features for generic programming can enable faster runtime execution than idiomatic @void *@-based C code. 2567 2567 This 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 thanin length and clarity of source code.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. 2569 2569 A 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}.2570 Figure~\ref{fig:BenchmarkTest} shows the \CFA benchmark tests for a generic stack based on a singly linked-list. 2571 2571 The 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.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. 2573 2573 2574 2574 \begin{figure} 2575 2575 \begin{cfa}[xleftmargin=3\parindentlnth,aboveskip=0pt,belowskip=0pt] 2576 int main( int argc, char * argv[]) {2576 int main() { 2577 2577 int max = 0, val = 42; 2578 2578 stack( int ) si, ti; 2579 2579 2580 2580 REPEAT_TIMED( "push_int", N, push( si, val ); ) 2581 TIMED( "copy_int", ti = si; )2581 TIMED( "copy_int", ti{ si }; ) 2582 2582 TIMED( "clear_int", clear( si ); ) 2583 2583 REPEAT_TIMED( "pop_int", N, int x = pop( ti ); if ( x > max ) max = x; ) 2584 2584 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; 2587 2587 2588 2588 REPEAT_TIMED( "push_pair", N, push( sp, val ); ) 2589 TIMED( "copy_pair", tp = sp; )2589 TIMED( "copy_pair", tp{ sp }; ) 2590 2590 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; ) 2592 2592 } 2593 2593 \end{cfa} … … 2600 2600 hence runtime checks are necessary to safely down-cast objects. 2601 2601 The 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. 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. 2604 2603 2605 2604 Figure~\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. 2606 2605 The 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.2606 All code is compiled at \texttt{-O2} by gcc or g++ 6.3.0, with all \CC code compiled as \CCfourteen. 2608 2607 The 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. 2609 2608 … … 2623 2622 & \CT{C} & \CT{\CFA} & \CT{\CC} & \CT{\CCV} \\ \hline 2624 2623 maximum 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 & 2 29 & 18 & 38\\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 \\ 2628 2627 \end{tabular} 2629 2628 \end{table} 2630 2629 2631 2630 The 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 -basedbenchmarks.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.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. 2634 2633 \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. 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. 2638 2636 Finally, the binary size for \CFA is larger because of static linking with the \CFA libraries. 2639 2637 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 54lines, 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. 2641 2639 On 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; 2643 2641 with their omission, the \CCV line count is similar to C. 2644 2642 We 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. … … 2646 2644 Raw line-count, however, is a fairly rough measure of code complexity; 2647 2645 another 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 pointer sarguments 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@).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@). 2649 2647 To 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. 2650 2648 The \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 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}. 2654 2650 2655 2651 \section{Related Work} 2656 2657 2652 2658 2653 \subsection{Polymorphism} … … 2735 2730 user defined: D, Objective-C 2736 2731 2737 2738 2732 \section{Conclusion and Future Work} 2739 2733 … … 2783 2777 \CFA 2784 2778 \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 };2789 2779 forall( otype T ) struct stack_node { 2790 2780 T value; 2791 2781 stack_node(T) * next; 2792 2782 }; 2793 forall( otype T) void ?{}( stack(T) & s ) { (s.head){ 0 }; } 2794 forall( otype T) void ?{}( stack(T) & s, stack(T) t ) { 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 ) { 2795 2786 stack_node(T) ** crnt = &s.head; 2796 2787 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; 2802 2791 } 2803 2792 *crnt = 0; … … 2811 2800 forall( otype T ) void ^?{}( stack(T) & s) { clear( s ); } 2812 2801 forall( 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; ) { 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; ) { 2827 2817 stack_node(T) * crnt = next; 2828 2818 next = crnt->next; 2829 delete( crnt ); 2819 ^(*crnt){}; 2820 free(crnt); 2830 2821 } 2831 s.head = 0;2822 head = 0; 2832 2823 } 2833 2824 \end{cfa} … … 2836 2827 \CC 2837 2828 \begin{cfa}[xleftmargin=2\parindentlnth,aboveskip=0pt,belowskip=0pt] 2838 template<typename T> classstack {2829 template<typename T> struct stack { 2839 2830 struct node { 2840 2831 T value; … … 2843 2834 }; 2844 2835 node * head; 2845 void copy(const stack<T> & o) {2836 void copy(const stack<T> & o) { 2846 2837 node ** crnt = &head; 2847 2838 for ( node * next = o.head;; next; next = next->next ) { … … 2851 2842 *crnt = nullptr; 2852 2843 } 2853 public:2854 2844 stack() : head(nullptr) {} 2855 stack(const stack<T> & o) { copy(o); }2845 stack(const stack<T> & o) { copy(o); } 2856 2846 stack(stack<T> && o) : head(o.head) { o.head = nullptr; } 2857 2847 ~stack() { clear(); } 2858 stack & operator= (const stack<T> & o) {2848 stack & operator= (const stack<T> & o) { 2859 2849 if ( this == &o ) return *this; 2860 2850 clear(); … … 2895 2885 struct stack_node * next; 2896 2886 }; 2887 struct stack { struct stack_node* head; }; 2897 2888 struct stack new_stack() { return (struct stack){ NULL }; /***/ } 2898 2889 void copy_stack(struct stack * s, const struct stack * t, void * (*copy)(const void *)) { … … 2900 2891 for ( struct stack_node * next = t->head; next; next = next->next ) { 2901 2892 *crnt = malloc(sizeof(struct stack_node)); /***/ 2902 **crnt = (struct stack_node){ copy(next->value) }; /***/2893 (*crnt)->value = copy(next->value); 2903 2894 crnt = &(*crnt)->next; 2904 2895 } 2905 *crnt = 0;2896 *crnt = NULL; 2906 2897 } 2907 2898 _Bool stack_empty(const struct stack * s) { return s->head == NULL; } … … 2932 2923 \CCV 2933 2924 \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; 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; 2940 2939 } 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; 2973 2949 } 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 }; 2976 2974 \end{cfa} 2977 2975 -
doc/papers/general/evaluation/c-bench.c
r70969f8 r9d6f011 5 5 #include "c-stack.h" 6 6 7 _Bool* new_bool( _Bool b) {8 _Bool* q = malloc(sizeof(_Bool)); /***/9 *q = b;7 char* new_char( char c ) { 8 char* q = malloc(sizeof(char)); /***/ 9 *q = c; 10 10 return q; 11 11 } 12 12 13 char* new_char( char c) {14 char* q = malloc(sizeof(char)); /***/15 *q = c;13 short* new_short( short s ) { 14 short* q = malloc(sizeof(short)); /***/ 15 *q = s; 16 16 return q; 17 17 } … … 23 23 } 24 24 25 void* copy_bool( const void* p ) { return new_bool( *(const _Bool*)p ); } /***/26 25 void* copy_char( const void* p ) { return new_char( *(const char*)p ); } /***/ 26 void* copy_short( const void* p ) { return new_short( *(const short*)p ); } /***/ 27 27 void* 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 } 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 ); } /***/ 34 30 35 31 int cmp_char( const void* a, const void* b ) { /***/ 36 32 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; 37 37 } 38 38 … … 49 49 free(xi); ) 50 50 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') ); 53 53 struct stack sp = new_stack(), tp; 54 54 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 ); /***/ ) 58 58 REPEAT_TIMED( "pop_pair", N, 59 59 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 ); /***/ 62 62 maxp = xp; 63 63 } else { 64 free_pair_ bool_char( xp ); /***/64 free_pair_short_char( xp ); /***/ 65 65 } ) 66 free_pair_ bool_char( maxp ); /***/67 free_pair_ bool_char( valp ); /***/66 free_pair_short_char( maxp ); /***/ 67 free_pair_short_char( valp ); /***/ 68 68 } -
doc/papers/general/evaluation/c-stack.c
r70969f8 r9d6f011 13 13 for ( struct stack_node* next = t->head; next; next = next->next ) { 14 14 *crnt = malloc(sizeof(struct stack_node)); /***/ 15 **crnt = (struct stack_node){ copy(next->value) }; /***/15 (*crnt)->value = copy(next->value); 16 16 crnt = &(*crnt)->next; 17 17 } 18 *crnt = 0;18 *crnt = NULL; 19 19 } 20 20 -
doc/papers/general/evaluation/cfa-bench.c
r70969f8 r9d6f011 3 3 #include "cfa-pair.h" 4 4 5 int main( int argc, char * argv[]) {5 int main() { 6 6 int max = 0, val = 42; 7 7 stack( int ) si, ti; 8 8 9 9 REPEAT_TIMED( "push_int", N, push( si, val ); ) 10 TIMED( "copy_int", ti = si; )10 TIMED( "copy_int", ti{ si }; ) 11 11 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; ) 14 13 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; 17 16 18 17 REPEAT_TIMED( "push_pair", N, push( sp, val ); ) 19 TIMED( "copy_pair", tp = sp; )18 TIMED( "copy_pair", tp{ sp }; ) 20 19 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; ) 23 21 } -
doc/papers/general/evaluation/cfa-stack.c
r70969f8 r9d6f011 12 12 stack_node(T) ** crnt = &s.head; 13 13 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 }; 17 16 crnt = &(*crnt)->next; 18 17 } … … 31 30 forall(otype T) _Bool empty( const stack(T) & s ) { return s.head == 0; } 32 31 33 forall(otype T) void push( stack(T) & s, T value ) {34 stack_node(T)* n ew_node = (stack_node(T)*)malloc(); /***/35 (*n ew_node){ value, s.head };36 s.head = new_node;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; 37 36 } 38 37 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;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; 43 42 ^(*n){}; 44 43 free( n ); 45 return v;44 return x; 46 45 } 47 46 48 forall(otype T) void clear( stack(T) & s ) {49 for ( stack_node(T) * next = s.head; next; ) {47 forall(otype T) void clear( stack(T) & s ) with( s ) { 48 for ( stack_node(T) * next = head; next; ) { 50 49 stack_node(T) * crnt = next; 51 50 next = crnt->next; … … 53 52 free(crnt); 54 53 } 55 s.head = 0;54 head = 0; 56 55 } -
doc/papers/general/evaluation/cpp-bench.cpp
r70969f8 r9d6f011 13 13 REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop() ); ) 14 14 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; 17 17 18 18 REPEAT_TIMED( "push_pair", N, sp.push( valp ); ) -
doc/papers/general/evaluation/cpp-vbench.cpp
r70969f8 r9d6f011 13 13 REPEAT_TIMED( "pop_int", N, maxi = std::max( maxi, ti.pop()->as<integer>() ); /***/ ) 14 14 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') }; 17 17 stack sp, tp; 18 18 -
doc/papers/general/evaluation/cpp-vstack.cpp
r70969f8 r9d6f011 7 7 node** crnt = &head; 8 8 for ( node* next = o.head; next; next = next->next ) { 9 *crnt = new node{ *next->value }; 9 *crnt = new node{ *next->value }; /***/ 10 10 crnt = &(*crnt)->next; 11 11 } -
doc/papers/general/evaluation/object.hpp
r70969f8 r9d6f011 67 67 }; 68 68 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 92 69 class character : public ordered, public printable { 93 70 char x; … … 116 93 }; 117 94 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 118 118 class integer : public ordered, public printable { 119 119 int x; … … 137 137 138 138 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; }160 139 }; 161 140 … … 188 167 return y->as<ordered>().cmp( that.y->as<ordered>() ); /***/ 189 168 } 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>() ); } /***/ 191 170 192 171 void print(std::ostream& out) const override { -
doc/papers/general/evaluation/timing.dat
r70969f8 r9d6f011 1 1 "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.