1. Andy Gross
  2. bashohash

Commits

Andy Gross  committed a364084

nif-ize

  • Participants
  • Parent commits 83f8a2d
  • Branches default

Comments (0)

Files changed (6)

File .hgignore

View file
  • Ignore whitespace
 ^c_src/.*.o
 ^.eunit/.*
 ^ebin/.*.beam
-^priv/efnv_drv.so
+^priv/efnv_nifs.so

File c_src/efnv_drv.c

  • Ignore whitespace
-
-#include "fnv.h"
-#include <erl_driver.h>
-#include <ei.h>
-#include <stdio.h>
-
-#define write_int32(i, s) {((char*)(s))[0] = (char)((i) >> 24) & 0xff; \
-                        ((char*)(s))[1] = (char)((i) >> 16) & 0xff; \
-                        ((char*)(s))[2] = (char)((i) >> 8)  & 0xff; \
-                        ((char*)(s))[3] = (char)((i)        & 0xff);}
-
-static ErlDrvData init(ErlDrvPort port, char *cmd);
-static void stop(ErlDrvData handle);
-static void outputv(ErlDrvData handle, ErlIOVec *ev);
-
-static ErlDrvData init(ErlDrvPort port, char *cmd) {
-  return (ErlDrvData) port;
-}
-
-static void stop(ErlDrvData handle) {
-  //noop
-}
-
-static void outputv(ErlDrvData handle, ErlIOVec *ev) {
-  ErlDrvPort port = (ErlDrvPort) handle;
-  ErlDrvTermData caller;
-  SysIOVec *bin;
-  int i, index = 0;
-  unsigned long hash;
-  unsigned long seed;
-  //first piece of the iovec is the seed
-  // printf("ev->size %d\n", ev->size);
-  // printf("ev-vsize %d\n", ev->vsize);
-  //apparently we start counting at 1 round here?
-  bin = &ev->iov[1];
-  // printf("bin->orig_size %d\n", bin->iov_len);
-  // printf("bin->iov_base %s\n", bin->iov_base);
-  ei_decode_version(bin->iov_base, &index, NULL);
-  ei_decode_ulong(bin->iov_base, &index, &seed);
-  hash = seed;
-  if (index < bin->iov_len) {
-    hash = fnv_hash(&bin->iov_base[index], bin->iov_len - index, hash);
-  }
-  for (i=2; i<ev->vsize; i++) {
-    bin = &ev->iov[i];
-    hash = fnv_hash(bin->iov_base, bin->iov_len, hash);
-  }
-  caller = driver_caller(port);
-  ErlDrvTermData spec[] = {
-    ERL_DRV_UINT, hash
-  };
-  driver_send_term(port, caller, spec, 2);
-}
-
-static int control(ErlDrvData data, unsigned int seed, char *buf, int len, char **rbuf, int rlen) {
-  unsigned int hash;
-  // printf("length %d\n", len);
-  // printf("buf %s\n", buf);
-  hash = fnv_hash(buf, len, seed);
-  if (rlen < sizeof(hash)) {
-    (*rbuf) = (char *) driver_realloc(*rbuf, sizeof(hash));
-  }
-  write_int32(hash, *rbuf);
-  return sizeof(hash);
-}
-
-
-static ErlDrvEntry efnv_driver_entry = {
-    NULL,                             /* init */
-    init, 
-    stop, 
-    NULL,                             /* output */
-    NULL,                             /* ready_input */
-    NULL,                             /* ready_output */ 
-    "efnv_drv",                        /* the name of the driver */
-    NULL,                             /* finish */
-    NULL,                             /* handle */
-    control,                          /* control */
-    NULL,                             /* timeout */
-    outputv,                          /* outputv */
-    NULL,                             /* ready_async */
-    NULL,                             /* flush */
-    NULL,                             /* call */
-    NULL,                             /* event */
-    ERL_DRV_EXTENDED_MARKER,          /* ERL_DRV_EXTENDED_MARKER */
-    ERL_DRV_EXTENDED_MAJOR_VERSION,   /* ERL_DRV_EXTENDED_MAJOR_VERSION */
-    ERL_DRV_EXTENDED_MAJOR_VERSION,   /* ERL_DRV_EXTENDED_MINOR_VERSION */
-    ERL_DRV_FLAG_USE_PORT_LOCKING     /* ERL_DRV_FLAGs */
-    
-};
-
-DRIVER_INIT(efnv_driver) {
-  return &efnv_driver_entry;
-}

File c_src/efnv_nifs.c

View file
  • Ignore whitespace
