Permalink
Browse files

Initial code commit

  • Loading branch information...
0 parents commit bca94a7dc0cae785adbd75590aa9b42bea4d8545 @yrashk committed Sep 23, 2012
Showing with 132 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +5 −0 README.md
  3. +49 −0 c_src/erlmb.c
  4. +3 −0 rebar.config
  5. +11 −0 src/erlmb.app.src
  6. +60 −0 src/erlmb.erl
@@ -0,0 +1,4 @@
+priv/*.so
+c_src/*.o
+ebin
+.eunit
@@ -0,0 +1,5 @@
+Erlang Mutable Binaries
+=======================
+
+Beware: it is an "evil" technique that you really don't want to be using
+(at least without knowing what you are doing... and even then...)
@@ -0,0 +1,49 @@
+#include "erl_nif.h"
+
+#include <string.h>
+
+// Prototypes
+static ERL_NIF_TERM erlmb_write(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[]);
+
+static ErlNifFunc nif_funcs[] =
+{
+ {"do_write", 4, erlmb_write},
+};
+
+static ERL_NIF_TERM erlmb_write(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[])
+{
+ // verify is first argument is a binary
+ if (!enif_is_binary(env, argv[0])) {
+ return enif_make_badarg(env);
+ }
+
+ // Extract the binary
+ ErlNifBinary bin;
+ enif_inspect_binary(env, argv[0], &bin);
+
+ // Figure out offset and value length
+ int offset, length;
+ enif_get_int(env, argv[2], &offset);
+ enif_get_int(env, argv[3], &length);
+
+ if (enif_is_binary(env, argv[1])) {
+ // binaries are totally fine
+ ErlNifBinary value_bin;
+ enif_inspect_binary(env, argv[1], &value_bin);
+ memcpy(bin.data + offset, value_bin.data, length);
+ } else {
+ return enif_make_badarg(env);
+ }
+
+ return argv[0];
+}
+
+
+static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ return 0;
+}
+
+ERL_NIF_INIT(erlmb, nif_funcs, &on_load, NULL, NULL, NULL);
@@ -0,0 +1,3 @@
+{port_specs,
+ [{"priv/erlmb.so",
+ ["c_src/erlmb.c"]}]}.
@@ -0,0 +1,11 @@
+{application, erlmb,
+ [
+ {description, "Erlang Mutable Binaries"},
+ {vsn, git},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {env, []}
+ ]}.
@@ -0,0 +1,60 @@
+-module(erlmb).
+
+%% Public
+-export([write/4]).
+
+-on_load(init/0).
+
+-define(nif_stub, nif_stub_error(?LINE)).
+nif_stub_error(Line) ->
+ erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}).
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-endif.
+
+init() ->
+ PrivDir = case code:priv_dir(?MODULE) of
+ {error, bad_name} ->
+ EbinDir = filename:dirname(code:which(?MODULE)),
+ AppPath = filename:dirname(EbinDir),
+ filename:join(AppPath, "priv");
+ Path ->
+ Path
+ end,
+ erlang:load_nif(filename:join(PrivDir, ?MODULE), 0).
+
+%% ===================================================================
+%% Public
+%% ===================================================================
+
+write(Binary, Value, Offset, Length) when is_integer(Value) ->
+ write(Binary, <<Value:(Length * 8)>>, Offset, Length);
+
+write(Binary, Value, Offset, Length) ->
+ do_write(Binary, Value, Offset, Length).
+
+do_write(_Binary, _Value, _Offset, _Length) ->
+ ?nif_stub.
+
+%% ===================================================================
+%% EUnit tests
+%% ===================================================================
+-ifdef(TEST).
+
+write_byte_test() ->
+ Binary = <<0,1,2,3>>,
+ write(Binary, <<-1>>, 1, 1),
+ ?assertEqual(<<0,-1,2,3>>, Binary).
+
+write_multiple_byte_test() ->
+ Binary = <<1,1,2,3>>,
+ write(Binary, <<-2,-1>>, 1, 2),
+ ?assertEqual(<<1,-2,-1,3>>, Binary).
+
+write_integer_test() ->
+ Binary = <<2,1,2,3>>,
+ write(Binary, -1, 1, 1),
+ ?assertEqual(<<2,-1,2,3>>, Binary).
+
+-endif.

0 comments on commit bca94a7

Please sign in to comment.