231103.1 · 7f4a9ed91bbecb84e39f4bc8030247ce5116ddf8
Reorganize examples into categorized folders (#341)
* refactor: create directory structure to organize exmaples
* test: update test_all to work with new directory structure
* fix: bug in test_all if no package.json scripts
* test: cleanup output of test_all
* fix: remove default test script that throws from thread_safe_function_with_object_wrap
* fix: remove build_with_cmake from .gitignore
* fix: swith to ' from " and remove subdir from getAllTests call
* test: add extra test cases for npm start and just running the pkgJson.main with node
* refactor: move all examples to src directory
* refactor: add numbers to categories so they are ordered in the src folder
* refactor: simplify getAllExamples in test_all.js
* docs: add directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure example in readme
* add back build_with_cmake
---------
Co-authored-by: legendecas <legendecas@gmail.com>
reading declarations
Changes to src/6-threadsafe-function/threadsafe-async-iterator/node-addon-api/example.cc. All files
src/6-threadsafe-function/threadsafe-async-iterator/node-addon-api/example.cc
@@ -0,0 +1,163 @@+#include <napi.h>+#include <condition_variable>+#include <functional>+#include <memory>+#include <mutex>+#include <optional>+#include <thread>++using namespace Napi;++class ThreadSafeAsyncIteratorExample+ : public ObjectWrap<ThreadSafeAsyncIteratorExample> {+ public:+ ThreadSafeAsyncIteratorExample(const CallbackInfo& info)+ : ObjectWrap<ThreadSafeAsyncIteratorExample>(info),+ _current(info[0].As<Number>()),+ _last(info[1].As<Number>()) {}++ static Object Init(Napi::Env env, Napi::Object exports);++ Napi::Value Iterator(const CallbackInfo& info);++ private:+ using Context = ThreadSafeAsyncIteratorExample;++ struct DataType {+ std::unique_ptr<Promise::Deferred> deferred;+ bool done;+ std::optional<int> value;+ };++ static void CallJs(Napi::Env env,+ Function callback,+ Context* context,+ DataType* data);++ using TSFN = TypedThreadSafeFunction<Context, DataType, CallJs>;++ using FinalizerDataType = void;++ int _current;+ int _last;+ TSFN _tsfn;+ std::thread _thread;+ std::unique_ptr<Promise::Deferred> _deferred;++ // Thread-safety+ std::mutex _mtx;+ std::condition_variable _cv;++ void threadEntry();++ static void FinalizerCallback(Napi::Env env,+ void*,+ ThreadSafeAsyncIteratorExample* context);+};++Object ThreadSafeAsyncIteratorExample::Init(Napi::Env env,+ Napi::Object exports) {+ Napi::Function func =+ DefineClass(env,+ "ThreadSafeAsyncIteratorExample",+ {InstanceMethod(Napi::Symbol::WellKnown(env, "asyncIterator"),+ &ThreadSafeAsyncIteratorExample::Iterator)});++ exports.Set("ThreadSafeAsyncIteratorExample", func);+ return exports;+}++Napi::Value ThreadSafeAsyncIteratorExample::Iterator(const CallbackInfo& info) {+ auto env = info.Env();++ if (_thread.joinable()) {+ Napi::Error::New(env, "Concurrent iterations not implemented.")+ .ThrowAsJavaScriptException();+ return Napi::Value();+ }++ _tsfn =+ TSFN::New(info.Env(),+ "tsfn",+ 0,+ 1,+ this,+ std::function<decltype(FinalizerCallback)>(FinalizerCallback));++ // To prevent premature garbage collection; Unref in TFSN finalizer+ Ref();++ // Create thread+ _thread = std::thread(&ThreadSafeAsyncIteratorExample::threadEntry, this);++ // Create iterable+ auto iterable = Napi::Object::New(env);++ iterable["next"] =+ Function::New(env, [this](const CallbackInfo& info) -> Napi::Value {+ std::lock_guard<std::mutex> lk(_mtx);+ auto env = info.Env();+ if (_deferred) {+ Napi::Error::New(env, "Concurrent iterations not implemented.")+ .ThrowAsJavaScriptException();+ return Napi::Value();+ }+ _deferred = std::make_unique<Promise::Deferred>(env);+ _cv.notify_all();+ return _deferred->Promise();+ });++ return iterable;+}++void ThreadSafeAsyncIteratorExample::threadEntry() {+ while (true) {+ std::unique_lock<std::mutex> lk(_mtx);+ _cv.wait(lk, [this] { return this->_deferred != nullptr; });+ auto done = _current > _last;+ if (done) {+ _tsfn.BlockingCall(new DataType{std::move(this->_deferred), true, {}});+ break;+ } else {+ std::this_thread::sleep_for(+ std::chrono::seconds(1)); // Simulate CPU-intensive work+ _tsfn.BlockingCall(+ new DataType{std::move(this->_deferred), false, _current++});+ }+ }+ _tsfn.Release();+}++void ThreadSafeAsyncIteratorExample::CallJs(Napi::Env env,+ Function callback,+ Context* context,+ DataType* data) {+ if (env != nullptr) {+ auto value = Object::New(env);++ if (data->done) {+ value["done"] = Boolean::New(env, true);+ } else {+ value["done"] = Boolean::New(env, false);+ value["value"] = Number::New(env, data->value.value());+ }+ data->deferred->Resolve(value);+ }++ if (data != nullptr) {+ delete data;+ }+}++void ThreadSafeAsyncIteratorExample::FinalizerCallback(+ Napi::Env env, void*, ThreadSafeAsyncIteratorExample* context) {+ context->_thread.join();+ context->Unref();+}++Napi::Object Init(Napi::Env env, Object exports) {+ ThreadSafeAsyncIteratorExample::Init(env, exports);+ return exports;+}++NODE_API_MODULE(example, Init)