push_element/2 - efficient sliding window

Ulf Wiger (AL/EAB) ulf.wiger@REDACTED
Wed Aug 10 16:23:17 CEST 2005


Inspired by Joel Reymont's trials trying to make an on-line trading platform in erlang, and by the recent discussions about trace data, I thought I'd try to invent a new BIF (never tried that before...)

Since I have no authority to introduce BIFs in Erlang, getting this accepted could be done by:
(a) the OTP team finding it a good idea and just doing it
(b) enough users finding it useful to generate popular demand.


erlang:push_element(Tuple, Value) pushes value into position 1 of Tuple, shifting the existing values one step to the right. This can be used as a fixed-size sliding window which costs the same as setelement/3 to update.

Eshell V5.4.8  (abort with ^G)
1> erlang:push_element({a,b,c},3).
{3,a,b}
2> erlang:push_element(v(1),3).        
{3,3,a}
3> erlang:push_element({a,b},3).      
{3,a}
4> erlang:push_element({a},3).  
{3}
5> erlang:push_element({},3). 

=ERROR REPORT==== 10-Aug-2005::16:10:49 ===
Error in process <0.30.0> with exit value: {badarg,[{erlang,push_element,[{},3]},{erl_eval,do_apply,5},{shell,exprs,6},{shell,eval_loop,3}]}

** exited: {badarg,[{erlang,push_element,[{},3]},
                    {erl_eval,do_apply,5},
                    {shell,exprs,6},
                    {shell,eval_loop,3}]} **
6> T = erlang:make_tuple(200,a). 
{a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a|...}
7> timer:tc(erlang,push_element,[T,1]).
{8,{1,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a|...}}


My heavy-handed attempt at writing this in C (copy-paste setelement_3 and tweaking it some):

BIF_RETTYPE push_element_2(BIF_ALIST_2)
{
    Eterm* ptr;
    Eterm* hp;
    Eterm* resp;
    Uint size;

    if (is_not_tuple(BIF_ARG_1)) {
    error:
	BIF_ERROR(BIF_P, BADARG);
    }
    ptr = tuple_val(BIF_ARG_1);
    size = arityval(*ptr) + 1;   /* include arity */
    if (size < 2) {
	goto error;
    }

    hp = HAlloc(BIF_P, size);

    /* copy the tuple */
    resp = hp;
    *hp++ = *ptr++;
    *hp++ = BIF_ARG_2;
    size = size-2;
    while (size--) {	/* XXX use memcpy? */
	*hp++ = *ptr++;
    }
    BIF_RET(make_tuple(resp));
}


You then have to go into erts/emulator/beam/bif.tab and add the new BIF.
In order to test it, make clean, and then 'make opt' (rebuild the optimized beam).


/Uffe



More information about the erlang-questions mailing list