summaryrefslogtreecommitdiff
path: root/src/lib_misc.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib_misc.erl')
-rw-r--r--src/lib_misc.erl235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/lib_misc.erl b/src/lib_misc.erl
new file mode 100644
index 00000000..f5449295
--- /dev/null
+++ b/src/lib_misc.erl
@@ -0,0 +1,235 @@
+-module(lib_misc).
+
+-define(OFFSET_BASIS, 2166136261).
+-define(FNV_PRIME, 16777619).
+
+-export([rm_rf/1, pmap/3, succ/1, fast_acc/3, hash/1, hash/2, fnv/1,
+ nthdelete/2, zero_split/1, nthreplace/3, rand_str/1, position/2,
+ shuffle/1, floor/1, ceiling/1, time_to_epoch_int/1,
+ time_to_epoch_float/1, now_int/0, now_float/0, byte_size/1, listify/1,
+ reverse_bits/1]).
+
+-include("../include/config.hrl").
+-include("../include/profile.hrl").
+
+
+rm_rf(Name) when is_list(Name) ->
+ case filelib:is_dir(Name) of
+ false ->
+ file:delete(Name);
+ true ->
+ case file:list_dir(Name) of
+ {ok, Filenames} ->
+ lists:foreach(fun rm_rf/1, [ filename:join(Name, F) || F <- Filenames]),
+ file:del_dir(Name);
+ {error, Reason} -> error_logger:info_msg("rm_rf failed because ~p~n", [Reason])
+ end
+ end.
+
+zero_split(Bin) ->
+ zero_split(0, Bin).
+
+zero_split(N, Bin) when N > erlang:byte_size(Bin) -> Bin;
+
+zero_split(N, Bin) ->
+ case Bin of
+ <<_:N/binary, 0:8, _/binary>> -> split_binary(Bin, N);
+ _ -> zero_split(N+1, Bin)
+ end.
+
+rand_str(N) ->
+ lists:map(fun(_I) ->
+ random:uniform(26) + $a - 1
+ end, lists:seq(1,N)).
+
+nthreplace(N, E, List) ->
+ lists:sublist(List, N-1) ++ [E] ++ lists:nthtail(N, List).
+
+nthdelete(N, List) ->
+ nthdelete(N, List, []).
+
+nthdelete(0, List, Ret) ->
+ lists:reverse(Ret) ++ List;
+
+nthdelete(_, [], Ret) ->
+ lists:reverse(Ret);
+
+nthdelete(1, [_E|L], Ret) ->
+ nthdelete(0, L, Ret);
+
+nthdelete(N, [E|L], Ret) ->
+ nthdelete(N-1, L, [E|Ret]).
+
+floor(X) ->
+ T = erlang:trunc(X),
+ case (X - T) of
+ Neg when Neg < 0 -> T - 1;
+ Pos when Pos > 0 -> T;
+ _ -> T
+ end.
+
+ceiling(X) ->
+ T = erlang:trunc(X),
+ case (X - T) of
+ Neg when Neg < 0 -> T;
+ Pos when Pos > 0 -> T + 1;
+ _ -> T
+ end.
+
+succ([]) ->
+ [];
+
+succ(Str) ->
+ succ_int(lists:reverse(Str), []).
+
+succ_int([Char|Str], Acc) ->
+ if
+ Char >= $z -> succ_int(Str, [$a|Acc]);
+ true -> lists:reverse(lists:reverse([Char+1|Acc]) ++ Str)
+ end.
+
+fast_acc(_, Acc, 0) -> Acc;
+
+fast_acc(Fun, Acc, N) ->
+ fast_acc(Fun, Fun(Acc), N-1).
+
+shuffle(List) when is_list(List) ->
+ [ N || {_R,N} <- lists:keysort(1, [{random:uniform(),X} || X <- List]) ].
+
+pmap(Fun, List, ReturnNum) ->
+ N = if
+ ReturnNum > length(List) -> length(List);
+ true -> ReturnNum
+ end,
+ SuperParent = self(),
+ SuperRef = erlang:make_ref(),
+ Ref = erlang:make_ref(),
+ %% we spawn an intermediary to collect the results
+ %% this is so that there will be no leaked messages sitting in our mailbox
+ Parent = spawn(fun() ->
+ L = gather(N, length(List), Ref, []),
+ SuperParent ! {SuperRef, pmap_sort(List, L)}
+ end),
+ Pids = [spawn(fun() ->
+ Parent ! {Ref, {Elem, (catch Fun(Elem))}}
+ end) || Elem <- List],
+ Ret = receive
+ {SuperRef, Ret1} -> Ret1
+ end,
+ % i think we need to cleanup here.
+ lists:foreach(fun(P) -> exit(P, die) end, Pids),
+ Ret.
+
+pmap_sort(Original, Results) ->
+ pmap_sort([], Original, lists:reverse(Results)).
+
+% pmap_sort(Sorted, [], _) -> lists:reverse(Sorted);
+pmap_sort(Sorted, _, []) -> lists:reverse(Sorted);
+pmap_sort(Sorted, [E|Original], Results) ->
+ case lists:keytake(E, 1, Results) of
+ {value, {E, Val}, Rest} -> pmap_sort([Val|Sorted], Original, Rest);
+ false -> pmap_sort(Sorted, Original, Results)
+ end.
+
+gather(_, Max, _, L) when length(L) == Max -> L;
+gather(0, _, _, L) -> L;
+gather(N, Max, Ref, L) ->
+ receive
+ {Ref, {Elem, {not_found, Ret}}} -> gather(N, Max, Ref, [{Elem, {not_found, Ret}}|L]);
+ {Ref, {Elem, {badrpc, Ret}}} -> gather(N, Max, Ref, [{Elem, {badrpc, Ret}}|L]);
+ {Ref, {Elem, {'EXIT', Ret}}} -> gather(N, Max, Ref, [{Elem, {'EXIT', Ret}}|L]);
+ {Ref, Ret} -> gather(N-1, Max, Ref, [Ret|L])
+ end.
+
+get_hash_module(#config{hash_module=HashModule}) ->
+ HashModule.
+
+hash(Term) ->
+ HashModule = get_hash_module(configuration:get_config()),
+ ?prof(hash),
+ R = HashModule:hash(Term),
+ ?forp(hash),
+ R.
+
+hash(Term, Seed) ->
+ HashModule = get_hash_module(configuration:get_config()),
+ ?prof(hash),
+ R = HashModule:hash(Term, Seed),
+ ?forp(hash),
+ R.
+
+%32 bit fnv. magic numbers ahoy
+fnv(Term) when is_binary(Term) ->
+ fnv_int(?OFFSET_BASIS, 0, Term);
+
+fnv(Term) ->
+ fnv_int(?OFFSET_BASIS, 0, term_to_binary(Term)).
+
+fnv_int(Hash, ByteOffset, Bin) when erlang:byte_size(Bin) == ByteOffset ->
+ Hash;
+
+fnv_int(Hash, ByteOffset, Bin) ->
+ <<_:ByteOffset/binary, Octet:8, _/binary>> = Bin,
+ Xord = Hash bxor Octet,
+ fnv_int((Xord * ?FNV_PRIME) rem (2 bsl 31), ByteOffset+1, Bin).
+
+position(Predicate, List) when is_function(Predicate) ->
+ position(Predicate, List, 1);
+
+position(E, List) ->
+ position(E, List, 1).
+
+position(Predicate, [], _N) when is_function(Predicate) -> false;
+
+position(Predicate, [E|List], N) when is_function(Predicate) ->
+ case Predicate(E) of
+ true -> N;
+ false -> position(Predicate, List, N+1)
+ end;
+
+position(_, [], _) -> false;
+
+position(E, [E|_List], N) -> N;
+
+position(E, [_|List], N) -> position(E, List, N+1).
+
+now_int() ->
+ time_to_epoch_int(now()).
+
+now_float() ->
+ time_to_epoch_float(now()).
+
+time_to_epoch_int(Time) when is_integer(Time) or is_float(Time) ->
+ Time;
+
+time_to_epoch_int({Mega,Sec,_}) ->
+ Mega * 1000000 + Sec.
+
+time_to_epoch_float(Time) when is_integer(Time) or is_float(Time) ->
+ Time;
+
+time_to_epoch_float({Mega,Sec,Micro}) ->
+ Mega * 1000000 + Sec + Micro / 1000000.
+
+byte_size(List) when is_list(List) ->
+ lists:foldl(fun(El, Acc) -> Acc + lib_misc:byte_size(El) end, 0, List);
+
+byte_size(Term) ->
+ erlang:byte_size(Term).
+
+listify(List) when is_list(List) ->
+ List;
+
+listify(El) -> [El].
+
+reverse_bits(V) when is_integer(V) ->
+ % swap odd and even bits
+ V1 = ((V bsr 1) band 16#55555555) bor (((V band 16#55555555) bsl 1) band 16#ffffffff),
+ % swap consecutive pairs
+ V2 = ((V1 bsr 2) band 16#33333333) bor (((V1 band 16#33333333) bsl 2) band 16#ffffffff),
+ % swap nibbles ...
+ V3 = ((V2 bsr 4) band 16#0F0F0F0F) bor (((V2 band 16#0F0F0F0F) bsl 4) band 16#ffffffff),
+ % swap bytes
+ V4 = ((V3 bsr 8) band 16#00FF00FF) bor (((V3 band 16#00FF00FF) bsl 8) band 16#ffffffff),
+ % swap 2-byte long pairs
+ ((V4 bsr 16) band 16#ffffffff) bor ((V4 bsl 16) band 16#ffffffff).