Skip to content

Commit 7a3d2b6

Browse files
authored
refactore
* Refactored api * Adding badge * Remove #prama once * Change clangformat settings * Added threading primitive wrappers * Updated Docs * Extended tests / added tests for parallel access * Cache and store factories itself * Added iterators
1 parent 225b2b0 commit 7a3d2b6

24 files changed

+646
-204
lines changed

.clang-format

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
---
22
BasedOnStyle: Microsoft
33
AlwaysBreakTemplateDeclarations: 'Yes'
4+
PackConstructorInitializers: 'Never'
45
...

.github/workflows/ci.yaml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ jobs:
114114
cache-environment: true
115115
post-cleanup: 'all'
116116

117-
- name: build and test
117+
- name: build
118118
shell: cmd /C CALL {0}
119119
run: |
120120
mkdir bld
@@ -126,9 +126,13 @@ jobs:
126126
-DXPLUGIN_BUILD_EXAMPLES=OFF ^
127127
-DCMAKE_PREFIX_PATH="%CONDA_PREFIX%\Library" ^
128128
-DCMAKE_INSTALL_PREFIX="%CONDA_PREFIX%
129-
130129
cmake --build . --config Release
131-
ctest -C Release -V
130+
131+
- name: Run C++ tests
132+
shell: cmd /C CALL {0}
133+
run: |
134+
cd bld
135+
ctest -V --config Release
132136
133137
- name: Install
134138
shell: cmd /C CALL {0}

README.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,10 @@ int main(int argc, char** argv)
9999
std::string plugin_directory = argv[1];
100100

101101

102-
plugin_registry_type registry;
103-
registry.add_from_directory(plugin_directory);
102+
plugin_registry_type registry(plugin_directory);
104103

105-
for (auto& name : registry.plugin_names()){
104+
for (auto [name, factory] : registry){
106105
std::cout << name << std::endl;
107-
auto factory = registry.create_factory(name);
108106
auto plugin = factory->create();
109107
plugin->do_something();
110108
}
@@ -215,15 +213,13 @@ int main(int argc, char** argv)
215213
std::string plugin_directory = argv[1];
216214

217215

218-
plugin_registry_type registry;
219-
registry.add_from_directory(plugin_directory);
216+
plugin_registry_type registry(plugin_directory);
220217

221218
int some_data = 42;
222219
std::string some_other_data = "Hello World";
223220

224-
for (auto& name : registry.plugin_names()){
221+
for (auto [name, factory] : registry){
225222
std::cout << name << std::endl;
226-
auto factory = registry.create_factory(name);
227223
auto plugin = factory->create(some_data, some_other_data);
228224
plugin->do_something();
229225
}

cmake/xplugin_emscripten_utils.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ endfunction()
1010
function(xplugin_add_emscripten_flags)
1111
if(EMSCRIPTEN)
1212
set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE)
13+
# for emscripten we do not want any threads or thread primitives
14+
add_compile_definitions(XPLUGIN_NO_THREADS)
15+
1316
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-s SIDE_MODULE=1")
1417
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "-s SIDE_MODULE=1")
1518
set(CMAKE_STRIP FALSE)

docs/api/index.rst

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,23 @@ C++ API
66
Models
77
--------
88

9-
10-
119
.. doxygenclass:: xp::xshared_library
1210
:project: xplugin
1311

12+
.. doxygenclass:: xp::xlazy_shared_library_plugin_factory
13+
:project: xplugin
14+
1415
.. doxygenclass:: xp::xfactory_base
1516
:project: xplugin
1617

1718
.. doxygenclass:: xp::xfactory
1819
:project: xplugin
1920

20-
.. doxygenclass:: xp::xplugin_registry
21+
.. doxygenclass:: xp::detail::xplugin_registry_impl
22+
:project: xplugin
23+
24+
.. doxygentypedef:: xp::xplugin_registry
25+
:project: xplugin
26+
27+
.. doxygentypedef:: xp::xthread_save_plugin_registry
2128
:project: xplugin

examples/accumulator/main_accumulator.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,24 @@ int main(int argc, char **argv)
1818
using factory_base_type = xp::xfactory_base<base_type>;
1919
using plugin_registry_type = xp::xplugin_registry<factory_base_type>;
2020

21-
plugin_registry_type registry;
22-
registry.add_from_directory(plugin_directory);
21+
plugin_registry_type registry(plugin_directory);
2322

2423
std::cout << "available plugins:" << std::endl;
25-
for (auto &p : registry.plugin_names())
24+
for (auto p : registry)
2625
{
27-
std::cout << p << std::endl;
26+
std::cout << p.first << std::endl;
2827
}
2928

3029
// create data to accumulate
3130
std::vector<double> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
3231

3332
// create and use plugin_accumulator_max
34-
auto factory_max = registry.create_factory("plugin_accumulator_max");
35-
auto acc_max = factory_max->create();
33+
auto acc_max = registry["plugin_accumulator_max"]->create();
3634
auto result_max = acc_max->accumulate(data);
3735
std::cout << "accumulator " << acc_max->name() << " result: " << result_max << std::endl;
3836

