# @param varname - variable to replace # @param func - function name, for error messages # @param vars - definitions of the function's vars # @param id - the unique id of this field # @param argCount - the argument count declared by the function sub replaceStep # ($varname, $func, $vars, $id, $argCount) { my ($varname, $func, $vars, $id, $argCount) = @_; if ($varname eq 'argiter') { confess "MySimpleAggregator: internal error in definition of aggregation function '$func', step computation refers to 'argiter' but the function declares no arguments" unless ($argCount > 0); return "\$a${id}"; } elsif ($varname eq 'niter') { return "\$npos"; } elsif ($varname eq 'groupsize') { return "\$context->groupSize()"; } elsif (exists $vars->{$varname}) { return "\$v${id}_${varname}"; } else { confess "MySimpleAggregator: internal error in definition of aggregation function '$func', step computation refers to an unknown variable '$varname'" } } sub replaceResult # ($varname, $func, $vars, $id, $argCount) { my ($varname, $func, $vars, $id, $argCount) = @_; if ($varname eq 'argfirst') { confess "MySimpleAggregator: internal error in definition of aggregation function '$func', result computation refers to '$varname' but the function declares no arguments" unless ($argCount > 0); return "\$f${id}"; } elsif ($varname eq 'arglast') { confess "MySimpleAggregator: internal error in definition of aggregation function '$func', result computation refers to '$varname' but the function declares no arguments" unless ($argCount > 0); return "\$l${id}"; } elsif ($varname eq 'groupsize') { return "\$context->groupSize()"; } elsif (exists $vars->{$varname}) { return "\$v${id}_${varname}"; } else { confess "MySimpleAggregator: internal error in definition of aggregation function '$func', result computation refers to an unknown variable '$varname'" } }
And finally the definition of the aggregation functions:
our $FUNCTIONS = { first => { result => '$%argfirst', }, last => { result => '$%arglast', }, count_star => { argcount => 0, result => '$%groupsize', }, count => { vars => { count => 0 }, step => '$%count++ if (defined $%argiter);', result => '$%count', }, sum => { vars => { sum => 0 }, step => '$%sum += $%argiter;', result => '$%sum', }, max => { vars => { max => 'undef' }, step => '$%max = $%argiter if (!defined $%max || $%argiter > $%max);', result => '$%max', }, min => { vars => { min => 'undef' }, step => '$%min = $%argiter if (!defined $%min || $%argiter < $%min);', result => '$%min', }, avg => { vars => { sum => 0, count => 0 }, step => 'if (defined $%argiter) { $%sum += $%argiter; $%count++; }', result => '($%count == 0? undef : $%sum / $%count)', }, avg_perl => { # Perl-like treat the NULLs as 0s vars => { sum => 0 }, step => '$%sum += $%argiter;', result => '$%sum / $%groupsize', }, nth_simple => { # inefficient, need proper multi-args for better efficiency vars => { n => 'undef', tmp => 'undef', val => 'undef' }, step => '($%n, $%tmp) = @$%argiter; if ($%n == $%niter) { $%val = $%tmp; }', result => '$%val', }, };
You can use as the starting point for building your own. As you can see, this very first simple version of SimpleAggregator didn't include the user-provided functions but the real one already does.
That's it, the whole aggregator generation.
No comments:
Post a Comment