All sorts of things.
This commit is contained in:
parent
146bb62380
commit
fece77ec72
7 changed files with 138 additions and 56 deletions
146
Makefile
146
Makefile
|
@ -1,58 +1,116 @@
|
||||||
TARGET= hamt
|
# Copyright 2012 Erlware, LLC. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# This file is provided to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations under
|
||||||
|
# the License.
|
||||||
|
|
||||||
REBAR= /usr/bin/env rebar
|
# Source: https://gist.github.com/ericbmerritt/5706091
|
||||||
ERL= /usr/bin/env erl
|
|
||||||
DIALYZER= /usr/bin/env dialyzer
|
|
||||||
REBAR= /usr/bin/env rebar
|
ERLFLAGS= -pa $(CURDIR)/.eunit -pa $(CURDIR)/ebin -pa $(CURDIR)/deps/*/ebin
|
||||||
ifdef suites
|
|
||||||
SUITE_OPTION := suites=$(suites)
|
DEPS_PLT=$(CURDIR)/.deps_plt
|
||||||
|
DEPS=erts kernel stdlib
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Verify that the programs we need to run are installed on this system
|
||||||
|
# =============================================================================
|
||||||
|
ERL = $(shell which erl)
|
||||||
|
|
||||||
|
ifeq ($(ERL),)
|
||||||
|
$(error "Erlang not available on this system")
|
||||||
endif
|
endif
|
||||||
ifdef tests
|
|
||||||
TESTS_OPTION := tests=$(tests)
|
REBAR=$(shell which rebar)
|
||||||
|
|
||||||
|
ifeq ($(REBAR),)
|
||||||
|
$(error "Rebar not available on this system")
|
||||||
endif
|
endif
|
||||||
EUNIT_OPTIONS := $(SUITE_OPTION) $(TESTS_OPTION)
|
|
||||||
|
|
||||||
.PHONY: deps test
|
DIALYZER=$(shell which dialyzer)
|
||||||
|
|
||||||
all: deps compile
|
ifeq ($(DIALYZER),)
|
||||||
|
$(error "Dialyzer not available on this system")
|
||||||
|
endif
|
||||||
|
|
||||||
|
TYPER=$(shell which typer)
|
||||||
|
|
||||||
|
ifeq ($(TYPER),)
|
||||||
|
$(error "Typer not available on this system")
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all compile doc clean test dialyzer typer shell distclean pdf \
|
||||||
|
update-deps clean-common-test-data rebuild
|
||||||
|
|
||||||
|
all: deps compile dialyzer test
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Rules to build the system
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
deps:
|
deps:
|
||||||
$(REBAR) get-deps
|
$(REBAR) get-deps
|
||||||
|
|
||||||
compile: deps
|
|
||||||
$(REBAR) compile
|
$(REBAR) compile
|
||||||
|
|
||||||
|
update-deps:
|
||||||
|
$(REBAR) update-deps
|
||||||
|
$(REBAR) compile
|
||||||
|
|
||||||
|
compile:
|
||||||
|
$(REBAR) skip_deps=true compile
|
||||||
|
|
||||||
|
doc:
|
||||||
|
$(REBAR) skip_deps=true doc
|
||||||
|
|
||||||
|
eunit: compile clean-common-test-data
|
||||||
|
$(REBAR) skip_deps=true eunit
|
||||||
|
|
||||||
|
test: compile eunit
|
||||||
|
|
||||||
|
$(DEPS_PLT):
|
||||||
|
@echo Building local plt at $(DEPS_PLT)
|
||||||
|
@echo
|
||||||
|
$(DIALYZER) --output_plt $(DEPS_PLT) --build_plt \
|
||||||
|
--apps $(DEPS) -r deps
|
||||||
|
|
||||||
|
dialyzer: $(DEPS_PLT)
|
||||||
|
$(DIALYZER) --fullpath --plt $(DEPS_PLT) -Wrace_conditions -r ./ebin
|
||||||
|
|
||||||
|
typer:
|
||||||
|
$(TYPER) --plt $(DEPS_PLT) -r ./src
|
||||||
|
|
||||||
|
xref:
|
||||||
|
$(REBAR) xref skip_deps=true
|
||||||
|
|
||||||
|
# You often want *rebuilt* rebar tests to be available to the shell you have to
|
||||||
|
# call eunit (to get the tests rebuilt). However, eunit runs the tests, which
|
||||||
|
# probably fails (thats probably why You want them in the shell). This
|
||||||
|
# (prefixing the command with "-") runs eunit but tells make to ignore the
|
||||||
|
# result.
|
||||||
|
shell: deps compile
|
||||||
|
- @$(REBAR) skip_deps=true eunit
|
||||||
|
@$(ERL) $(ERLFLAGS)
|
||||||
|
|
||||||
|
pdf:
|
||||||
|
pandoc README.md -o README.pdf
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(REBAR) clean
|
- c_src/build_deps.sh clean
|
||||||
|
- rm -rf $(CURDIR)/test/*.beam
|
||||||
|
- rm -rf $(CURDIR)/logs
|
||||||
|
- rm -rf $(CURDIR)/ebin
|
||||||
|
$(REBAR) skip_deps=true clean
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
$(REBAR) delete-deps
|
- rm -rf $(DEPS_PLT)
|
||||||
|
- rm -rvf $(CURDIR)/deps
|
||||||
|
|
||||||
eunit: test
|
rebuild: distclean deps compile escript dialyzer test
|
||||||
|
|
||||||
test: compile
|
|
||||||
$(REBAR) skip_deps=true $(EUNIT_OPTIONS) eunit
|
|
||||||
|
|
||||||
console: compile
|
|
||||||
erl -pa ebin deps/*/ebin
|
|
||||||
|
|
||||||
plt: compile
|
|
||||||
@$(DIALYZER) --build_plt --output_plt .$(TARGET).plt \
|
|
||||||
-pa deps/plain_fsm/ebin \
|
|
||||||
deps/plain_fsm/ebin \
|
|
||||||
--apps kernel stdlib
|
|
||||||
|
|
||||||
analyze: compile
|
|
||||||
$(DIALYZER) --plt .$(TARGET).plt \
|
|
||||||
-pa deps/plain_fsm/ebin \
|
|
||||||
-pa deps/ebloom/ebin \
|
|
||||||
ebin
|
|
||||||
|
|
||||||
repl:
|
|
||||||
$(ERL) -pz deps/*/ebin -pa ebin
|
|
||||||
|
|
||||||
eunit-repl:
|
|
||||||
erl -pa .eunit -pz deps/*/ebin -pz ebin -exec 'cd(".eunit").'
|
|
||||||
|
|
||||||
gdb-eunit-repl:
|
|
||||||
USE_GDB=1 erl -pa .eunit -pz deps/*/ebin -pz ebin -exec 'cd(".eunit").'
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
%%% -*- mode: erlang -*-
|
%%% -*- mode: erlang -*-
|
||||||
|
|
||||||
{require_otp_vsn, "R15"}.
|
{require_otp_vsn, "R1[56]"}.
|
||||||
|
|
||||||
{cover_enabled, true}.
|
{cover_enabled, true}.
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@
|
||||||
warn_obsolete_guard,
|
warn_obsolete_guard,
|
||||||
warn_export_vars,
|
warn_export_vars,
|
||||||
warn_exported_vars,
|
warn_exported_vars,
|
||||||
warn_untyped_record
|
warn_untyped_record,
|
||||||
|
inline, native, {hipe, [o2]}
|
||||||
%warn_missing_spec,
|
%warn_missing_spec,
|
||||||
%strict_validation
|
%strict_validation
|
||||||
%{parse_transform, lager_transform},
|
%{parse_transform, lager_transform},
|
||||||
|
|
|
@ -33,6 +33,11 @@ count(X, Acc) -> count((X band (X - 1)), (Acc + 1)).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
%-ifdef(WORKING_METHOD_2). % Works well enough
|
%-ifdef(WORKING_METHOD_2). % Works well enough
|
||||||
|
-spec count(non_neg_integer()) -> char().
|
||||||
|
-spec c1(pos_integer()) -> integer().
|
||||||
|
-spec c2(pos_integer()) -> non_neg_integer().
|
||||||
|
-spec c3(pos_integer()) -> non_neg_integer().
|
||||||
|
-spec c4(pos_integer()) -> non_neg_integer().
|
||||||
count(0) -> 0;
|
count(0) -> 0;
|
||||||
count(X)
|
count(X)
|
||||||
when is_integer(X), X > 0, X < 16#FFFFFFFF ->
|
when is_integer(X), X > 0, X < 16#FFFFFFFF ->
|
||||||
|
|
23
src/hamt.erl
23
src/hamt.erl
|
@ -4,16 +4,15 @@
|
||||||
%%
|
%%
|
||||||
%% Copyright (C) 2013 Gregory Burd. All Rights Reserved.
|
%% Copyright (C) 2013 Gregory Burd. All Rights Reserved.
|
||||||
%%
|
%%
|
||||||
%% The contents of this file are subject to the Mozilla Public License,
|
%% The contents of this file are subject to the Mozilla Public License, Version
|
||||||
%% Version 2, (the "License"); you may not use this file except in
|
%% 2, (the "License"); you may not use this file except in compliance with the
|
||||||
%% compliance with the License. You should have received a copy of the
|
%% License. You should have received a copy of the Mozilla Public License along
|
||||||
%% Mozilla Public License along with this software. If not, it can be
|
%% with this software. If not, it can be retrieved online at
|
||||||
%% retrieved online at http://www.mozilla.org/MPL/
|
%% http://www.mozilla.org/MPL/
|
||||||
%%
|
%%
|
||||||
%% Software distributed under the License is distributed on an "AS IS"
|
%% Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
%% WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
||||||
%% the License for the specific language governing rights and limitations
|
%% the specific language governing rights and limitations under the License.
|
||||||
%% under the License.
|
|
||||||
%%
|
%%
|
||||||
%% %CopyrightEnd%
|
%% %CopyrightEnd%
|
||||||
%%
|
%%
|
||||||
|
@ -81,6 +80,7 @@
|
||||||
-ifdef(EQC).
|
-ifdef(EQC).
|
||||||
-include_lib("eqc/include/eqc.hrl").
|
-include_lib("eqc/include/eqc.hrl").
|
||||||
-include_lib("eqc/include/eqc_fsm.hrl").
|
-include_lib("eqc/include/eqc_fsm.hrl").
|
||||||
|
-define(QC_OUT(P), eqc:on_output(fun(Str, Args) -> io:format(user, Str, Args) end, P)).
|
||||||
-endif.
|
-endif.
|
||||||
-compile(export_all).
|
-compile(export_all).
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
@ -165,6 +165,7 @@ get(Key, {hamt, HashSize, {cnode, _Bitmap, _Nodes}=CN}) ->
|
||||||
{error, not_found}
|
{error, not_found}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec get_1(non_neg_integer(),_,non_neg_integer(),30 | 125 | 160) -> 'none' | {_,_}.
|
||||||
get_1(Hash, {cnode, Bitmap, Nodes}, L, M) when L =< M ->
|
get_1(Hash, {cnode, Bitmap, Nodes}, L, M) when L =< M ->
|
||||||
Bit = bitpos(Hash, L),
|
Bit = bitpos(Hash, L),
|
||||||
case exists(Bit, Bitmap) of
|
case exists(Bit, Bitmap) of
|
||||||
|
@ -181,6 +182,7 @@ get_1(_Hash, {lnode, List}, _L, _M)
|
||||||
when is_list(List) ->
|
when is_list(List) ->
|
||||||
{list, List}.
|
{list, List}.
|
||||||
|
|
||||||
|
-spec get_2(_,maybe_improper_list()) -> 'none' | {_,_}.
|
||||||
get_2(_Key, []) ->
|
get_2(_Key, []) ->
|
||||||
none;
|
none;
|
||||||
get_2(Key, [{Key, Value} | _Rest]) ->
|
get_2(Key, [{Key, Value} | _Rest]) ->
|
||||||
|
@ -215,6 +217,7 @@ put(Key, Value, {hamt, HashSize, nil}) ->
|
||||||
put(Key, Value, {hamt, HashSize, Node}) ->
|
put(Key, Value, {hamt, HashSize, Node}) ->
|
||||||
{hamt, HashSize, put_1(hash(HashSize, Key), Key, Value, Node, 0, max_depth(HashSize))}.
|
{hamt, HashSize, put_1(hash(HashSize, Key), Key, Value, Node, 0, max_depth(HashSize))}.
|
||||||
|
|
||||||
|
-spec put_1(non_neg_integer(),_,_,{'lnode',maybe_improper_list()} | {'cnode',integer(),[any()]} | {'snode',_,_},non_neg_integer(),30 | 125 | 160) -> {'lnode',nonempty_maybe_improper_list()} | {'cnode',integer(),[any(),...]} | {'snode',_,_}.
|
||||||
put_1(Hash, Key, Value, {cnode, Bitmap, Nodes}, L, M)
|
put_1(Hash, Key, Value, {cnode, Bitmap, Nodes}, L, M)
|
||||||
when L =< M ->
|
when L =< M ->
|
||||||
Bit = bitpos(Hash, L),
|
Bit = bitpos(Hash, L),
|
||||||
|
@ -230,7 +233,7 @@ put_1(_Hash, Key, Value, {snode, Key, _}, _L, _M) ->
|
||||||
{snode, Key, Value};
|
{snode, Key, Value};
|
||||||
put_1(Hash, Key, Value, {snode, SNKey, SNValue}, L, M)
|
put_1(Hash, Key, Value, {snode, SNKey, SNValue}, L, M)
|
||||||
when L =< M ->
|
when L =< M ->
|
||||||
CN = {cnode, bitpos(Hash, L), [{snode, SNKey, SNValue}]},
|
CN = {cnode, bitpos(Hash, L), [{snode, SNKey, SNValue}]}, %% TODO: wrong hash XXX
|
||||||
put_1(Hash, Key, Value, CN, L, M);
|
put_1(Hash, Key, Value, CN, L, M);
|
||||||
put_1(_Hash, Key1, Value1, {snode, Key2, Value2}, L, M)
|
put_1(_Hash, Key1, Value1, {snode, Key2, Value2}, L, M)
|
||||||
when L > M ->
|
when L > M ->
|
||||||
|
|
|
@ -9,8 +9,10 @@
|
||||||
%% Application callbacks
|
%% Application callbacks
|
||||||
%% ===================================================================
|
%% ===================================================================
|
||||||
|
|
||||||
|
-spec start(_,_) -> 'ignore' | {'error',_} | {'ok',pid()}.
|
||||||
start(_StartType, _StartArgs) ->
|
start(_StartType, _StartArgs) ->
|
||||||
hamt_sup:start_link().
|
hamt_sup:start_link().
|
||||||
|
|
||||||
|
-spec stop(_) -> 'ok'.
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
%% API functions
|
%% API functions
|
||||||
%% ===================================================================
|
%% ===================================================================
|
||||||
|
|
||||||
|
-spec start_link() -> 'ignore' | {'error',_} | {'ok',pid()}.
|
||||||
start_link() ->
|
start_link() ->
|
||||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||||
|
|
||||||
|
@ -23,5 +24,6 @@ start_link() ->
|
||||||
%% Supervisor callbacks
|
%% Supervisor callbacks
|
||||||
%% ===================================================================
|
%% ===================================================================
|
||||||
|
|
||||||
|
-spec init([]) -> {'ok', term()}.
|
||||||
init([]) ->
|
init([]) ->
|
||||||
{ok, { {one_for_one, 5, 10}, []} }.
|
{ok, { {one_for_one, 5, 10}, []} }.
|
||||||
|
|
|
@ -26,22 +26,27 @@
|
||||||
|
|
||||||
-define(MASK32, 16#FFFFFFFF).
|
-define(MASK32, 16#FFFFFFFF).
|
||||||
|
|
||||||
|
-spec rotl32(integer(),13 | 15) -> non_neg_integer().
|
||||||
rotl32(Num, R) -> ((Num bsl R) bor (Num bsr (32 - R))) band ?MASK32.
|
rotl32(Num, R) -> ((Num bsl R) bor (Num bsr (32 - R))) band ?MASK32.
|
||||||
|
|
||||||
|
-spec hash32_mmix(non_neg_integer()) -> non_neg_integer().
|
||||||
hash32_mmix(K1) ->
|
hash32_mmix(K1) ->
|
||||||
K2 = (K1 * 16#CC9E2D51) band ?MASK32,
|
K2 = (K1 * 16#CC9E2D51) band ?MASK32,
|
||||||
K3 = rotl32(K2, 15),
|
K3 = rotl32(K2, 15),
|
||||||
(K3 * 16#1B873593) band ?MASK32.
|
(K3 * 16#1B873593) band ?MASK32.
|
||||||
|
|
||||||
|
-spec hash32_fmix(integer()) -> non_neg_integer().
|
||||||
hash32_fmix(H) ->
|
hash32_fmix(H) ->
|
||||||
H2 = ((H bxor (H bsr 16)) * 16#85EBCA6B) band ?MASK32,
|
H2 = ((H bxor (H bsr 16)) * 16#85EBCA6B) band ?MASK32,
|
||||||
H3 = ((H2 bxor (H2 bsr 13)) * 16#C2B2AE35) band ?MASK32,
|
H3 = ((H2 bxor (H2 bsr 13)) * 16#C2B2AE35) band ?MASK32,
|
||||||
H3 bxor (H3 bsr 16).
|
H3 bxor (H3 bsr 16).
|
||||||
|
|
||||||
|
-spec hash32_tail_mix(non_neg_integer(),integer()) -> integer().
|
||||||
hash32_tail_mix(K1, Hash) ->
|
hash32_tail_mix(K1, Hash) ->
|
||||||
Hash bxor hash32_mmix(K1).
|
Hash bxor hash32_mmix(K1).
|
||||||
|
|
||||||
% 4-byte blocks
|
% 4-byte blocks
|
||||||
|
-spec hash32_body(binary(),_) -> non_neg_integer().
|
||||||
hash32_body(<<K1:32/little, Rest/binary>>, Hash) ->
|
hash32_body(<<K1:32/little, Rest/binary>>, Hash) ->
|
||||||
K2 = hash32_mmix(K1),
|
K2 = hash32_mmix(K1),
|
||||||
Hash2 = Hash bxor K2,
|
Hash2 = Hash bxor K2,
|
||||||
|
@ -54,15 +59,21 @@ hash32_body(<<K1:16/little>>, Hash) -> hash32_tail_mix(K1, Hash);
|
||||||
hash32_body(<<K1:24/little>>, Hash) -> hash32_tail_mix(K1, Hash);
|
hash32_body(<<K1:24/little>>, Hash) -> hash32_tail_mix(K1, Hash);
|
||||||
hash32_body(<<>>, Hash) -> Hash.
|
hash32_body(<<>>, Hash) -> Hash.
|
||||||
|
|
||||||
|
-spec hash32_impl(binary(),_) -> non_neg_integer().
|
||||||
hash32_impl(Data, Seed) ->
|
hash32_impl(Data, Seed) ->
|
||||||
Len = byte_size(Data),
|
Len = byte_size(Data),
|
||||||
hash32_fmix(hash32_body(Data, Seed) bxor Len).
|
hash32_fmix(hash32_body(Data, Seed) bxor Len).
|
||||||
|
|
||||||
|
-spec hash32(_,_) -> non_neg_integer().
|
||||||
hash32(Data, Seed) when is_binary(Data) -> hash32_impl(Data, Seed);
|
hash32(Data, Seed) when is_binary(Data) -> hash32_impl(Data, Seed);
|
||||||
hash32(Data, Seed) -> hash32(term_to_binary(Data), Seed).
|
hash32(Data, Seed) -> hash32(term_to_binary(Data), Seed).
|
||||||
|
|
||||||
|
-spec hash32(_) -> non_neg_integer().
|
||||||
hash32(Data) -> hash32(Data, 16#9E3779B9). % Seed is "golden ratio" FWIW.
|
hash32(Data) -> hash32(Data, 16#9E3779B9). % Seed is "golden ratio" FWIW.
|
||||||
|
|
||||||
|
-spec hash(_) -> non_neg_integer().
|
||||||
hash(Data) -> hash32(Data).
|
hash(Data) -> hash32(Data).
|
||||||
|
-spec hash(32,_) -> non_neg_integer().
|
||||||
hash(32, Data) -> hash32(Data).
|
hash(32, Data) -> hash32(Data).
|
||||||
|
-spec hash(32,_,_) -> non_neg_integer().
|
||||||
hash(32, Data, Seed) -> hash32(Data, Seed).
|
hash(32, Data, Seed) -> hash32(Data, Seed).
|
||||||
|
|
Loading…
Reference in a new issue