3937
// create and use plugin_accumulator_min
40-
auto factory_min = registry.create_factory("plugin_accumulator_min");
41-
auto acc_min = factory_min->create();
38+
auto acc_min = registry["plugin_accumulator_min"]->create();
4239
auto result_min = acc_min->accumulate(data);
4340
std::cout << "accumulator " << acc_min->name() << " result: " << result_min << std::endl;
4441
}

examples/custom_factory_with_metadata/custom_factory_with_metadata_plugin_a.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class PluginAFactory : public PluginFactoryBase
2424
public:
2525
using factory_base_type = PluginFactoryBase;
2626

27-
PluginBase *create() override
27+
std::unique_ptr<PluginBase> create() override
2828
{
29-
return new PluginA();
29+
return std::make_unique<PluginA>();
3030
}
3131

3232
std::string name() const override

examples/custom_factory_with_metadata/custom_factory_with_metadata_plugin_b.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class PluginBFactory : public PluginFactoryBase
2424
public:
2525
using factory_base_type = PluginFactoryBase;
2626

27-
PluginBase *create() override
27+
std::unique_ptr<PluginBase> create() override
2828
{
29-
return new PluginB();
29+
return std::make_unique<PluginB>();
3030
}
3131

3232
std::string name() const override

examples/custom_factory_with_metadata/custom_factory_with_metadata_plugin_base.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef CUSTOM_FACTORY_WITH_METADATA_PLUGIN_BASE_HPP
22
#define CUSTOM_FACTORY_WITH_METADATA_PLUGIN_BASE_HPP
33

4+
#include <memory>
45
#include <string>
56

67
class PluginBase
@@ -19,7 +20,7 @@ class PluginFactoryBase
1920
virtual ~PluginFactoryBase() = default;
2021

2122
// the factory method
22-
virtual PluginBase *create() = 0;
23+
virtual std::unique_ptr<PluginBase> create() = 0;
2324

2425
// some additional metadata
2526
virtual std::string name() const = 0;

examples/custom_factory_with_metadata/main_custom_factory_with_metadata.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,18 @@ int main(int argc, char **argv)
1414
std::string plugin_directory = argv[1];
1515

1616
using factory_base_type = PluginFactoryBase;
17-
auto &registry = xp::get_registry<factory_base_type>();
18-
registry.add_from_directory(plugin_directory);
17+
using plugin_registry_type = xp::xplugin_registry<factory_base_type>;
18+
plugin_registry_type registry(plugin_directory);
1919

20-
for (auto &p : registry.plugin_names())
20+
for (auto [name, factory] : registry)
2121
{
22-
auto factory = registry.create_factory(p);
2322

24-
std::cout << "plugin " << p << " factory metadata: " << std::endl;
23+
std::cout << "plugin " << name << " factory metadata: " << std::endl;
2524
std::cout << " name: " << factory->name() << std::endl;
2625
std::cout << " description: " << factory->description() << std::endl;
2726
std::cout << " version: " << factory->version() << std::endl;
2827

2928
auto instance = factory->create();
30-
std::cout << "plugin " << p << " says: " << instance->some_function() << std::endl;
29+
std::cout << "plugin " << name << " says: " << instance->some_function() << std::endl;
3130
}
3231
}

examples/fubar/main_fubar.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,11 @@ int main(int argc, char **argv)
1616
using factory_type = xp::xfactory_base<fubar::FubarBase, const std::string &>;
1717
using plugin_registry_type = xp::xplugin_registry<factory_type>;
1818

19-
plugin_registry_type registry;
20-
registry.add_from_directory(plugin_directory);
19+
plugin_registry_type registry(plugin_directory);
2120

22-
std::cout << "available plugins:" << std::endl;
23-
for (auto &p : registry.plugin_names())
21+
for (auto [name, factory] : registry)
2422
{
25-
std::cout << p << std::endl;
26-
}
27-
28-
for (auto &p : registry.plugin_names())
29-
{
30-
auto factory = registry.create_factory(p);
3123
auto instance = factory->create("main_fubar");
32-
std::cout << "plugin " << p << " says: " << instance->fubar() << std::endl;
24+
std::cout << "plugin " << name << " says: " << instance->fubar() << std::endl;
3325
}
3426
}

