fixes to dialyzer
All types should now be correct and dialyzer runs successfully Signed-off-by: Jordan Wilberding <diginux@gmail.com>
This commit is contained in:
parent
7e42c243b0
commit
e035ae3dbf
12 changed files with 107 additions and 92 deletions
4
Makefile
4
Makefile
|
@ -35,7 +35,7 @@ $(ERLWARE_COMMONS_PLT):
|
||||||
@echo Building local plt at $(ERLWARE_COMMONS_PLT)
|
@echo Building local plt at $(ERLWARE_COMMONS_PLT)
|
||||||
@echo
|
@echo
|
||||||
- dialyzer --output_plt $(ERLWARE_COMMONS_PLT) --build_plt \
|
- dialyzer --output_plt $(ERLWARE_COMMONS_PLT) --build_plt \
|
||||||
--apps erts kernel stdlib -r deps
|
--apps erts kernel stdlib eunit -r deps
|
||||||
|
|
||||||
dialyzer: $(ERLWARE_COMMONS_PLT)
|
dialyzer: $(ERLWARE_COMMONS_PLT)
|
||||||
dialyzer --plt $(ERLWARE_COMMONS_PLT) -Wrace_conditions --src src
|
dialyzer --plt $(ERLWARE_COMMONS_PLT) -Wrace_conditions --src src
|
||||||
|
@ -49,7 +49,7 @@ shell: compile
|
||||||
# rebuilt). However, eunit runs the tests, which probably
|
# rebuilt). However, eunit runs the tests, which probably
|
||||||
# fails (thats probably why You want them in the shell). This
|
# fails (thats probably why You want them in the shell). This
|
||||||
# runs eunit but tells make to ignore the result.
|
# runs eunit but tells make to ignore the result.
|
||||||
- @$(REBAR) eunit
|
- @$(REBAR) skip_deps=true eunit
|
||||||
@$(ERL) $(ERLFLAGS)
|
@$(ERL) $(ERLFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
|
@ -29,7 +29,9 @@
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Types
|
%%% Types
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
-opaque dictionary(K, V) :: {ec_assoc_list,
|
%% This should be opaque, but that kills dialyzer so for now we export it
|
||||||
|
%% however you should not rely on the internal representation here
|
||||||
|
-type dictionary(K, V) :: {ec_assoc_list,
|
||||||
[{ec_dictionary:key(K), ec_dictionary:value(V)}]}.
|
[{ec_dictionary:key(K), ec_dictionary:value(V)}]}.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
@ -82,7 +84,7 @@ remove(Key, {ec_assoc_list, Data}) ->
|
||||||
has_value(Value, {ec_assoc_list, Data}) ->
|
has_value(Value, {ec_assoc_list, Data}) ->
|
||||||
lists:keymember(Value, 2, Data).
|
lists:keymember(Value, 2, Data).
|
||||||
|
|
||||||
-spec size(Object::dictionary(_K, _V)) -> integer().
|
-spec size(Object::dictionary(_K, _V)) -> non_neg_integer().
|
||||||
size({ec_assoc_list, Data}) ->
|
size({ec_assoc_list, Data}) ->
|
||||||
length(Data).
|
length(Data).
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,9 @@
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Types
|
%%% Types
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
-opaque dictionary(_K, _V) :: dict().
|
%% This should be opaque, but that kills dialyzer so for now we export it
|
||||||
|
%% however you should not rely on the internal representation here
|
||||||
|
-type dictionary(_K, _V) :: dict().
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
|
@ -88,7 +90,7 @@ has_value(Value, Data) ->
|
||||||
false,
|
false,
|
||||||
Data).
|
Data).
|
||||||
|
|
||||||
-spec size(Object::dictionary(_K, _V)) -> integer().
|
-spec size(Object::dictionary(_K, _V)) -> non_neg_integer().
|
||||||
size(Data) ->
|
size(Data) ->
|
||||||
dict:size(Data).
|
dict:size(Data).
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,6 @@
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(ec_dictionary).
|
-module(ec_dictionary).
|
||||||
|
|
||||||
%%% Behaviour Callbacks
|
|
||||||
-export([behaviour_info/1]).
|
|
||||||
|
|
||||||
%% API
|
%% API
|
||||||
-export([new/1,
|
-export([new/1,
|
||||||
has_key/2,
|
has_key/2,
|
||||||
|
@ -38,30 +35,27 @@
|
||||||
{callback,
|
{callback,
|
||||||
data}).
|
data}).
|
||||||
|
|
||||||
-opaque dictionary(_K, _V) :: #dict_t{}.
|
%% This should be opaque, but that kills dialyzer so for now we export it
|
||||||
|
%% however you should not rely on the internal representation here
|
||||||
|
-type dictionary(_K, _V) :: #dict_t{}.
|
||||||
-type key(T) :: T.
|
-type key(T) :: T.
|
||||||
-type value(T) :: T.
|
-type value(T) :: T.
|
||||||
|
|
||||||
|
-callback new() -> any().
|
||||||
|
-callback has_key(key(any()), any()) -> boolean().
|
||||||
|
-callback get(key(any()), any()) -> any().
|
||||||
|
-callback add(key(any()), value(any()), T) -> T.
|
||||||
|
-callback remove(key(any()), T) -> T.
|
||||||
|
-callback has_value(value(any()), any()) -> boolean().
|
||||||
|
-callback size(any()) -> non_neg_integer().
|
||||||
|
-callback to_list(any()) -> [{key(any()), value(any())}].
|
||||||
|
-callback from_list([{key(any()), value(any())}]) -> any().
|
||||||
|
-callback keys(any()) -> [key(any())].
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
%% @doc export the behaviour callbacks for this type
|
|
||||||
%% @private
|
|
||||||
behaviour_info(callbacks) ->
|
|
||||||
[{new, 0},
|
|
||||||
{has_key, 2},
|
|
||||||
{get, 2},
|
|
||||||
{add, 3},
|
|
||||||
{remove, 2},
|
|
||||||
{has_value, 2},
|
|
||||||
{size, 1},
|
|
||||||
{to_list, 1},
|
|
||||||
{from_list, 1},
|
|
||||||
{keys, 1}];
|
|
||||||
behaviour_info(_) ->
|
|
||||||
undefined.
|
|
||||||
|
|
||||||
%% @doc create a new dictionary object from the specified module. The
|
%% @doc create a new dictionary object from the specified module. The
|
||||||
%% module should implement the dictionary behaviour.
|
%% module should implement the dictionary behaviour.
|
||||||
%%
|
%%
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export_type([
|
-export_type([
|
||||||
path/0,
|
|
||||||
option/0
|
option/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -43,14 +42,13 @@
|
||||||
%%============================================================================
|
%%============================================================================
|
||||||
%% Types
|
%% Types
|
||||||
%%============================================================================
|
%%============================================================================
|
||||||
-type path() :: string().
|
-type option() :: recursive.
|
||||||
-type option() :: [atom()].
|
-type void() :: ok.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%% @doc copy an entire directory to another location.
|
%% @doc copy an entire directory to another location.
|
||||||
-spec copy(path(), path(), Options::[option()]) -> ok.
|
-spec copy(file:name(), file:name(), Options::[option()]) -> void().
|
||||||
copy(From, To, []) ->
|
copy(From, To, []) ->
|
||||||
copy(From, To);
|
copy(From, To);
|
||||||
copy(From, To, [recursive] = Options) ->
|
copy(From, To, [recursive] = Options) ->
|
||||||
|
@ -63,7 +61,7 @@ copy(From, To, [recursive] = Options) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc copy a file including timestamps,ownership and mode etc.
|
%% @doc copy a file including timestamps,ownership and mode etc.
|
||||||
-spec copy(From::string(), To::string()) -> ok.
|
-spec copy(From::file:filename(), To::file:filename()) -> ok.
|
||||||
copy(From, To) ->
|
copy(From, To) ->
|
||||||
try
|
try
|
||||||
ec_file_copy(From, To)
|
ec_file_copy(From, To)
|
||||||
|
@ -81,7 +79,7 @@ md5sum(Value) ->
|
||||||
%% <pre>
|
%% <pre>
|
||||||
%% Example: remove("./tmp_dir", [recursive]).
|
%% Example: remove("./tmp_dir", [recursive]).
|
||||||
%% </pre>
|
%% </pre>
|
||||||
-spec remove(path(), Options::[option()]) -> ok | {error, Reason::term()}.
|
-spec remove(file:name(), Options::[option()]) -> ok | {error, Reason::term()}.
|
||||||
remove(Path, Options) ->
|
remove(Path, Options) ->
|
||||||
try
|
try
|
||||||
ok = ec_file_remove(Path, Options)
|
ok = ec_file_remove(Path, Options)
|
||||||
|
@ -90,12 +88,12 @@ remove(Path, Options) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc delete a file.
|
%% @doc delete a file.
|
||||||
-spec remove(path()) -> ok | {error, Reason::term()}.
|
-spec remove(file:name()) -> ok | {error, Reason::term()}.
|
||||||
remove(Path) ->
|
remove(Path) ->
|
||||||
remove(Path, []).
|
remove(Path, []).
|
||||||
|
|
||||||
%% @doc indicates witha boolean if the path supplied refers to symlink.
|
%% @doc indicates witha boolean if the path supplied refers to symlink.
|
||||||
-spec is_symlink(path()) -> boolean().
|
-spec is_symlink(file:name()) -> boolean().
|
||||||
is_symlink(Path) ->
|
is_symlink(Path) ->
|
||||||
case file:read_link_info(Path) of
|
case file:read_link_info(Path) of
|
||||||
{ok, #file_info{type = symlink}} ->
|
{ok, #file_info{type = symlink}} ->
|
||||||
|
@ -107,7 +105,7 @@ is_symlink(Path) ->
|
||||||
|
|
||||||
%% @doc make a unique temorory directory. Similar function to BSD stdlib
|
%% @doc make a unique temorory directory. Similar function to BSD stdlib
|
||||||
%% function of the same name.
|
%% function of the same name.
|
||||||
-spec insecure_mkdtemp() -> TmpDirPath::path().
|
-spec insecure_mkdtemp() -> TmpDirPath::file:name().
|
||||||
insecure_mkdtemp() ->
|
insecure_mkdtemp() ->
|
||||||
random:seed(now()),
|
random:seed(now()),
|
||||||
UniqueNumber = erlang:integer_to_list(erlang:trunc(random:uniform() * 1000000000000)),
|
UniqueNumber = erlang:integer_to_list(erlang:trunc(random:uniform() * 1000000000000)),
|
||||||
|
@ -128,7 +126,7 @@ insecure_mkdtemp() ->
|
||||||
|
|
||||||
|
|
||||||
%% @doc Makes a directory including parent dirs if they are missing.
|
%% @doc Makes a directory including parent dirs if they are missing.
|
||||||
-spec mkdir_path(path()) -> ok.
|
-spec mkdir_path(file:name()) -> ok.
|
||||||
mkdir_path(Path) ->
|
mkdir_path(Path) ->
|
||||||
%% We are exploiting a feature of ensuredir that that creates all
|
%% We are exploiting a feature of ensuredir that that creates all
|
||||||
%% directories up to the last element in the filename, then ignores
|
%% directories up to the last element in the filename, then ignores
|
||||||
|
@ -144,7 +142,7 @@ mkdir_path(Path) ->
|
||||||
|
|
||||||
%% @doc consult an erlang term file from the file system.
|
%% @doc consult an erlang term file from the file system.
|
||||||
%% Provide user readible exeption on failure.
|
%% Provide user readible exeption on failure.
|
||||||
-spec consult(FilePath::path()) -> term().
|
-spec consult(FilePath::file:name()) -> term().
|
||||||
consult(FilePath) ->
|
consult(FilePath) ->
|
||||||
case file:consult(FilePath) of
|
case file:consult(FilePath) of
|
||||||
{ok, [Term]} ->
|
{ok, [Term]} ->
|
||||||
|
@ -160,7 +158,7 @@ consult(FilePath) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc read a file from the file system. Provide UEX exeption on failure.
|
%% @doc read a file from the file system. Provide UEX exeption on failure.
|
||||||
-spec read(FilePath::string()) -> binary().
|
-spec read(FilePath::file:filename()) -> binary().
|
||||||
read(FilePath) ->
|
read(FilePath) ->
|
||||||
try
|
try
|
||||||
{ok, FileBin} = file:read_file(FilePath),
|
{ok, FileBin} = file:read_file(FilePath),
|
||||||
|
@ -173,7 +171,7 @@ read(FilePath) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc write a file to the file system. Provide UEX exeption on failure.
|
%% @doc write a file to the file system. Provide UEX exeption on failure.
|
||||||
-spec write(FileName::string(), Contents::string()) -> ok.
|
-spec write(FileName::file:filename(), Contents::string()) -> ok.
|
||||||
write(FileName, Contents) ->
|
write(FileName, Contents) ->
|
||||||
case file:write_file(FileName, Contents) of
|
case file:write_file(FileName, Contents) of
|
||||||
ok ->
|
ok ->
|
||||||
|
@ -187,13 +185,13 @@ write(FileName, Contents) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @doc write a term out to a file so that it can be consulted later.
|
%% @doc write a term out to a file so that it can be consulted later.
|
||||||
-spec write_term(string(), term()) -> ok.
|
-spec write_term(file:filename(), term()) -> ok.
|
||||||
write_term(FileName, Term) ->
|
write_term(FileName, Term) ->
|
||||||
write(FileName, lists:flatten(io_lib:fwrite("~p. ", [Term]))).
|
write(FileName, lists:flatten(io_lib:fwrite("~p. ", [Term]))).
|
||||||
|
|
||||||
%% @doc Finds files and directories that match the regexp supplied in
|
%% @doc Finds files and directories that match the regexp supplied in
|
||||||
%% the TargetPattern regexp.
|
%% the TargetPattern regexp.
|
||||||
-spec find(FromDir::path(), TargetPattern::string()) -> [path()].
|
-spec find(FromDir::file:name(), TargetPattern::string()) -> [file:name()].
|
||||||
find([], _) ->
|
find([], _) ->
|
||||||
[];
|
[];
|
||||||
find(FromDir, TargetPattern) ->
|
find(FromDir, TargetPattern) ->
|
||||||
|
@ -214,7 +212,7 @@ find(FromDir, TargetPattern) ->
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Internal Functions
|
%%% Internal Functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
-spec find_in_subdirs(path(), string()) -> [path()].
|
-spec find_in_subdirs(file:name(), string()) -> [file:name()].
|
||||||
find_in_subdirs(FromDir, TargetPattern) ->
|
find_in_subdirs(FromDir, TargetPattern) ->
|
||||||
lists:foldl(fun(CheckFromDir, Acc)
|
lists:foldl(fun(CheckFromDir, Acc)
|
||||||
when CheckFromDir == FromDir ->
|
when CheckFromDir == FromDir ->
|
||||||
|
@ -228,14 +226,14 @@ find_in_subdirs(FromDir, TargetPattern) ->
|
||||||
[],
|
[],
|
||||||
filelib:wildcard(filename:join(FromDir, "*"))).
|
filelib:wildcard(filename:join(FromDir, "*"))).
|
||||||
|
|
||||||
-spec ec_file_remove(path(), [{atom(), any()}]) -> ok.
|
-spec ec_file_remove(file:name(), [option()]) -> ok | {error, Reason::any()}.
|
||||||
ec_file_remove(Path, Options) ->
|
ec_file_remove(Path, Options) ->
|
||||||
case lists:member(recursive, Options) of
|
case lists:member(recursive, Options) of
|
||||||
false -> file:delete(Path);
|
false -> file:delete(Path);
|
||||||
true -> remove_recursive(Path, Options)
|
true -> remove_recursive(Path, Options)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec remove_recursive(path(), Options::list()) -> ok.
|
-spec remove_recursive(file:name(), Options::list()) -> ok.
|
||||||
remove_recursive(Path, Options) ->
|
remove_recursive(Path, Options) ->
|
||||||
case filelib:is_dir(Path) of
|
case filelib:is_dir(Path) of
|
||||||
false ->
|
false ->
|
||||||
|
@ -247,7 +245,7 @@ remove_recursive(Path, Options) ->
|
||||||
ok = file:del_dir(Path)
|
ok = file:del_dir(Path)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec tmp() -> path().
|
-spec tmp() -> file:name().
|
||||||
tmp() ->
|
tmp() ->
|
||||||
case erlang:system_info(system_architecture) of
|
case erlang:system_info(system_architecture) of
|
||||||
"win32" ->
|
"win32" ->
|
||||||
|
@ -257,7 +255,7 @@ tmp() ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Copy the subfiles of the From directory to the to directory.
|
%% Copy the subfiles of the From directory to the to directory.
|
||||||
-spec copy_subfiles(path(), path(), [option()]) -> ok.
|
-spec copy_subfiles(file:name(), file:name(), [option()]) -> void().
|
||||||
copy_subfiles(From, To, Options) ->
|
copy_subfiles(From, To, Options) ->
|
||||||
Fun =
|
Fun =
|
||||||
fun(ChildFrom) ->
|
fun(ChildFrom) ->
|
||||||
|
@ -266,13 +264,13 @@ copy_subfiles(From, To, Options) ->
|
||||||
end,
|
end,
|
||||||
lists:foreach(Fun, filelib:wildcard(filename:join(From, "*"))).
|
lists:foreach(Fun, filelib:wildcard(filename:join(From, "*"))).
|
||||||
|
|
||||||
-spec ec_file_copy(path(), path()) -> ok.
|
-spec ec_file_copy(file:name(), file:name()) -> ok.
|
||||||
ec_file_copy(From, To) ->
|
ec_file_copy(From, To) ->
|
||||||
{ok, _} = file:copy(From, To),
|
{ok, _} = file:copy(From, To),
|
||||||
{ok, FileInfo} = file:read_file_info(From),
|
{ok, FileInfo} = file:read_file_info(From),
|
||||||
ok = file:write_file_info(To, FileInfo).
|
ok = file:write_file_info(To, FileInfo).
|
||||||
|
|
||||||
-spec make_dir_if_dir(path()) -> ok.
|
-spec make_dir_if_dir(file:name()) -> ok.
|
||||||
make_dir_if_dir(File) ->
|
make_dir_if_dir(File) ->
|
||||||
case filelib:is_dir(File) of
|
case filelib:is_dir(File) of
|
||||||
true -> ok;
|
true -> ok;
|
||||||
|
@ -356,5 +354,4 @@ find_test() ->
|
||||||
find(BaseDir, "file[a-z]+\$")),
|
find(BaseDir, "file[a-z]+\$")),
|
||||||
remove(BaseDir, [recursive]).
|
remove(BaseDir, [recursive]).
|
||||||
|
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
|
|
@ -30,7 +30,9 @@
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Types
|
%%% Types
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
-opaque dictionary(K, V) :: {non_neg_integer(), ec_gb_tree_node(K, V)}.
|
%% This should be opaque, but that kills dialyzer so for now we export it
|
||||||
|
%% however you should not rely on the internal representation here
|
||||||
|
-type dictionary(K, V) :: {non_neg_integer(), ec_gb_tree_node(K, V)}.
|
||||||
|
|
||||||
-type ec_gb_tree_node(K, V) :: 'nil' | {K, V,
|
-type ec_gb_tree_node(K, V) :: 'nil' | {K, V,
|
||||||
ec_gb_tree_node(K, V),
|
ec_gb_tree_node(K, V),
|
||||||
|
@ -124,7 +126,7 @@ has_value(Value, Data) ->
|
||||||
%% @doc return the current number of key value pairs in the dictionary
|
%% @doc return the current number of key value pairs in the dictionary
|
||||||
%%
|
%%
|
||||||
%% @param Object the object return the size for.
|
%% @param Object the object return the size for.
|
||||||
-spec size(Object::dictionary(_K, _V)) -> integer().
|
-spec size(Object::dictionary(_K, _V)) -> non_neg_integer().
|
||||||
size(Data) ->
|
size(Data) ->
|
||||||
gb_trees:size(Data).
|
gb_trees:size(Data).
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
%% the third value is the element passed to the function. The purpose
|
%% the third value is the element passed to the function. The purpose
|
||||||
%% of this is to allow a list to be searched where some internal state
|
%% of this is to allow a list to be searched where some internal state
|
||||||
%% is important while the input element is not.
|
%% is important while the input element is not.
|
||||||
-spec search(fun(), list()) -> {ok, Result::term(), Element::term()}.
|
-spec search(fun(), list()) -> {ok, Result::term(), Element::term()} | not_found.
|
||||||
search(Fun, [H|T]) ->
|
search(Fun, [H|T]) ->
|
||||||
case Fun(H) of
|
case Fun(H) of
|
||||||
{ok, Value} ->
|
{ok, Value} ->
|
||||||
|
|
|
@ -31,7 +31,9 @@
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Types
|
%%% Types
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
-opaque dictionary(K, V) :: [{K, V}].
|
%% This should be opaque, but that kills dialyzer so for now we export it
|
||||||
|
%% however you should not rely on the internal representation here
|
||||||
|
-type dictionary(K, V) :: [{K, V}].
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
|
@ -88,7 +90,7 @@ has_value(Value, Data) ->
|
||||||
false,
|
false,
|
||||||
Data).
|
Data).
|
||||||
|
|
||||||
-spec size(Object::dictionary(_K, _V)) -> integer().
|
-spec size(Object::dictionary(_K, _V)) -> non_neg_integer().
|
||||||
size(Data) ->
|
size(Data) ->
|
||||||
orddict:size(Data).
|
orddict:size(Data).
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,13 @@
|
||||||
filter/2,
|
filter/2,
|
||||||
filter/3]).
|
filter/3]).
|
||||||
|
|
||||||
|
-export_type([thunk/0]).
|
||||||
|
|
||||||
|
%%=============================================================================
|
||||||
|
%% Types
|
||||||
|
%%=============================================================================
|
||||||
|
-type thunk() :: fun((any()) -> any()).
|
||||||
|
|
||||||
%%=============================================================================
|
%%=============================================================================
|
||||||
%% Public API
|
%% Public API
|
||||||
%%=============================================================================
|
%%=============================================================================
|
||||||
|
@ -25,7 +32,7 @@
|
||||||
map(Fun, List) ->
|
map(Fun, List) ->
|
||||||
map(Fun, List, infinity).
|
map(Fun, List, infinity).
|
||||||
|
|
||||||
-spec map(fun(), [any()], non_neg_integer()) -> [any()].
|
-spec map(thunk(), [any()], timeout() | infinity) -> [any()].
|
||||||
map(Fun, List, Timeout) ->
|
map(Fun, List, Timeout) ->
|
||||||
run_list_fun_in_parallel(map, Fun, List, Timeout).
|
run_list_fun_in_parallel(map, Fun, List, Timeout).
|
||||||
|
|
||||||
|
@ -43,29 +50,29 @@ map(Fun, List, Timeout) ->
|
||||||
%% 2> ftmap(fun(N) -> factorial(N) end, [1, 2, 1000000, "not num"], 100)
|
%% 2> ftmap(fun(N) -> factorial(N) end, [1, 2, 1000000, "not num"], 100)
|
||||||
%% [{value, 1}, {value, 2}, timeout, {badmatch, ...}]
|
%% [{value, 1}, {value, 2}, timeout, {badmatch, ...}]
|
||||||
%% </pre>
|
%% </pre>
|
||||||
-spec ftmap(fun(), [any()]) -> [{value, any()} | any()].
|
-spec ftmap(thunk(), [any()]) -> [{value, any()} | any()].
|
||||||
ftmap(Fun, List) ->
|
ftmap(Fun, List) ->
|
||||||
ftmap(Fun, List, infinity).
|
ftmap(Fun, List, infinity).
|
||||||
|
|
||||||
-spec ftmap(fun(), [any()], non_neg_integer()) -> [{value, any()} | any()].
|
-spec ftmap(thunk(), [any()], timeout() | infinity) -> [{value, any()} | any()].
|
||||||
ftmap(Fun, List, Timeout) ->
|
ftmap(Fun, List, Timeout) ->
|
||||||
run_list_fun_in_parallel(ftmap, Fun, List, Timeout).
|
run_list_fun_in_parallel(ftmap, Fun, List, Timeout).
|
||||||
|
|
||||||
%% @doc Returns a list of the elements in the supplied list which
|
%% @doc Returns a list of the elements in the supplied list which
|
||||||
%% the function Fun returns true. A timeout is optional. In the
|
%% the function Fun returns true. A timeout is optional. In the
|
||||||
%% event of a timeout the filter operation fails.
|
%% event of a timeout the filter operation fails.
|
||||||
-spec filter(fun(), [any()]) -> [any()].
|
-spec filter(thunk(), [any()]) -> [any()].
|
||||||
filter(Fun, List) ->
|
filter(Fun, List) ->
|
||||||
filter(Fun, List, infinity).
|
filter(Fun, List, infinity).
|
||||||
|
|
||||||
-spec filter(fun(), [any()], integer()) -> [any()].
|
-spec filter(thunk(), [any()], timeout() | infinity) -> [any()].
|
||||||
filter(Fun, List, Timeout) ->
|
filter(Fun, List, Timeout) ->
|
||||||
run_list_fun_in_parallel(filter, Fun, List, Timeout).
|
run_list_fun_in_parallel(filter, Fun, List, Timeout).
|
||||||
|
|
||||||
%%=============================================================================
|
%%=============================================================================
|
||||||
%% Internal API
|
%% Internal API
|
||||||
%%=============================================================================
|
%%=============================================================================
|
||||||
-spec run_list_fun_in_parallel(atom(), fun(), [any()], integer()) -> [any()].
|
-spec run_list_fun_in_parallel(atom(), thunk(), [any()], timeout() | infinity) -> [any()].
|
||||||
run_list_fun_in_parallel(ListFun, Fun, List, Timeout) ->
|
run_list_fun_in_parallel(ListFun, Fun, List, Timeout) ->
|
||||||
LocalPid = self(),
|
LocalPid = self(),
|
||||||
Pids =
|
Pids =
|
||||||
|
@ -79,7 +86,7 @@ run_list_fun_in_parallel(ListFun, Fun, List, Timeout) ->
|
||||||
end, List),
|
end, List),
|
||||||
gather(ListFun, Pids).
|
gather(ListFun, Pids).
|
||||||
|
|
||||||
-spec wait(pid(), fun(), any(), integer()) -> any().
|
-spec wait(pid(), thunk(), any(), timeout() | infinity) -> any().
|
||||||
wait(Parent, Fun, E, Timeout) ->
|
wait(Parent, Fun, E, Timeout) ->
|
||||||
WaitPid = self(),
|
WaitPid = self(),
|
||||||
Child = spawn(fun() ->
|
Child = spawn(fun() ->
|
||||||
|
@ -88,7 +95,7 @@ wait(Parent, Fun, E, Timeout) ->
|
||||||
|
|
||||||
wait(Parent, Child, Timeout).
|
wait(Parent, Child, Timeout).
|
||||||
|
|
||||||
-spec wait(pid(), pid(), integer()) -> any().
|
-spec wait(pid(), pid(), timeout() | infinity) -> any().
|
||||||
wait(Parent, Child, Timeout) ->
|
wait(Parent, Child, Timeout) ->
|
||||||
receive
|
receive
|
||||||
{Child, Ret} ->
|
{Child, Ret} ->
|
||||||
|
@ -146,7 +153,7 @@ filter_gather([{Pid, E} | Rest]) ->
|
||||||
filter_gather([]) ->
|
filter_gather([]) ->
|
||||||
[].
|
[].
|
||||||
|
|
||||||
-spec do_f(pid(), fun(), any()) -> no_return().
|
-spec do_f(pid(), thunk(), any()) -> no_return().
|
||||||
do_f(Parent, F, E) ->
|
do_f(Parent, F, E) ->
|
||||||
try
|
try
|
||||||
Result = F(E),
|
Result = F(E),
|
||||||
|
|
|
@ -68,8 +68,9 @@
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% Types
|
%%% Types
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
%% This should be opaque, but that kills dialyzer so for now we export it
|
||||||
-opaque dictionary(K, V) :: empty | {color(),
|
%% however you should not rely on the internal representation here
|
||||||
|
-type dictionary(K, V) :: empty | {color(),
|
||||||
dictionary(K, V),
|
dictionary(K, V),
|
||||||
ec_dictionary:key(K),
|
ec_dictionary:key(K),
|
||||||
ec_dictionary:value(V),
|
ec_dictionary:value(V),
|
||||||
|
@ -116,7 +117,7 @@ get(K, Default, {_, _, K1, _, Right}) when K > K1 ->
|
||||||
get(_, _, {_, _, _, Val, _}) ->
|
get(_, _, {_, _, _, Val, _}) ->
|
||||||
Val.
|
Val.
|
||||||
|
|
||||||
-spec add(ec_dicitonary:key(K), ec_dictionary:value(V),
|
-spec add(ec_dictionary:key(K), ec_dictionary:value(V),
|
||||||
dictionary(K, V)) -> dictionary(K, V).
|
dictionary(K, V)) -> dictionary(K, V).
|
||||||
add(Key, Value, Dict) ->
|
add(Key, Value, Dict) ->
|
||||||
{_, L, K1, V1, R} = add1(Key, Value, Dict),
|
{_, L, K1, V1, R} = add1(Key, Value, Dict),
|
||||||
|
@ -133,7 +134,7 @@ has_value(Value, Dict) ->
|
||||||
end,
|
end,
|
||||||
false, Dict).
|
false, Dict).
|
||||||
|
|
||||||
-spec size(dictionary(_K, _V)) -> integer().
|
-spec size(dictionary(_K, _V)) -> non_neg_integer().
|
||||||
size(T) ->
|
size(T) ->
|
||||||
size1(T).
|
size1(T).
|
||||||
|
|
||||||
|
@ -227,7 +228,7 @@ erase_aux(K, {r, A, Xk, Xv, B}) ->
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec erase_min(dictionary(K, V)) ->
|
-spec erase_min(dictionary(K, V)) ->
|
||||||
{dictionary(K, V), {ec_dictionary:key(K), ec_dictionary:value(V)}, boolean}.
|
{dictionary(K, V), {ec_dictionary:key(K), ec_dictionary:value(V)}, boolean()}.
|
||||||
erase_min({b, empty, Xk, Xv, empty}) ->
|
erase_min({b, empty, Xk, Xv, empty}) ->
|
||||||
{empty, {Xk, Xv}, true};
|
{empty, {Xk, Xv}, true};
|
||||||
erase_min({b, empty, Xk, Xv, {r, A, Yk, Yv, B}}) ->
|
erase_min({b, empty, Xk, Xv, {r, A, Yk, Yv, B}}) ->
|
||||||
|
@ -274,7 +275,8 @@ unbalright(b, A, Xk, Xv,
|
||||||
D},
|
D},
|
||||||
false}.
|
false}.
|
||||||
|
|
||||||
-spec fold(fun(), dictionary(K, V), dictionary(K, V)) -> dictionary(K, V).
|
-spec fold(fun((ec_dictionary:key(K), ec_dictionary:value(V), any()) -> any()),
|
||||||
|
any(), dictionary(K, V)) -> any().
|
||||||
fold(_, Acc, empty) -> Acc;
|
fold(_, Acc, empty) -> Acc;
|
||||||
fold(F, Acc, {_, A, Xk, Xv, B}) ->
|
fold(F, Acc, {_, A, Xk, Xv, B}) ->
|
||||||
fold(F, F(Xk, Xv, fold(F, Acc, B)), A).
|
fold(F, F(Xk, Xv, fold(F, Acc, B)), A).
|
||||||
|
@ -295,7 +297,7 @@ to_list({_, A, Xk, Xv, B}, List) ->
|
||||||
|
|
||||||
%% Balance a tree afer (possibly) adding a node to the left/right.
|
%% Balance a tree afer (possibly) adding a node to the left/right.
|
||||||
-spec lbalance(color(), dictionary(K, V),
|
-spec lbalance(color(), dictionary(K, V),
|
||||||
ec_dictinary:key(K), ec_dictionary:value(V),
|
ec_dictionary:key(K), ec_dictionary:value(V),
|
||||||
dictionary(K, V)) ->
|
dictionary(K, V)) ->
|
||||||
dictionary(K, V).
|
dictionary(K, V).
|
||||||
lbalance(b, {r, {r, A, Xk, Xv, B}, Yk, Yv, C}, Zk, Zv,
|
lbalance(b, {r, {r, A, Xk, Xv, B}, Yk, Yv, C}, Zk, Zv,
|
||||||
|
@ -307,7 +309,7 @@ lbalance(b, {r, A, Xk, Xv, {r, B, Yk, Yv, C}}, Zk, Zv,
|
||||||
lbalance(C, A, Xk, Xv, B) -> {C, A, Xk, Xv, B}.
|
lbalance(C, A, Xk, Xv, B) -> {C, A, Xk, Xv, B}.
|
||||||
|
|
||||||
-spec rbalance(color(), dictionary(K, V),
|
-spec rbalance(color(), dictionary(K, V),
|
||||||
ec_dictinary:key(K), ec_dictionary:value(V),
|
ec_dictionary:key(K), ec_dictionary:value(V),
|
||||||
dictionary(K, V)) ->
|
dictionary(K, V)) ->
|
||||||
dictionary(K, V).
|
dictionary(K, V).
|
||||||
rbalance(b, A, Xk, Xv,
|
rbalance(b, A, Xk, Xv,
|
||||||
|
|
|
@ -20,11 +20,13 @@
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
-type semvar() :: string().
|
-type semvar() :: string().
|
||||||
-type parsed_semvar() :: {MajorVsn::string(),
|
-type parsed_semvar() :: {MajorVsn::integer(),
|
||||||
MinorVsn::string(),
|
MinorVsn::integer(),
|
||||||
PatchVsn::string(),
|
PatchVsn::integer(),
|
||||||
PathString::string()}.
|
PathString::string()}.
|
||||||
|
|
||||||
|
-type semver_tokens() :: {string(), string(), string(), string()}.
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
%%% API
|
%%% API
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
@ -41,7 +43,7 @@ compare(VsnA, VsnB) ->
|
||||||
%%% Internal Functions
|
%%% Internal Functions
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
|
|
||||||
-spec tokens(semvar()) -> parsed_semvar().
|
-spec tokens(semvar()) -> semver_tokens().
|
||||||
tokens(Vsn) ->
|
tokens(Vsn) ->
|
||||||
[MajorVsn, MinorVsn, RawPatch] = string:tokens(Vsn, "."),
|
[MajorVsn, MinorVsn, RawPatch] = string:tokens(Vsn, "."),
|
||||||
{PatchVsn, PatchString} = split_patch(RawPatch),
|
{PatchVsn, PatchString} = split_patch(RawPatch),
|
||||||
|
@ -62,7 +64,7 @@ split_patch([Dig|T], {PatchVsn, PatchStr}) when Dig >= $0 andalso Dig =< $9 ->
|
||||||
split_patch(PatchStr, {PatchVsn, ""}) ->
|
split_patch(PatchStr, {PatchVsn, ""}) ->
|
||||||
{PatchVsn, PatchStr}.
|
{PatchVsn, PatchStr}.
|
||||||
|
|
||||||
-spec compare_toks(parsed_semvar(), parsed_semvar()) -> boolean().
|
-spec compare_toks(semver_tokens(), semver_tokens()) -> boolean().
|
||||||
compare_toks({MajA, MinA, PVA, PSA}, {MajB, MinB, PVB, PSB}) ->
|
compare_toks({MajA, MinA, PVA, PSA}, {MajB, MinB, PVB, PSB}) ->
|
||||||
compare_toks2({to_int(MajA), to_int(MinA), to_int(PVA), PSA},
|
compare_toks2({to_int(MajA), to_int(MinA), to_int(PVA), PSA},
|
||||||
{to_int(MajB), to_int(MinB), to_int(PVB), PSB}).
|
{to_int(MajB), to_int(MinB), to_int(PVB), PSB}).
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
%%============================================================================
|
%%============================================================================
|
||||||
-type prompt() :: string().
|
-type prompt() :: string().
|
||||||
-type type() :: boolean | number | string.
|
-type type() :: boolean | number | string.
|
||||||
-type supported() :: string() | boolean() | number().
|
-type supported() :: boolean() | number() | string().
|
||||||
|
|
||||||
%%============================================================================
|
%%============================================================================
|
||||||
%% API
|
%% API
|
||||||
|
@ -100,8 +100,11 @@ ask_default(Prompt, string, Default) ->
|
||||||
%% between min and max.
|
%% between min and max.
|
||||||
-spec ask(prompt(), number(), number()) -> number().
|
-spec ask(prompt(), number(), number()) -> number().
|
||||||
ask(Prompt, Min, Max)
|
ask(Prompt, Min, Max)
|
||||||
when is_list(Prompt), is_number(Min), is_number(Max) ->
|
when erlang:is_list(Prompt),
|
||||||
Res = ask(Prompt, fun get_integer/1, none),
|
erlang:is_number(Min),
|
||||||
|
erlang:is_number(Max),
|
||||||
|
Min =< Max ->
|
||||||
|
Res = ask_convert(Prompt, fun get_integer/1, number, none),
|
||||||
case (Res >= Min andalso Res =< Max) of
|
case (Res >= Min andalso Res =< Max) of
|
||||||
true ->
|
true ->
|
||||||
Res;
|
Res;
|
||||||
|
@ -115,14 +118,16 @@ ask(Prompt, Min, Max)
|
||||||
%% ============================================================================
|
%% ============================================================================
|
||||||
%% @doc Actually does the work of asking, checking result and
|
%% @doc Actually does the work of asking, checking result and
|
||||||
%% translating result into the requested format.
|
%% translating result into the requested format.
|
||||||
-spec ask_convert(prompt(), fun(), type(), supported()) -> supported().
|
-spec ask_convert(prompt(), fun((any()) -> any()), type(), supported() | none) -> supported().
|
||||||
ask_convert(Prompt, TransFun, Type, Default) ->
|
ask_convert(Prompt, TransFun, Type, Default) ->
|
||||||
NewPrompt = Prompt ++ case Default of
|
NewPrompt =
|
||||||
|
erlang:binary_to_list(erlang:iolist_to_binary([Prompt,
|
||||||
|
case Default of
|
||||||
none ->
|
none ->
|
||||||
[];
|
[];
|
||||||
Default ->
|
Default ->
|
||||||
" (" ++ sin_utils:term_to_list(Default) ++ ")"
|
[" (", io_lib:format("~p", [Default]) , ")"]
|
||||||
end ++ "> ",
|
end, "> "])),
|
||||||
Data = string:strip(string:strip(io:get_line(NewPrompt)), both, $\n),
|
Data = string:strip(string:strip(io:get_line(NewPrompt)), both, $\n),
|
||||||
Ret = TransFun(Data),
|
Ret = TransFun(Data),
|
||||||
case Ret of
|
case Ret of
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue