From fece77ec72c465dc209ccbccc3d871b44d3aa80b Mon Sep 17 00:00:00 2001 From: Gregory Burd Date: Fri, 15 Nov 2013 13:43:54 -0500 Subject: [PATCH] All sorts of things. --- Makefile | 146 +++++++++++++++++++++++++++++++++-------------- rebar.config | 5 +- src/bitpop.erl | 5 ++ src/hamt.erl | 23 ++++---- src/hamt_app.erl | 2 + src/hamt_sup.erl | 2 + src/murmur3.erl | 11 ++++ 7 files changed, 138 insertions(+), 56 deletions(-) diff --git a/Makefile b/Makefile index 13af30a..d2735f7 100644 --- a/Makefile +++ b/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 -ERL= /usr/bin/env erl -DIALYZER= /usr/bin/env dialyzer -REBAR= /usr/bin/env rebar -ifdef suites - SUITE_OPTION := suites=$(suites) +# Source: https://gist.github.com/ericbmerritt/5706091 + + +ERLFLAGS= -pa $(CURDIR)/.eunit -pa $(CURDIR)/ebin -pa $(CURDIR)/deps/*/ebin + +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 -ifdef tests - TESTS_OPTION := tests=$(tests) + +REBAR=$(shell which rebar) + +ifeq ($(REBAR),) +$(error "Rebar not available on this system") 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: $(REBAR) get-deps - -compile: deps $(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: - $(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 - $(REBAR) delete-deps + - rm -rf $(DEPS_PLT) + - rm -rvf $(CURDIR)/deps -eunit: 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").' +rebuild: distclean deps compile escript dialyzer test diff --git a/rebar.config b/rebar.config index d72b27b..88bb4de 100644 --- a/rebar.config +++ b/rebar.config @@ -1,6 +1,6 @@ %%% -*- mode: erlang -*- -{require_otp_vsn, "R15"}. +{require_otp_vsn, "R1[56]"}. {cover_enabled, true}. @@ -21,7 +21,8 @@ warn_obsolete_guard, warn_export_vars, warn_exported_vars, - warn_untyped_record + warn_untyped_record, + inline, native, {hipe, [o2]} %warn_missing_spec, %strict_validation %{parse_transform, lager_transform}, diff --git a/src/bitpop.erl b/src/bitpop.erl index 2c10853..55ed001 100644 --- a/src/bitpop.erl +++ b/src/bitpop.erl @@ -33,6 +33,11 @@ count(X, Acc) -> count((X band (X - 1)), (Acc + 1)). -endif. %-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(X) when is_integer(X), X > 0, X < 16#FFFFFFFF -> diff --git a/src/hamt.erl b/src/hamt.erl index 93df5c0..f13bd15 100644 --- a/src/hamt.erl +++ b/src/hamt.erl @@ -4,16 +4,15 @@ %% %% Copyright (C) 2013 Gregory Burd. All Rights Reserved. %% -%% The contents of this file are subject to the Mozilla Public License, -%% Version 2, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Mozilla Public License along with this software. If not, it can be -%% retrieved online at http://www.mozilla.org/MPL/ +%% The contents of this file are subject to the Mozilla Public License, Version +%% 2, (the "License"); you may not use this file except in compliance with the +%% License. You should have received a copy of the Mozilla Public License along +%% with this software. If not, it can be retrieved online at +%% http://www.mozilla.org/MPL/ %% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. +%% Software distributed under the License is distributed on an "AS IS" basis, +%% WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for +%% the specific language governing rights and limitations under the License. %% %% %CopyrightEnd% %% @@ -81,6 +80,7 @@ -ifdef(EQC). -include_lib("eqc/include/eqc.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. -compile(export_all). -include_lib("eunit/include/eunit.hrl"). @@ -165,6 +165,7 @@ get(Key, {hamt, HashSize, {cnode, _Bitmap, _Nodes}=CN}) -> {error, not_found} 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 -> Bit = bitpos(Hash, L), case exists(Bit, Bitmap) of @@ -181,6 +182,7 @@ get_1(_Hash, {lnode, List}, _L, _M) when is_list(List) -> {list, List}. +-spec get_2(_,maybe_improper_list()) -> 'none' | {_,_}. get_2(_Key, []) -> none; get_2(Key, [{Key, Value} | _Rest]) -> @@ -215,6 +217,7 @@ put(Key, Value, {hamt, HashSize, nil}) -> put(Key, Value, {hamt, HashSize, Node}) -> {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) when L =< M -> Bit = bitpos(Hash, L), @@ -230,7 +233,7 @@ put_1(_Hash, Key, Value, {snode, Key, _}, _L, _M) -> {snode, Key, Value}; put_1(Hash, Key, Value, {snode, SNKey, SNValue}, 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, Key1, Value1, {snode, Key2, Value2}, L, M) when L > M -> diff --git a/src/hamt_app.erl b/src/hamt_app.erl index 02f1997..b08437d 100644 --- a/src/hamt_app.erl +++ b/src/hamt_app.erl @@ -9,8 +9,10 @@ %% Application callbacks %% =================================================================== +-spec start(_,_) -> 'ignore' | {'error',_} | {'ok',pid()}. start(_StartType, _StartArgs) -> hamt_sup:start_link(). +-spec stop(_) -> 'ok'. stop(_State) -> ok. diff --git a/src/hamt_sup.erl b/src/hamt_sup.erl index 2d62371..2f3911b 100644 --- a/src/hamt_sup.erl +++ b/src/hamt_sup.erl @@ -16,6 +16,7 @@ %% API functions %% =================================================================== +-spec start_link() -> 'ignore' | {'error',_} | {'ok',pid()}. start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). @@ -23,5 +24,6 @@ start_link() -> %% Supervisor callbacks %% =================================================================== +-spec init([]) -> {'ok', term()}. init([]) -> {ok, { {one_for_one, 5, 10}, []} }. diff --git a/src/murmur3.erl b/src/murmur3.erl index 12b3a73..c5bf81b 100644 --- a/src/murmur3.erl +++ b/src/murmur3.erl @@ -26,22 +26,27 @@ -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. +-spec hash32_mmix(non_neg_integer()) -> non_neg_integer(). hash32_mmix(K1) -> K2 = (K1 * 16#CC9E2D51) band ?MASK32, K3 = rotl32(K2, 15), (K3 * 16#1B873593) band ?MASK32. +-spec hash32_fmix(integer()) -> non_neg_integer(). hash32_fmix(H) -> H2 = ((H bxor (H bsr 16)) * 16#85EBCA6B) band ?MASK32, H3 = ((H2 bxor (H2 bsr 13)) * 16#C2B2AE35) band ?MASK32, H3 bxor (H3 bsr 16). +-spec hash32_tail_mix(non_neg_integer(),integer()) -> integer(). hash32_tail_mix(K1, Hash) -> Hash bxor hash32_mmix(K1). % 4-byte blocks +-spec hash32_body(binary(),_) -> non_neg_integer(). hash32_body(<>, Hash) -> K2 = hash32_mmix(K1), Hash2 = Hash bxor K2, @@ -54,15 +59,21 @@ hash32_body(<>, Hash) -> hash32_tail_mix(K1, Hash); hash32_body(<>, Hash) -> hash32_tail_mix(K1, Hash); hash32_body(<<>>, Hash) -> Hash. +-spec hash32_impl(binary(),_) -> non_neg_integer(). hash32_impl(Data, Seed) -> Len = byte_size(Data), 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) -> hash32(term_to_binary(Data), Seed). +-spec hash32(_) -> non_neg_integer(). hash32(Data) -> hash32(Data, 16#9E3779B9). % Seed is "golden ratio" FWIW. +-spec hash(_) -> non_neg_integer(). hash(Data) -> hash32(Data). +-spec hash(32,_) -> non_neg_integer(). hash(32, Data) -> hash32(Data). +-spec hash(32,_,_) -> non_neg_integer(). hash(32, Data, Seed) -> hash32(Data, Seed).