LCOV - code coverage report
Current view: top level - cppthread - plugins.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 97 106 91.5 %
Date: 2021-08-21 09:27:22 Functions: 123 123 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2013-2021  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/cppthread
       4             : // contact@m2osw.com
       5             : //
       6             : // This program is free software; you can redistribute it and/or modify
       7             : // it under the terms of the GNU General Public License as published by
       8             : // the Free Software Foundation; either version 2 of the License, or
       9             : // (at your option) any later version.
      10             : //
      11             : // This program is distributed in the hope that it will be useful,
      12             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : // GNU General Public License for more details.
      15             : //
      16             : // You should have received a copy of the GNU General Public License along
      17             : // with this program; if not, write to the Free Software Foundation, Inc.,
      18             : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             : #pragma once
      20             : 
      21             : // self
      22             : //
      23             : #include    "cppthread/mutex.h"
      24             : 
      25             : #include    "cppthread/exception.h"
      26             : #include    "cppthread/version.h"       // used in CPPTHREAD_PLUGIN_START()
      27             : 
      28             : 
      29             : // snapdev lib
      30             : //
      31             : #include    <snapdev/not_used.h>
      32             : 
      33             : 
      34             : // C++ set
      35             : //
      36             : #include    <map>
      37             : #include    <memory>
      38             : #include    <set>
      39             : #include    <string>
      40             : #include    <vector>
      41             : 
      42             : 
      43             : namespace cppthread
      44             : {
      45             : 
      46             : 
      47             : namespace detail
      48             : {
      49             : class plugin_repository;
      50             : } // detail namespace
      51             : 
      52             : 
      53             : typedef std::set<std::string>           string_set_t;
      54             : 
      55             : 
      56             : template<int N>
      57           8 : constexpr char const * validate_name(char const (&str)[N])
      58             : {
      59             :     static_assert(N - 1 > 0);
      60             : 
      61           8 :     if(str[0] != '_'
      62           8 :     && (str[0] < 'a' || str[0] > 'z')
      63           0 :     && (str[0] < 'A' || str[0] > 'Z'))
      64             :     {
      65             :         throw cppthread_logic_error(
      66             :                     "first character of name \""
      67             :                   + std::string(str)
      68           0 :                   + "\" not valid.");
      69             :     }
      70             : 
      71          62 :     for(int i(1); i < N - 1; ++i)
      72             :     {
      73          54 :         if(str[i] != '_'
      74          52 :         && (str[i] < 'a' || str[i] > 'z')
      75           0 :         && (str[i] < 'A' || str[i] > 'Z')
      76           0 :         && (str[i] < '0' || str[i] > '9'))
      77             :         {
      78             :             throw cppthread_logic_error(
      79             :                     "character #"
      80             :                   + std::to_string(i)
      81             :                   + " ("
      82           0 :                   + str[i]
      83             :                   + ") of name \""
      84             :                   + str
      85           0 :                   + "\" not valid.");
      86             :         }
      87             :     }
      88             : 
      89           8 :     return str;
      90             : }
      91             : 
      92             : 
      93           1 : constexpr time_t validate_date(time_t date)
      94             : {
      95             :     // any new plugin must be created after this date (about 2021/06/22 10:30)
      96             :     //
      97           1 :     if(date < 1624382757LL)
      98             :     {
      99           0 :         throw cppthread_out_of_range("plugin dates are expected to be at least 2021/06/22 10:30");
     100             :     }
     101           1 :     return date;
     102             : }
     103             : 
     104             : 
     105             : template<typename T>
     106           2 : constexpr void validate_version(T const major, T const minor)
     107             : {
     108           2 :     if(major == 0 && minor == 0)
     109             :     {
     110           0 :         throw cppthread_logic_error("the plugin version cannot be 0.0.");
     111             :     }
     112           2 : }
     113             : 
     114             : 
     115             : 
     116             : 
     117             : struct version_t
     118             : {
     119             :                         constexpr version_t()
     120             :                             : f_major(0)
     121             :                             , f_minor(0)
     122             :                             , f_patch(0)
     123             :                         {
     124             :                         }
     125             : 
     126           2 :                         version_t(
     127             :                                   std::int32_t major
     128             :                                 , std::int32_t minor
     129             :                                 , std::int32_t patch = 0)
     130           2 :                             : f_major(major)
     131             :                             , f_minor(minor)
     132           2 :                             , f_patch(patch)
     133             :                         {
     134           2 :                             validate_version(major, minor);
     135           2 :                         }
     136             : 
     137             :     std::int32_t        f_major = 0;
     138             :     std::int32_t        f_minor = 0;
     139             :     std::int32_t        f_patch = 0;
     140             : };
     141             : 
     142             : 
     143           1 : struct plugin_definition
     144             : {
     145             :     version_t                           f_version = version_t();
     146             :     version_t                           f_library_version = version_t();
     147             :     time_t                              f_last_modification = 0;        // uses the compilation date & time converted to a Unix date
     148             :     std::string                         f_name = std::string();
     149             :     std::string                         f_description = std::string();
     150             :     std::string                         f_help_uri = std::string();
     151             :     std::string                         f_icon = std::string();
     152             :     string_set_t                        f_categorization_tags = string_set_t();
     153             :     string_set_t                        f_dependencies = string_set_t();
     154             :     string_set_t                        f_conflicts = string_set_t();
     155             :     string_set_t                        f_suggestions = string_set_t();
     156             : };
     157             : 
     158             : 
     159             : 
     160             : 
     161             : 
     162             : template<typename T>
     163             : class plugin_definition_value
     164             : {
     165             : public:
     166             :     typedef T   value_t;
     167             : 
     168          17 :     constexpr plugin_definition_value<T>(T const v)
     169          17 :         : f_value(v)
     170             :     {
     171          17 :     }
     172             : 
     173          14 :     constexpr value_t get() const
     174             :     {
     175          14 :         return f_value;
     176             :     }
     177             : 
     178             : private:
     179             :     value_t     f_value = value_t();
     180             : };
     181             : 
     182             : 
     183             : 
     184             : 
     185             : class plugin_version
     186             :     : public plugin_definition_value<version_t>
     187             : {
     188             : public:
     189             :     constexpr plugin_version()
     190             :         : plugin_definition_value<version_t>(version_t())
     191             :     {
     192             :     }
     193             : 
     194           1 :     constexpr plugin_version(version_t version)
     195           1 :         : plugin_definition_value<version_t>(version)
     196             :     {
     197           1 :     }
     198             : };
     199             : 
     200             : 
     201             : class plugin_library_version
     202             :     : public plugin_definition_value<version_t>
     203             : {
     204             : public:
     205             :     constexpr plugin_library_version()
     206             :         : plugin_definition_value<version_t>(version_t())
     207             :     {
     208             :     }
     209             : 
     210           1 :     constexpr plugin_library_version(version_t version)
     211           1 :         : plugin_definition_value<version_t>(version)
     212             :     {
     213           1 :     }
     214             : };
     215             : 
     216             : 
     217             : class plugin_last_modification
     218             :     : public plugin_definition_value<time_t>
     219             : {
     220             : public:
     221             :     constexpr plugin_last_modification()
     222             :         : plugin_definition_value<time_t>(time_t())
     223             :     {
     224             :     }
     225             : 
     226           1 :     constexpr plugin_last_modification(time_t const last_modification)
     227           1 :         : plugin_definition_value<time_t>(validate_date(last_modification))
     228             :     {
     229           1 :     }
     230             : };
     231             : 
     232             : 
     233             : class plugin_name
     234             :     : public plugin_definition_value<char const *>
     235             : {
     236             : public:
     237             :     constexpr plugin_name()
     238             :         : plugin_definition_value<char const *>(nullptr)
     239             :     {
     240             :     }
     241             : 
     242             :     template<int N>
     243           1 :     constexpr plugin_name(char const (&name)[N])
     244           1 :         : plugin_definition_value<char const *>(validate_name(name))
     245             :     {
     246           1 :     }
     247             : };
     248             : 
     249             : 
     250             : class plugin_description
     251             :     : public plugin_definition_value<char const *>
     252             : {
     253             : public:
     254           1 :     constexpr plugin_description()
     255           1 :         : plugin_definition_value<char const *>(nullptr)
     256             :     {
     257           1 :     }
     258             : 
     259           1 :     constexpr plugin_description(char const * description)
     260           1 :         : plugin_definition_value<char const *>(description)
     261             :     {
     262           1 :     }
     263             : };
     264             : 
     265             : 
     266             : class plugin_help_uri
     267             :     : public plugin_definition_value<char const *>
     268             : {
     269             : public:
     270           1 :     constexpr plugin_help_uri()
     271           1 :         : plugin_definition_value<char const *>(nullptr)
     272             :     {
     273           1 :     }
     274             : 
     275           1 :     constexpr plugin_help_uri(char const * help_uri)
     276           1 :         : plugin_definition_value<char const *>(help_uri)
     277             :     {
     278           1 :     }
     279             : };
     280             : 
     281             : 
     282             : class plugin_icon
     283             :     : public plugin_definition_value<char const *>
     284             : {
     285             : public:
     286           1 :     constexpr plugin_icon()
     287           1 :         : plugin_definition_value<char const *>(nullptr)
     288             :     {
     289           1 :     }
     290             : 
     291           1 :     constexpr plugin_icon(char const * icon)
     292           1 :         : plugin_definition_value<char const *>(icon)
     293             :     {
     294           1 :     }
     295             : };
     296             : 
     297             : 
     298             : class plugin_categorization_tag
     299             :     : public plugin_definition_value<char const *>
     300             : {
     301             : public:
     302             :     //constexpr plugin_categorization_tag()
     303             :     //    : plugin_definition_value<char const *>()
     304             :     //{
     305             :     //}
     306             : 
     307             :     template<int N>
     308           3 :     constexpr plugin_categorization_tag(char const (&tag)[N])
     309           3 :         : plugin_definition_value<char const *>(validate_name(tag))
     310             :     {
     311           3 :     }
     312             : };
     313             : 
     314             : 
     315             : class plugin_dependencies
     316             :     : public plugin_definition_value<char const *>
     317             : {
     318             : public:
     319             :     constexpr plugin_dependencies()
     320             :         : plugin_definition_value<char const *>(nullptr)
     321             :     {
     322             :     }
     323             : 
     324             :     template<int N>
     325             :     constexpr plugin_dependencies(char const (&dependencies)[N])
     326             :         : plugin_definition_value<char const *>(validate_name(dependencies))
     327             :     {
     328             :     }
     329             : };
     330             : 
     331             : 
     332             : class plugin_conflicts
     333             :     : public plugin_definition_value<char const *>
     334             : {
     335             : public:
     336             :     constexpr plugin_conflicts()
     337             :         : plugin_definition_value<char const *>(nullptr)
     338             :     {
     339             :     }
     340             : 
     341             :     template<int N>
     342           3 :     constexpr plugin_conflicts(char const (&conflicts)[N])
     343           3 :         : plugin_definition_value<char const *>(validate_name(conflicts))
     344             :     {
     345           3 :     }
     346             : };
     347             : 
     348             : 
     349             : class plugin_suggestions
     350             :     : public plugin_definition_value<char const *>
     351             : {
     352             : public:
     353             :     constexpr plugin_suggestions()
     354             :         : plugin_definition_value<char const *>(nullptr)
     355             :     {
     356             :     }
     357             : 
     358             :     template<int N>
     359           1 :     constexpr plugin_suggestions(char const (&suggestions)[N])
     360           1 :         : plugin_definition_value<char const *>(validate_name(suggestions))
     361             :     {
     362           1 :     }
     363             : };
     364             : 
     365             : 
     366             : 
     367             : 
     368             : 
     369             : 
     370             : template<typename T, typename F, class ...ARGS>
     371           7 : constexpr typename std::enable_if<std::is_same<T, F>::value, typename T::value_t>::type find_plugin_information(F first, ARGS ...args)
     372             : {
     373           7 :     snap::NOT_USED(args...);
     374           7 :     return first.get();
     375             : }
     376             : 
     377             : 
     378             : template<typename T, typename F, class ...ARGS>
     379          21 : constexpr typename std::enable_if<!std::is_same<T, F>::value, typename T::value_t>::type find_plugin_information(F first, ARGS ...args)
     380             : {
     381          21 :     snap::NOT_USED(first);
     382          21 :     return find_plugin_information<T>(args...);
     383             : }
     384             : 
     385             : 
     386             : 
     387             : 
     388             : 
     389             : template<typename T, typename F>
     390           1 : typename std::enable_if<std::is_same<T, F>::value, string_set_t>::type find_plugin_set(F first)
     391             : {
     392           1 :     string_set_t s;
     393           1 :     s.insert(first.get());
     394           1 :     return s;
     395             : }
     396             : 
     397             : 
     398             : template<typename T, typename F>
     399           3 : typename std::enable_if<!std::is_same<T, F>::value, string_set_t>::type find_plugin_set(F first)
     400             : {
     401           3 :     snap::NOT_USED(first);
     402           3 :     return string_set_t();
     403             : }
     404             : 
     405             : 
     406             : template<typename T, typename F, class ...ARGS>
     407           6 : typename std::enable_if<std::is_same<T, F>::value && (sizeof...(ARGS) > 0), string_set_t>::type find_plugin_set(F first, ARGS ...args)
     408             : {
     409           6 :     string_set_t s(find_plugin_set<T>(args...));
     410           6 :     s.insert(first.get());
     411           6 :     return s;
     412             : }
     413             : 
     414             : 
     415             : template<typename T, typename F, class ...ARGS>
     416          46 : typename std::enable_if<!std::is_same<T, F>::value && (sizeof...(ARGS) > 0), string_set_t>::type find_plugin_set(F first, ARGS ...args)
     417             : {
     418          46 :     snap::NOT_USED(first);
     419          46 :     return find_plugin_set<T>(args...);
     420             : }
     421             : 
     422             : 
     423             : 
     424             : template<class ...ARGS>
     425           1 : constexpr plugin_definition define_plugin(ARGS ...args)
     426             : {
     427             : #pragma GCC diagnostic push
     428             : #pragma GCC diagnostic ignored "-Wpedantic"
     429           5 :     plugin_definition def =
     430             :     {
     431             :         .f_version =                find_plugin_information<plugin_version>(args...),               // no default, must be defined
     432             :         .f_library_version =        find_plugin_information<plugin_library_version>(args...),       // no default, must be defined
     433           1 :         .f_last_modification =      find_plugin_information<plugin_last_modification>(args...),     // no default, must be defined
     434             :         .f_name =                   find_plugin_information<plugin_name>(args...),                  // no default, must be defined
     435           1 :         .f_description =            find_plugin_information<plugin_description>(args..., plugin_description()),
     436           1 :         .f_help_uri =               find_plugin_information<plugin_help_uri>(args..., plugin_help_uri()),
     437           1 :         .f_icon =                   find_plugin_information<plugin_icon>(args..., plugin_icon()),
     438             :         .f_categorization_tags =    find_plugin_set<plugin_categorization_tag>(args...),
     439             :         .f_dependencies =           find_plugin_set<plugin_dependencies>(args...),
     440             :         .f_conflicts =              find_plugin_set<plugin_conflicts>(args...),
     441             :         .f_suggestions =            find_plugin_set<plugin_suggestions>(args...),
     442             :     };
     443             : #pragma GCC diagnostic pop
     444             : 
     445           1 :     return def;
     446             : }
     447             : 
     448             : 
     449             : 
     450             : 
     451             : 
     452             : 
     453          88 : class plugin_paths
     454             : {
     455             : public:
     456             :     typedef std::string                 path_t;
     457             :     typedef std::vector<std::string>    paths_t;
     458             : 
     459             :     std::size_t                         size() const;
     460             :     std::string                         at(std::size_t idx) const;
     461             :     void                                set_allow_redirects(bool allow = true);
     462             :     bool                                get_allow_redirects() const;
     463             :     path_t                              canonicalize(path_t const & path);
     464             :     void                                push(path_t const & path);
     465             :     void                                add(std::string const & paths);
     466             :     void                                erase(std::string const & path);
     467             : 
     468             : private:
     469             :     paths_t                             f_paths = paths_t();
     470             :     bool                                f_allow_redirects = false;
     471             : };
     472             : 
     473             : 
     474          12 : class plugin_names
     475             : {
     476             : public:
     477             :     typedef std::string                     name_t;
     478             :     typedef std::string                     filename_t;
     479             :     typedef std::map<name_t, filename_t>    names_t;
     480             : 
     481             :                                         plugin_names(plugin_paths const & paths, bool script_names = false);
     482             : 
     483             :     bool                                validate(name_t const & name);
     484             :     bool                                is_emcascript_reserved(std::string const & word);
     485             : 
     486             :     filename_t                          to_filename(name_t const & name);
     487             :     void                                push(name_t const & name);
     488             :     void                                add(std::string const & set);
     489             :     names_t                             names() const;
     490             : 
     491             :     void                                find_plugins(name_t const & prefix = name_t(), name_t const & suffix = name_t());
     492             : 
     493             : private:
     494             :     plugin_paths const                  f_paths;
     495             :     bool const                          f_prevent_script_names = false;
     496             :     names_t                             f_names = names_t();
     497             : };
     498             : 
     499             : 
     500             : 
     501             : 
     502             : 
     503             : class plugin;
     504             : 
     505             : 
     506             : class plugin_factory
     507             : {
     508             : public:
     509             :                                     plugin_factory(plugin_definition const & definition, std::shared_ptr<plugin> instance);
     510             :                                     ~plugin_factory();
     511             :                                     plugin_factory(plugin_factory const &) = delete;
     512             :     plugin_factory &                operator = (plugin_factory const &) = delete;
     513             : 
     514             :     plugin_definition const &       definition() const;
     515             :     std::shared_ptr<plugin>         instance() const;
     516             :     void                            register_plugin(char const * name, std::shared_ptr<plugin> p);
     517             : 
     518             : private:
     519             :     plugin_definition const &       f_definition;
     520             :     std::shared_ptr<plugin>         f_plugin = std::shared_ptr<plugin>();
     521             : };
     522             : 
     523             : 
     524             : 
     525             : 
     526             : class plugin
     527             : {
     528             : public:
     529             :     typedef std::shared_ptr<plugin>     pointer_t;
     530             :     typedef std::vector<pointer_t>      vector_t;       // sorted by dependencies & then by name
     531             :     typedef std::map<std::string, pointer_t>
     532             :                                         map_t;          // sorted by name
     533             : 
     534             :                                         plugin(plugin_factory const & factory);
     535             :                                         plugin(plugin const &) = delete;
     536             :     virtual                             ~plugin();
     537             :     plugin &                            operator = (plugin const &) = delete;
     538             : 
     539             :     version_t                           version() const;
     540             :     time_t                              last_modification() const;
     541             :     plugin_names::name_t                name() const;
     542             :     plugin_names::filename_t            filename() const;
     543             :     std::string                         description() const;
     544             :     std::string                         help_uri() const;
     545             :     std::string                         icon() const;
     546             :     string_set_t                        categorization_tags() const;
     547             :     string_set_t                        dependencies() const;
     548             :     string_set_t                        conflicts() const;
     549             :     string_set_t                        suggestions() const;
     550             : 
     551             :     virtual void                        bootstrap(void * data);
     552             : 
     553             : private:
     554             :     friend class detail::plugin_repository;
     555             : 
     556             :     plugin_factory const &              f_factory;
     557             :     plugin_names::filename_t            f_filename = std::string();
     558             : };
     559             : 
     560             : 
     561             : #define CPPTHREAD_PLUGIN_DEFAULTS(name) \
     562             :     public: \
     563             :     typedef std::shared_ptr<name> pointer_t; \
     564             :     name(); \
     565             :     virtual ~name(); \
     566             :     static pointer_t instance();
     567             :     
     568             : 
     569             : 
     570             : 
     571           1 : class plugin_collection
     572             : {
     573             : public:
     574             :     typedef std::shared_ptr<plugin_collection>  pointer_t;
     575             : 
     576             :                                         plugin_collection(plugin_names const & names);
     577             :                                         plugin_collection(plugin_collection const &) = delete;
     578             :     plugin_collection &                 operator = (plugin_collection const &) = delete;
     579             : 
     580             :     bool                                load_plugins();
     581             :     bool                                is_loaded(std::string const & name) const;
     582             : 
     583             :     /** \brief Retrieve a plugin from this collection.
     584             :      *
     585             :      * This function searches for a plugin by the given name in this collection.
     586             :      *
     587             :      * Note that different collections can share the same plugin (if the filenames
     588             :      * are the same) and one collection may know about a plugin and another
     589             :      * collection may not know about a plugin. At this time, the library does not
     590             :      * offer a direct access to the global list so you can't determine whether
     591             :      * a specific plugin is loaded through a plugin_collection.
     592             :      *
     593             :      * \param[in] name  The name of the plugin to search.
     594             :      *
     595             :      * \return The pointer to the plugin if found, nullptr otherwise.
     596             :      */
     597             :     template<class T>
     598           1 :     typename T::pointer_t               get_plugin_by_name(std::string const & name)
     599             :     {
     600           1 :         auto it(f_plugins_by_name.find(name));
     601           1 :         if(it != f_plugins_by_name.end())
     602             :         {
     603           1 :             return std::static_pointer_cast<T>(it->second);
     604             :         }
     605             : 
     606           0 :         return typename T::pointer_t();
     607             :     }
     608             : 
     609             :     void                                set_data(void * data);
     610             : 
     611             : private:
     612             :     mutex                               f_mutex = mutex();
     613             :     plugin_names                        f_names;
     614             :     plugin::map_t                       f_plugins_by_name = plugin::map_t();        // plugins sorted by name only
     615             :     plugin::vector_t                    f_ordered_plugins = plugin::vector_t();     // sorted plugins
     616             :     void *                              f_data = nullptr;
     617             : };
     618             : 
     619             : 
     620             : 
     621             : 
     622             : #define CPPTHREAD_PLUGIN_START(name, major, minor) \
     623             :     ::cppthread::plugin_definition const g_plugin_##name##_definition = ::cppthread::define_plugin( \
     624             :           ::cppthread::plugin_version(::cppthread::version_t(major, minor, 0)) \
     625             :         , ::cppthread::plugin_library_version(::cppthread::version_t(CPPTHREAD_VERSION_MAJOR, CPPTHREAD_VERSION_MINOR, CPPTHREAD_VERSION_PATCH)) \
     626             :         , ::cppthread::plugin_last_modification(UTC_BUILD_TIME_STAMP) \
     627             :         , ::cppthread::plugin_name(#name)
     628             : 
     629             : 
     630             : #define CPPTHREAD_PLUGIN_END(name) \
     631             :     ); \
     632             :     class plugin_##name##_factory : public ::cppthread::plugin_factory { \
     633             :     public: plugin_##name##_factory() \
     634             :         : plugin_factory(g_plugin_##name##_definition, std::make_shared<name>()) \
     635             :         { register_plugin(#name, instance()); } \
     636             :     plugin_##name##_factory(plugin_##name##_factory const &) = delete; \
     637             :     plugin_##name##_factory & operator = (plugin_##name##_factory const &) = delete; \
     638             :     } g_plugin_##name##_factory; \
     639             :     name::name() : plugin(g_plugin_##name##_factory) {} \
     640             :     name::~name() {} \
     641             :     name::pointer_t name::instance() { return std::static_pointer_cast<name>(g_plugin_##name##_factory.instance()); }
     642             : 
     643             : 
     644             : 
     645             : 
     646             : } // namespace cppthread
     647             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13