GithubHelp home page GithubHelp logo

gracicot / kangaru Goto Github PK

View Code? Open in Web Editor NEW
470.0 470.0 39.0 1.57 MB

๐Ÿฆ˜ A dependency injection container for C++11, C++14 and later

License: MIT License

CMake 2.69% C++ 97.31%
c-plus-plus dependency-injection injection inversion-of-control ioc ioc-container

kangaru's Introduction

  • ๐Ÿ‘‹ Hi, Iโ€™m Guillaume Racicot
  • I'm interested in developer experience, build system and libraries.
  • When developers make a mess, it's because they lack the tools they needed
  • I make the tools, usually in the form of library, dev environments and frameworks.
  • I mostly do C++, lil bit of rust on the side
  • I love high throughput, performance sensitive code with a sprinkle of linear algebra

kangaru's People

Contributors

codacy-badger avatar d1amond avatar denisss025 avatar dirtybirthdaycake avatar gracicot avatar lracicot avatar robertbernstein avatar ruanwenfeng avatar spaceim avatar wopss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kangaru's Issues

The container ignore noexcept specifications

Currently, the container will ignore noexcept, even if a service can be constructed with a constructor marked as noexcept. the function kgr::Container::service should be aware of noexcept specifications.

Supplying an already constructed service via emplace

Hi,

I would like to use the container with services that are generated outside of the container by another system. I would like to avoid having to emplace every new container managed service that has a dependency on an externally managed service. Ideally I would like something that allows me to register into the container and already constructed service that can later be automaticlly injected. In spring this would be something like the registerSingleton method.

Is this something that is already possible?

Thanks
Andre

Remove the use of macros in kgr::Autocall

Right now, to use kgr::Autocall with a relatively nice syntax, you must use a macro that expands into kgr::Method with the name of the function present two times.

With C++17, we could define kgr::AutoCall a bit like that:

template<auto... functions>
struct Autocall {
    // ...
};

Allow reference services

A common way right now to have an externally provided service instance is by using a single service which is a pointer type. That pointer points to the designated instance when instantiating the service using emplace:

kgr::container c;
c.emplace<ExternService>(&instance);

Then, it also requires specifying how the injection is done, since we need to dereference it:

struct ExternService : kgr::single_service<Extern*>, kgr::supplied {
    Extern& forward() const {
        return *instance();
    }
};

It would be great to allow reference service types. That way, injection is done by default like a normal single service, and construction will be done by reference too.

Detect problems in construct function, abstract services and autocall

Since version 3.1.0, we check for the validity of services, dependencies and constructors. Now that we have that kind of problem detection, we can extend it to allow checking for more potential problem and give meaningful message to the user. Right now, the biggest issues are:

  • Construct function problem. Is the construct function is callable with given parameters?
  • Autocall. Are every services are okay and is the service map filled?
  • Abstract service: we have a check, but it could be way better. We could check if the service in kgr::Default is valid and if it overrides the abstract service
  • Enforce correctness: kgr::Default has no meaning if the service is not abstract. It should be rejected.
  • Maybe others?

Measure and optimize template compiling time

Compiling times can rapidly become a concern when introducing a template-heavy library into a codebase. We should measure bottlenecks compilers have when compiling code that uses kangaru.

Tools such as Templight is a good start.

Any help or requests regarding this issue is welcomed.

kgr::autocall causes errors when used on a pointer based service

This code produces a compilation error:

struct some_class { void func(){}};
struct some_service :  kgr::shared_service<some_class>,
    kgr::autocall<kgr::method<decltype(&some_class::func), &some_class::func>> {};

kgr::container{}.sevice<some_service>();

This will fail because the wrong syntax has been used to call pointer to member function on a std::unique_ptr.

Comments needed

I like the quantity of comments inside container.hpp. However, I cannot say the same for other files and classes. Comments need to be added if we want other developpers to be able to read our code.

Generic lambda are instanciated with wrong type when not using references

In version 3.3.x, generic lambda are supported. However, since almost the same code as construct function extraction has been used, types sent as template parameters are the same received in invoke. Then, if a generic lambda has this form:

double d = 9.2;
auto function = [](auto) {};

kgr::Container{}.invoke(function, d);

First, the function is instanciated using double& as template parameter when taking the function pointer. Then, it is instantiated again by the function call, which makes the parameter deduced as double.

I don't know if it's fixable, but hopefully yes. Maybe some dark sfinae tricks can help us, but I'm not sure.

Support for service defined locally

When writing tests, I stumble across an error that basically said that function such as construct function could not been sent as a template argument to std::integral_constant because it needs linkage.

Well we understand the error, I think it's easily avoidable. instead of sending the pointer to member as template argument to integral constant, we can just define value and value_type inside a struct.

The order of destruction is wrong

When using service that refers on each other on destruction, you're up for a bad time un kangaru:

