1 %%%-------------------------------------------------------------------
2 %%% File : etorrent_utils.erl
3 %%% Author : User Jlouis <jesper.louis.andersen@gmail.com>
4 %%% License : See COPYING
5 %%% Description : A selection of utilities used throughout the code
7 %%% Created : 17 Apr 2007 by User Jlouis <jesper.louis.andersen@gmail.com>
8 %%%-------------------------------------------------------------------
9 -module(etorrent_utils
).
12 -export([queue_remove
/2, queue_remove_with_check
/2,
13 build_encoded_form_rfc1738
/1,
14 shuffle
/1, gsplit
/2]).
16 %%====================================================================
18 %%====================================================================
20 %%--------------------------------------------------------------------
21 %% Function: gsplit(N, L1) -> {L2, L3}
23 %% types: N - integer()
24 %% L1, L2, L3 - list()
26 %% Graceful split. Works is lists:split, but if N is greater than
27 %% length(L1) then L1 =:= L2 and L3 = []
28 %%--------------------------------------------------------------------
32 gsplit(_N
, [], Rest
) ->
33 {lists:reverse(Rest
), []};
34 gsplit(0, L1
, Rest
) ->
35 {lists:reverse(Rest
), L1
};
36 gsplit(N
, [H
|T
], Rest
) ->
37 gsplit(N
-1, T
, [H
| Rest
]).
39 %%--------------------------------------------------------------------
40 %% Function: queue_remove_with_check(Item, Q1) -> {ok, Q2} | false
41 %% Description: If Item is present in queue(), remove the first
42 %% occurence and return it as {ok, Q2}. If the item can not be found
44 %% Note: Inefficient implementation. Converts to/from lists.
45 %%--------------------------------------------------------------------
46 queue_remove_with_check(Item
, Q
) ->
47 QList
= queue:to_list(Q
),
48 case lists:member(Item
, QList
) of
50 List
= lists:delete(Item
, QList
),
51 {ok
, queue:from_list(List
)};
56 %%--------------------------------------------------------------------
57 %% Function: queue_remove(Item, queue()) -> queue()
58 %% Description: Remove first occurence of Item in queue() if present.
59 %% Note: This function assumes the representation of queue is opaque
60 %% and thus the function is quite ineffective. We can build a much
61 %% much faster version if we create our own queues.
62 %%--------------------------------------------------------------------
63 queue_remove(Item
, Q
) ->
64 QList
= queue:to_list(Q
),
65 List
= lists:delete(Item
, QList
),
66 queue:from_list(List
).
68 %%--------------------------------------------------------------------
69 %% Function: build_encoded_form_rfc1738(list() | binary()) -> String
70 %% Description: Convert the list into RFC1738 encoding (URL-encoding).
71 %%--------------------------------------------------------------------
72 build_encoded_form_rfc1738(List
) when is_list(List
) ->
73 Unreserved
= rfc_3986_unreserved_characters_set(),
75 case sets:is_element(E
, Unreserved
) of
80 ["%", io_lib:format("~2.16.0B", [E
])])
83 lists:flatten([F(E
) || E
<- List
]);
84 build_encoded_form_rfc1738(Binary
) when is_binary(Binary
) ->
85 build_encoded_form_rfc1738(binary_to_list(Binary
)).
87 %%--------------------------------------------------------------------
88 %% Function: shuffle(List1) -> List2
89 %% Description: Permute List1 randomly. Returns the permuted list.
90 %%--------------------------------------------------------------------
94 %%====================================================================
96 %%====================================================================
98 rfc_3986_unreserved_characters() ->
99 % jlouis: I deliberately killed ~ from the list as it seems the Mainline
100 % client doesn't announce this.
101 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_./".
103 rfc_3986_unreserved_characters_set() ->
104 sets:from_list(rfc_3986_unreserved_characters()).
107 %% Flip a coin randomly
109 random:uniform(2) - 1.
112 %% Merge 2 lists, using a coin flip to choose which list to take the next element from.
117 merge([A
| As
], [B
| Bs
]) ->
120 [A
| merge(As
, [B
| Bs
])];
122 [B
| merge([A
| As
], Bs
)]
126 %% Partition a list into items.
128 partition_l(List
, [], []).
130 partition_l([], A
, B
) ->
132 partition_l([Item
], A
, B
) ->
134 partition_l([Item
| Rest
], A
, B
) ->
135 partition_l(Rest
, B
, [Item
| A
]).
138 %% Shuffle a list by partitioning it and then merging it back by coin-flips
141 merge_shuffle([Item
]) ->
143 merge_shuffle(List
) ->
144 {A
, B
} = partition(List
),
145 merge(merge_shuffle(A
), merge_shuffle(B
)).