+#include "efnv_nifs.h"
+#include "fnv.h"
+
+
+ERL_NIF_TERM efnv_hash(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]);
+
+
+static ErlNifFunc nif_funcs[] = {
+    {"efnv_hash", 2, efnv_hash}
+};
+
+ERL_NIF_INIT(efnv, nif_funcs, NULL, NULL, NULL, NULL);
+
+ERL_NIF_TERM efnv_hash(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { 
+    ErlNifBinary bin_term;
+    unsigned int seed;
+    unsigned int result = 0;
+    if (!enif_inspect_binary(env, argv[0], &bin_term)) 
+        return enif_make_badarg(env);
+    if (!enif_get_uint(env, argv[1], &seed))
+        return enif_make_badarg(env);
+    result = fnv_hash((const void *)bin_term.data, bin_term.size, seed);
+    return enif_make_uint(env, result);
+}

File c_src/efnv_nifs.h

View file
  • Ignore whitespace
+#ifndef EFNV_NIFS_H_
+#define EFNV_NIFS_H_
+
+#include "erl_nif.h"
+
+
+#endif /* include guard */
+

File rebar.config

View file
  • Ignore whitespace
+{port_sources, ["c_src/*.c"]}.
+{so_name, "efnv_nifs.so"}.
+
+{port_envs, [
+             %% Make sure to link -lstdc++ on linux or solaris
+             {"(linux|solaris)", "LDFLAGS", "$LDFLAGS -lstdc++"},
+
+             %% OS X Leopard flags for 64-bit
+             {"darwin9.*-64$", "CXXFLAGS", "-m64"},
+             {"darwin9.*-64$", "LDFLAGS", "-arch x86_64 -lstdc++"},
+
+             %% OS X Snow Leopard flags for 32-bit
+             {"darwin10.*-32$", "CXXFLAGS", "-m32"},
+             {"darwin10.*-32$", "LDFLAGS", "-arch i386"}
+             ]}.
+
+

File src/efnv.erl

View file
  • Ignore whitespace
-%%%-------------------------------------------------------------------
-%%% File:      fnv.erl
-%%% @author    Cliff Moon <> []
-%%% @copyright 2009 Cliff Moon
-%%% @doc
-%%%
-%%% @end
-%%%
-%%% @since 2009-01-29 by Cliff Moon
-%%%-------------------------------------------------------------------
+
 -module(efnv).
 -author('cliff@powerset.com').
+-author('andy@basho.com').
+-export([fnv/1, fnv/2]).
+-on_load(init/0).
 
 -define(SEED, 2166136261).
-%% API
--export([start/0, stop/1, hash/1, hash/2]).
 
-%%====================================================================
-%% API
-%%====================================================================
-%%--------------------------------------------------------------------
-%% @spec
-%% @doc
-%% @end
-%%--------------------------------------------------------------------
-start() ->
-  case load_driver() of
-    ok ->
-      Pid = spawn_link(fun() ->
-          P = open(),
-          register(efnv_drv, P),
-          loop(P)
-        end),
-      timer:sleep(1),
-      {ok, Pid};
-    {error, Err} ->
-      Msg = erl_ddll:format_error(Err),
-      {error, Msg}
-  end.
+init() ->
+    case code:priv_dir(efnv) of
+        {error, bad_name} ->
+            SoName = filename:join("../priv", efnv_nifs);
+        Dir ->
+            SoName = filename:join(Dir, efnv_nifs)
+    end,
+    erlang:load_nif(SoName, 0).
 
-stop(P) ->
-  unlink(P),
-  exit(P, die).
-
-hash(Thing) ->
-  hash(Thing, ?SEED).
-
-hash(Thing, Seed) when is_binary(Thing) ->
-  P = get_or_open(),
-  convert(port_control(P, Seed, Thing));
-
-hash(Thing, Seed) ->
-  P = get_or_open(),
-  convert(port_control(P, Seed, term_to_binary(Thing))).
-
-%%====================================================================
-%% Internal functions
-%%====================================================================
-loop(P) ->
-  receive _ -> loop(P) end.
-
-convert(List) ->
-  <<Hash:32/unsigned-integer>> = list_to_binary(List),
-  Hash.
-
-get_or_open() ->
-  case get(efnv_drv) of
-    undefined ->
-      load_driver(),
-      P = open(),
-      put(efnv_drv, P),
-      P;
-    P -> P
-  end.
-
-open() ->
-  open_port({spawn, efnv_drv}, [binary]).
-
-load_driver() ->
-  Dir = filename:join([filename:dirname(code:which(?MODULE)), "..", "priv"]),
-  erl_ddll:load(Dir, "efnv_drv").
-
+fnv(T) -> fnv(T, ?SEED).
+fnv(T, Seed) when is_binary(T) -> efnv_hash(T, Seed);
+fnv(T, Seed) -> efnv_hash(term_to_binary(T), Seed).
+efnv_hash(_T, _Seed) -> "NIF library not loaded".