struct A { int boom; };
struct B {
    A& a;

    ~B() {
        if (a.boom) {} // boom
    }
};

struct AService : kgr::single_service<A> {};
struct BService : kgr::single_service<B, kgr::dependency<AService>> {};

int main() {
    kgr::container{}.service<BService>(); // boom
}

This code uses freed memory because it deletes A before B, which we think it's wrong, the container should guarantee that since B depends on A, A should be useable throughout the whole lifetime of B.

Clang 3.5 build breaks

Current clang 3.5 build are failing. The code is compiling, but it seems tests are segfaulting all over the place.

Enable autowire by default

We should explore the possibility to enable autowire on all services by default.

With the dev-4.1.x branch, the current code is possible:

struct my_service {
    // The two members are autowired
    kgr::container& c;
    kgr::invoker i;
};

struct definition : kgr::service<my_service, kgr::autowire> {};

Currently, the default dependencies are kgr::dependency<>, which means that kgr::service<my_service> has no dependencies injected. This means that services that uses the default argument has no parameter injected to it, and enabling autowire by default will still inject no dependency.

Custom error message don't work since GCC 8

We provided custom compilation error messages. It doesn't really work right now, and it barely worked with provided services. We should try to overhaul the error system and make it work properly.

Support autowiring services

Automatic configuration from a class constructor would be really nice. We could add a service that tries to construct a class from its constructor parameter.

emplace fails to supply a shared_service

If I use a shared_service with kgr::supplied to pass some arbitrary values to constructor, when I try to emplace(), I get a compilation error. I thought that shared_service, by inheriting kgr::single, could be used with kgr::supplied.

Remove support for emplace construction in definitions

Right now, we are accepting definition to provide a emplace function as an alternative of a constructor that receives kgr::in_place_t. For example:

struct Service {};
struct Definition {
//  Definition(kgr::in_place_t) {}

    // The container will pick this one when the constructor is commented out.
    void emplace() {}

    static auto construct() -> kgr::inject_result<> { return {}; }
    Service forward() { return {}; }
};

This was because for constructor to be usable with base classes, we had to inherit constructors explicitly, which wasn't gret of a syntax when creating definition. Instead, we opted for a default constructible storage and an emplace function.

In C++17, empty service definition are considered aggregates, since they have no members nor virtual function. This makes the base class constructor visible:

struct A {
    A(int) {}
};

struct B : A {};

auto b = B{1};

This makes the emplace function useless. We should remove them as soon as we upgrade to C++17

Allow multiple maps with different priorities in AdlMap

AdlMap right now can have one global map. Allowing multiple profile of service map would solve that issue. The struct kgr::Map is perfect for that:

auto service_map(Some) -> SomeService;
auto service_map(Some, kgr::Map<Alternate>) -> SomeAlternateService;
auto service_map(Some, kgr::Map<Another>) -> SomeAnotherService;

auto service_map(SomeOther) -> SomeOtherService;

Then, when calling invoke:

container.invoke<kgr::Map<Alternate>>([](Some, SomeOther){
    // SomeAlternate and SomeOther is picked
});

The thing here is it work by priority. The first has the hightest priority. It will fallback to the one with empty map kgr::Map<> or at the end the one with no map specified.

This kind of map profile could be used with kgr::Invoke:

struct SomeService : kgr::Service<Some>, kgr::AutoCall<
    kgr::Invoke<&Some::function, kgr::Map<Alternate>>
> {};

The state of service map is awful

Currently, kangaru suggest users to define the whole service maps. This has the effect of the user needing to "send" the service map to the container and can easily lead to fragmented maps.

Another problem is that the service map won't follow basic parameter rules like cv qualifier. This needs to be fixed, especially in the version 4.

Add unit tests for service errors

Service error are the facility that output an error message when a service definition is not well formed, or it's usage with the container is invalid. Each time new checks are added and each time there's a new feature, we get regressions in the quality of error messages.

We should add tests that checks if the right error is outputted for particular case. It wil prevent regressions in the future and will enable us to provide better diagnostics.

Support trivially copiable/movable/destructible in kgr::Lazy

Right now, the kgr::Lazy wrapper is implementing a custom copy and move constructor, and forcebly add a destructor, making it itself a non trivially copiable/moveable/destructible type. This could speed up the wrapper and making it lighter.

Support CI

It would be awesome to support testing and CI, like travis or others.

Provide an easy way to enable autocall

Right now, autocall only works with kgr::GenericService. However, the usage of this service may not be preferred. When creating a custom service, autocall won't work and it's very unfortunate. We should provide an easy way to unable autocall in custom services.

GenericService don't properly call destructors

Affected versions: v3.2.0, v3.2.1

No destructors are called in kgr::GenericService. This is due to not properly extending kgr::detail::GenericServiceDestruction. Should be fixed ASAP

Allow more form of template function for construct

