# @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