examples/fubar/plugin_bar.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
class Bar : public fubar::FubarBase
55
{
66
public:
7-
Bar(const std::string name) : name_(name)
7+
Bar(const std::string name)
8+
: name_(name)
89
{
910
}
1011
virtual ~Bar() = default;

examples/fubar/plugin_foo.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
class Foo : public fubar::FubarBase
55
{
66
public:
7-
Foo(const std::string name) : name_(name)
7+
Foo(const std::string name)
8+
: name_(name)
89
{
910
}
1011

examples/serialize/main_serialize.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,24 +36,22 @@ int main(int argc, char **argv)
3636

3737
// the type base type of the factory
3838
using factory_base_type = xp::xfactory_base<SerializeBase>;
39+
using plugin_registry_type = xp::xplugin_registry<factory_base_type>;
3940

40-
// get the plugin registry for that base type
41-
auto &registry = xp::get_registry<factory_base_type>();
42-
43-
// add plugins from the plugin directory
44-
registry.add_from_directory(plugin_directory);
41+
// create the registry
42+
plugin_registry_type registry(plugin_directory);
4543

4644
// some data to serialize / deserialize
4745
std::unordered_map<std::string, double> data = {{"a", 1}, {"b", 2}, {"c", 3}};
4846

4947
// use all plugins
5048
///////////////////////////////////////////
51-
for (const auto &plugin_name : registry.plugin_names())
49+
for (auto [plugin_name, factory] : registry)
5250
{
5351
// create and use plugin_serialize_json
54-
auto plugin = registry.create_factory(plugin_name)->create();
52+
auto plugin = factory->create();
5553
auto serialized = plugin->serialize(data);
56-
std::cout << "serialized with" << plugin->name() << ":" << std::endl << serialized << std::endl;
54+
std::cout << plugin_name << " serialized with" << plugin->name() << ":" << std::endl << serialized << std::endl;
5755

5856
// deserialize with plugin_serialize_json
5957
auto deserialized = plugin->deserialize(serialized);
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/***************************************************************************
2+
* Copyright (c) 2023, Dr. Thorsten Beier *
3+
* *
4+
* Distributed under the terms of the BSD 3-Clause License. *
5+
* *
6+
* The full license is in the file LICENSE, distributed with this software. *
7+
****************************************************************************/
8+
#ifndef XLAZY_SHARED_LIBRARY_PLUGIN_FACTORY_HPP
9+
#define XLAZY_SHARED_LIBRARY_PLUGIN_FACTORY_HPP
10+
11+
#include <filesystem>
12+
#include <memory>
13+
#include <xplugin/xshared_library.hpp>
14+
#include <xplugin/xthreads.hpp>
15+
16+
namespace xp
17+
{
18+
19+
// lazy storage of a shared library
20+
// and the factory it contains.
21+
// Both are loaded / created on demand
22+
template <class FACTORY_BASE, bool THREAD_SAFE>
23+
class xlazy_shared_library_plugin_factory
24+
{
25+
public:
26+
using factory_base_type = FACTORY_BASE;
27+
xlazy_shared_library_plugin_factory(const xlazy_shared_library_plugin_factory &) = delete;
28+
xlazy_shared_library_plugin_factory &operator=(const xlazy_shared_library_plugin_factory &) = delete;
29+
30+
xlazy_shared_library_plugin_factory(xlazy_shared_library_plugin_factory &&other) = delete;
31+
xlazy_shared_library_plugin_factory &operator=(xlazy_shared_library_plugin_factory &&other) = delete;
32+
33+
~xlazy_shared_library_plugin_factory() = default;
34+
35+
inline xlazy_shared_library_plugin_factory(const std::filesystem::path &path);
36+
37+
inline const std::filesystem::path &path() const noexcept;
38+
39+
factory_base_type *factory() const;
40+
41+
private:
42+
using create_plugin_factory_type = factory_base_type *(*)();
43+
using mutex_type = xmutex_t<THREAD_SAFE>;
44+
using scoped_lock_type = xscoped_lock_t<THREAD_SAFE, mutex_type>;
45+
46+
mutable mutex_type m_mutex;
47+
std::filesystem::path m_path;
48+
mutable std::unique_ptr<xshared_library> m_library;
49+
mutable std::unique_ptr<factory_base_type> m_factory;
50+
};
51+
52+
template <class FACTORY_BASE, bool THREAD_SAFE>
53+
inline xlazy_shared_library_plugin_factory<FACTORY_BASE, THREAD_SAFE>::xlazy_shared_library_plugin_factory(
54+
const std::filesystem::path &path)
55+
: m_path(path),
56+
m_library()
57+
{
58+
}
59+
60+
template <class FACTORY_BASE, bool THREAD_SAFE>
61+
inline typename xlazy_shared_library_plugin_factory<FACTORY_BASE, THREAD_SAFE>::factory_base_type *
62+
xlazy_shared_library_plugin_factory<FACTORY_BASE, THREAD_SAFE>::factory() const
63+
{
64+
scoped_lock_type lock(m_mutex);
65+
if (!m_factory)
66+
{
67+
68+
m_library.reset(new xshared_library(m_path));
69+
m_factory.reset(m_library->find_symbol<create_plugin_factory_type>("create_plugin_factory")());
70+
}
71+
return m_factory.get();
72+
}
73+
74+
template <class FACTORY_BASE, bool THREAD_SAFE>
75+
const std::filesystem::path &xlazy_shared_library_plugin_factory<FACTORY_BASE, THREAD_SAFE>::path() const noexcept
76+
{
77+
return m_path;
78+
}
79+
80+
} // namespace xp
81+
82+
#endif // XLAZY_SHARED_LIBRARY_PLUGIN_FACTORY_HPP

0 commit comments

Comments
 (0)