Created
November 29, 2020 03:43
-
-
Save mattsan/5c7b568c603740c60a6406138a27eaac to your computer and use it in GitHub Desktop.
C++のクラスをNIFでElixirにバインドしてみた
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Counter do | |
@on_load {:load_nif, 0} | |
@compile {:autoload, false} | |
def load_nif do | |
Application.app_dir(:counter, "priv/counter_nif") | |
|> to_charlist() | |
|> :erlang.load_nif(0) | |
end | |
def create(_init_count), do: :erlang.nif_error(:nif_not_loaded) | |
def up(_ref), do: :erlang.nif_error(:nif_not_loaded) | |
def down(_ref), do: :erlang.nif_error(:nif_not_loaded) | |
def set(_ref, _count), do: :erlang.nif_error(:nif_not_loaded) | |
def get(_ref), do: :erlang.nif_error(:nif_not_loaded) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// c_src/counter.h | |
#ifndef COUNTER_H_ | |
#define COUNTER_H_ | |
class Counter { | |
public: | |
Counter(int count = 0) : count_(count) {} | |
~Counter() {} | |
int up() { return ++count_; } | |
int down() { return --count_; } | |
void set(int count) { count_ = count; } | |
int get() const { return count_; } | |
private: | |
int count_; | |
}; | |
#endif//COUNTER_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// c_src/counter_nif.cpp | |
#include <new> | |
#include <erl_nif.h> | |
#include "counter.h" | |
ErlNifResourceType* CounterType; | |
void destruct_counter(ErlNifEnv* caller_env, void* obj) { | |
Counter* counter = static_cast<Counter*>(obj); | |
counter->~Counter(); | |
} | |
int load(ErlNifEnv* caller_env, void** priv_data, ERL_NIF_TERM load_info) { | |
CounterType = enif_open_resource_type(caller_env, "Counter", "Counter", destruct_counter, ERL_NIF_RT_CREATE, nullptr); | |
return 0; | |
} | |
ERL_NIF_TERM create(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
int count; | |
enif_get_int(env, argv[0], &count); | |
void* resource = enif_alloc_resource(CounterType, sizeof(Counter)); | |
new(resource) Counter(count); | |
ERL_NIF_TERM handle = enif_make_resource(env, resource); | |
enif_release_resource(resource); | |
return enif_make_tuple2( | |
env, | |
enif_make_atom(env, "ok"), | |
handle | |
); | |
} | |
ERL_NIF_TERM up(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
Counter* counter; | |
enif_get_resource(env, argv[0], CounterType, reinterpret_cast<void**>(&counter)); | |
int result = counter->up(); | |
return enif_make_tuple2( | |
env, | |
enif_make_atom(env, "ok"), | |
enif_make_int(env, result) | |
); | |
} | |
ERL_NIF_TERM down(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
void* resource; | |
enif_get_resource(env, argv[0], CounterType, &resource); | |
Counter* counter = static_cast<Counter*>(resource); | |
int result = counter->down(); | |
return enif_make_tuple2( | |
env, | |
enif_make_atom(env, "ok"), | |
enif_make_int(env, result) | |
); | |
} | |
ERL_NIF_TERM set(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
void* resource; | |
enif_get_resource(env, argv[0], CounterType, &resource); | |
Counter* counter = static_cast<Counter*>(resource); | |
int count; | |
enif_get_int(env, argv[1], &count); | |
counter->set(count); | |
return enif_make_atom(env, "ok"); | |
} | |
ERL_NIF_TERM get(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
void* resource; | |
enif_get_resource(env, argv[0], CounterType, &resource); | |
Counter* counter = static_cast<Counter*>(resource); | |
int result = counter->get(); | |
return enif_make_tuple2( | |
env, | |
enif_make_atom(env, "ok"), | |
enif_make_int(env, result) | |
); | |
} | |
static ErlNifFunc nif_funcs[] = { | |
{"create", 1, create}, | |
{"up", 1, up}, | |
{"down", 1, down}, | |
{"set", 2, set}, | |
{"get", 1, get} | |
}; | |
ERL_NIF_INIT(Elixir.Counter, nif_funcs, load, nullptr, nullptr, nullptr); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PREFIX = $(MIX_APP_PATH)/priv | |
BUILD = $(MIX_APP_PATH)/obj | |
NIF = $(PREFIX)/counter_nif.so | |
CFLAGS = -std=c++11 -fpic | |
LDFLAGS = -lpthread -dynamiclib -undefined dynamic_lookup | |
ERL_CFLAGS = -I$(ERL_EI_INCLUDE_DIR) | |
ERL_LDFLAGS = -L$(ERL_EI_LIBDIR) -lei | |
SRC = $(wildcard c_src/*.cpp) | |
HEADERS = $(wildcard c_src/*.h) | |
OBJ = $(SRC:c_src/%.cpp=$(BUILD)/%.o) | |
all: install | |
install: $(PREFIX) $(BUILD) $(NIF) | |
$(OBJ): $(HEADERS) Makefile | |
$(BUILD)/%.o: c_src/%.cpp | |
$(CC) -c $(CFLAGS) $(ERL_CFLAGS) -o $@ $< | |
$(NIF): $(OBJ) | |
$(CC) $(LDFLAGS) $(ERL_LDFLAGS) -o $@ $^ | |
$(PREFIX) $(BUILD): | |
mkdir -p $@ | |
clean: | |
$(RM) $(NIF) $(OBJ) | |
.PHONY: all clean install |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Counter.MixProject do | |
use Mix.Project | |
def project do | |
[ | |
app: :counter, | |
version: "0.1.0", | |
elixir: "~> 1.11", | |
start_permanent: Mix.env() == :prod, | |
deps: deps(), | |
compilers: [:elixir_make | Mix.compilers()] | |
] | |
end | |
def application do | |
[ | |
extra_applications: [:logger] | |
] | |
end | |
defp deps do | |
[ | |
{:elixir_make, "~> 0.6", runtime: false} | |
] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment