1%% @author Northscale <info@northscale.com>
2%% @copyright 2010 NorthScale, Inc.
3%%
4%% Licensed under the Apache License, Version 2.0 (the "License");
5%% you may not use this file except in compliance with the License.
6%% You may obtain a copy of the License at
7%%
8%%      http://www.apache.org/licenses/LICENSE-2.0
9%%
10%% Unless required by applicable law or agreed to in writing, software
11%% distributed under the License is distributed on an "AS IS" BASIS,
12%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13%% See the License for the specific language governing permissions and
14%% limitations under the License.
15%%
16-module(ringbuffer).
17
18-export([new/1, to_list/1, to_list/2, to_list/3, add/2]).
19
20% Create a ringbuffer that can hold at most Size items.
21-spec new(integer()) -> queue().
22new(Size) ->
23    queue:from_list([empty || _ <- lists:seq(1, Size)]).
24
25
26% Convert the ringbuffer to a list (oldest items first).
27-spec to_list(integer()) -> list().
28to_list(R) -> to_list(R, false).
29-spec to_list(queue(), W) -> list() when is_subtype(W, boolean());
30             (integer(), queue()) -> list().
31to_list(R, WithEmpties) when is_boolean(WithEmpties) ->
32    queue:to_list(to_queue(R));
33
34% Get at most the N newest items from the given ringbuffer (oldest first).
35to_list(N, R) -> to_list(N, R, false).
36
37-spec to_list(integer(), queue(), boolean()) -> list().
38to_list(N, R, WithEmpties) ->
39    L =  lists:reverse(queue:to_list(to_queue(R, WithEmpties))),
40    lists:reverse(case (catch lists:split(N, L)) of
41                      {'EXIT', {badarg, _Reason}} -> L;
42                      {L1, _L2} -> L1
43                  end).
44
45% Add an element to a ring buffer.
46-spec add(term(), queue()) -> queue().
47add(E, R) ->
48    queue:in(E, queue:drop(R)).
49
50% private
51-spec to_queue(queue()) -> queue().
52to_queue(R) -> to_queue(R, false).
53
54-spec to_queue(queue(), boolean()) -> queue().
55to_queue(R, false) -> queue:filter(fun(X) -> X =/= empty end, R);
56to_queue(R, true) -> R.
57