Right now, construct is either not a template or a function template of this particular form:

template<typename... Args>
static auto construct(<services...>, Args&&...)

It is required right now that all forwarded argument fits into the pack. As such, this kind of form is not allowed:

// inside SomeService
template<typename... Args>
static auto construct(<services...>, int additionnalParameter1, Args&&...)

if we call service that way:

container.service<SomeService>(2, "some other arg", 3.2);

The logical thing to do would be to forward the int with the value of 2 to the parameter named additionnalParameter1. The container would have to deduce the pack to be {const char*, 3.2}, but right now uses all parameter to be in the pack, and will try to call construct<int, const char* 3.2>. Obviously the call fails.

The idea would be try different form of template parameter matching, validating the match by using sfinae. At first, we could allow the form we talked about here, dropping parameters from the pack one by one and try to call the function. Maybe later we could allow more forms of template function, but may slow down compilation.

Unwanted overhead in single services

Right now, every single service require a virtual dispatch to get the result, even when no Override is intended to be used. This overhead is avoidable.

Support final services

Currently, there is no way that a service cannot further be overrided. We should be able to detect is a service is final.

Find a consistent naming convention

A lot of names in the kgr namespace is either in camel case, or snake case. Even types and aliases are not consistent in their naming.

While changing naming convention, we propose to use the same naming convention as Boost and STL. So such code:

struct SomeService : kgr::Service<SomeClass, kgr::Dependency<OtherService>> {};

kgr::Container c;
auto i = c.service<kgr::InvokerService>();

will become:

struct SomeService : kgr::service<SomeClass, kgr::dependency<OtherService>> {};

kgr::container c;
auto i = c.service<kgr::invoker_service>();

To reduce transition friction, we propose to write a migration guide, and a shell script to help transition to the new version.

Make abstract service not abstract classes

Currently, abstract services are abstract classes. The thing is, it is no longer needed and it limits what we can do with abstract services. We think the best would be to change default implementations to use kgr::Abstract and still allow abstract classes for all 3.x.y versions, but disallow it for the 4.x.y versions.

type_id is not stable

kgr::type_id is not stable across compiler. For example, using clang and gcc for multiple TU will link, but will cause crashes because the id generated is different across compilers. We could see how ctti does it.

Add unit tests

To ensure the quality of this library and not introduce unwanted breaking change, we must have robust tests. It's more than late to add this. If we ever want this library to be taken seriously, we need testing.

Abstract service are broken in AdlMap

The mapped service reside in the return type of a function. It causes massive errors when an abstract service is mapped. We should find a solution ASAP to fix this.

Support service sources

Right now, the container has only one allocation strategy and one way to store services. What if one would like to control how services are allocated and where they are contained? We should explore solutions that would allow that.

Allow more than member function in Autocall

Right now, only member function are allowed in kgr::Autocall. I would be great to accept non member function too. Maybe we could start with supporting with non member function that takes a reference or a pointer to the service.

Split kangaru.hpp

What do you think about splitting kangaru.hpp into several files? The file growed from 200+ lines of code to 400+ lines of code.

I believe this would improve readability of the code. This would allow to minimize the number of merge conflicts.

I think about using such structure:

  • include/
    • detail/
      • InstanceHolder.hpp
      • CallbackHolder.hpp
      • util.hpp
    • kangaru.hpp

If single hpp file is a major feature of the library, we could create a script that converts all the hpp files into a single one.

Cleanup sfinae machinery

Our sfinae machinery is old. It uses the old method of doing stuff. We should find a way to cleanup the mess that it is right now and implement the traits in a way that is both compatible with visual studio 2015 and readable for mortals.

Here's the current plan:

  1. Find a way to expand an index sequence without using private member function
  2. Have clear semantics on what is checked and what is assumed
  3. Fix bug we deal today (lack of check with supplied services, visual studio's intellisense)
  4. Remove duplicated highly duplicated code in sfinae checks.

Use SBO for single service

Right now, we hold all services instances in unique pointers and we always use dynamic allocation. We could use SBO making single services effectively faster and consume less memory.

Add a bind functionality

It would be nice to be able to bind function. For example:

kgr::Container c;
auto func = c.bind([](SomeService ss, auto a, auto b, auto... additional) {
    // do stuff
}, 3, 7.6); // a is deduced to be int and b to be double

func(); // additional is empty
func("test", 123); // additional is {const char*, int}

As with other features dealing with the service map, the map or a list of services can be received:

kgr::Container c;
auto func1 = c.bind<SomeMap>([](SomeService ss) {});
auto func2 = c.bind<SomeServiceA, SomeServiceB>([](auto a, auto b) {});

Recursively detect service definition issues

Sometimes you can have a service definition that has errors in it. When you use it as a dependency or in autocall, it can be really hard to diagnose these errors. The container could use SFINAE to diagnose recursively errors and give a diagnostic to the user.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.