gb_trees:search/3
Sven-Olof Nystr|m
svenolof@REDACTED
Tue Sep 13 14:58:42 CEST 2005
Ulf Wiger (AL/EAB) writes:
> > > I'm sure you could do a lot of other stuff with
> > search/3 too.
> >
> > I'm not so sure. I can think of a few others, such as
> > building (unbalanced) trees of all nodes greater or
> > smaller than a given key, but I don't think you could
> > do much else with the search function.
>
> Well, we're both wrong, as it turns out. (:
> As written, you probably cannot do much else with it,
That was my point.
> and in fact not even what you suggest, since there
> is no way to make sure that you actually find all nodes
> greater or smaller than a given key (since it always
> goes down only one branch).
I disagree, but it's not very interesting, so I'll let it drop.
> New attempt:
>
> search_1(_Fun, Acc, nil) ->
[snip]
> The first example doesn't really introduce
> anything new, as it scans the whole tree
> (most likely less efficient than iterator())
or to_list().
[Moved example]
> 14> F1 = fun(K,V,Acc) when K > 5 ->
> {smaller,Acc}; (K,V,Acc) ->
> {both,[{K,V}|Acc]} end.
> #Fun<erl_eval.18.103411980>
>
> 15> vccTree:search(F1,[],T2).
> [{4,b},{5,a},{2,b},{3,a},{1,a}]
>
>
> The second example is almost equivalend to
> ets:select/2 on an ordered_set, but with the
> difference (as of now) that ets:select/2 will
> scan the whole table if at least the first part
> of the key isn't bound(*). Now, this is a feature
> that at least I use _a lot_.
So you scan the part of a tree where keys are smaller than 5.
See my comment at the end for alternative ways to provide this
functionality in gb_trees.
> (*) Also with the difference that my function
> screws up the order.
Too bad.
> > > There's probably a more elegant construct
> > > that would solve the problem with equal
> > > or better efficiency. Please go ahead and
> > > suggest better ways.
> >
> > See your next mail :-)
>
> Not fair, as it solved another problem. (:
> I want to support both getting the first
> available free resource, and reserving
> a specific resource (c.f. UNIX sockets.)
OK. I actually didn't realise that they implemented different
functions.
> > > free/2 is more involved as it needs to
> > > de-fragment the tree, but that would be
> > > done along the same lines as reserve/2,
> > > using the gb_trees:search/3 function.
> >
> > Why defragment? The cost of defragmentation
> > could easily exeed the cost of having a
> > fragmented tree in memory (unless you need to be
> > able to allocate contiguous sequences of resources,
> > of course).
>
> Yes, I do that too.
OK.
> My intention was to allow a very large virtual range.
> allocated. BTW, the code to free resources and
> de-fragment looks pretty much like this:
>
> do_free_x(Id, Free) ->
> Prev = prev(Id, Free),
> Next = next(Id, Free),
> case {Prev, Next} of
> {{value,{A,B}}, _} when A >= Id, Id >= B ->
> erlang:error({not_reserved, Id});
> {_, {value,{C,D}}} when C >= Id, Id >= D ->
> erlang:error({not_reserved, Id});
> {{value,{A,B}}, {value,{C,D}}} when B == Id-1, C == Id+1 ->
> Free1 = delete(C, Free),
> update(A, D, Free1);
> {_, {value,{C,D}}} when Id+1 == C ->
> Free1 = delete(C, Free),
> insert(Id, D, Free1);
> {{value,{A,B}}, _} when B+1 == Id ->
> update(A, Id, Free);
> Other ->
> insert(Id, Id, Free)
> end.
>
>
> Ony my SunBlade, reserving and freeing resources
> with gb_trees takes about 20-30 microsecs on a
> small tree, and about 40 usecs on a large one
> (10,000 nodes).
That's nice.
>
> Forgetting about this particular example, having
> previous(), next() and an efficient way to select
> nodes in a tree without having to traverse the
> whole tree would be useful, don't you think?
Sure, previous() and next() could be useful. I would prefer more
descriptive names, such as lookup_smaller() and lookup_larger(). Also,
I think they should always return a strictly smaller/larger key, even
if the given key is present.
> Today, you can do that with ets ordered_set, but
> not easily with any of the functional data
> structures provided by OTP.
Currently, iterators can only be used to scan the tree from start, One
might consider iterators that start the scan from a point in the
middle of the tree (from a given key), or iterators that scan the
tree backwards.
Another way to do partial scans might be a function
to_list(Key1, Key2)
that returns a list of the entries in the tree between the two keys.
Sven-Olof
More information about the erlang-questions
mailing list