Git Product home page Git Product logo

convw's Introduction

Convw

Convenient Callback Wrapper is a header only library that allows to omit any arguments in a callback:

using Cb = void (int, float, double); // required callback signature
void work(Convw<Cb> callback) { callback(1, 2.0f, 3.0); } // return some values

// then call function, but wee need only x from the passed arguments
work([](float x) { cout << x << std::endl; }); // outputs: 2
work([](int x, double y) { cout << x + y << std::endl; }); // outputs: 4

Since argument types are used to determine which arguments are to be passed, natural limitation is that you can only omit arguments based on their type order

using Cb = void (int, int); // required callback signature
void work(Convw<Cb> callback) { callback(1, 2); } // return some values

work([](int x) { cout << x << std::endl; }); // outputs: 1
// but we can't access second int without receiving the first in :(
//work([](int ?y?) { cout << ?y? << std::endl; });

Usage

#include "convw/convw.hpp"

using Callback = /* callback signature */;

// conveniently wrapping a callback
auto wrapped = sq::convw::convw<Callback>(callback);
wrapped(...);

// conveniently wrapping a callback into object (redundant in this case)
auto wrappedObj = sq::Convw<Callback>{callback};
wrappedObj(...);

More complicated example

Simplified real-life example that was a motivation for the library

#include "convw/convw.hpp"

#include <iostream>

// lets make it brief
using namespace sq;
using convw::Convw;
using convw::convw;
using namespace std;
using Peer = int;
using Packet = int;

using Cb = void (uint64_t time, const Peer&, Packet&&);

struct Host {
    void onConnect(Convw<Cb> cb) { cb_ = std::move(cb); }
    void connect() { cb_(1, 2, 3); }
    Convw<Cb> cb_;
};

// NOTE: Neither server nor client override onConnect method to supply different
// arguments that hosts sends that may not be applicable to their specific
// use cases
struct Client : public Host { };
struct Server : public Host { };

// normally client and server are created in different executables
int main()
{
    Server server{};
    Client client{};

    // we don't need to know time in this particular case
    server.onConnect([](const Peer& peer, Packet&& packet){
        cout << peer << " Connected saying: " << packet << endl;
    });

    // we don't need to know who is sending packet since we are only connected
    // to one server
    client.onConnect([](Packet&& packet) {
        cout << "Server says: " << packet << endl;
    });

    // some task that handles connection calls internally
    client.connect();
    server.connect();
}
  • Think how it would be implemented without this library (not too hard though)
  • Now imagine we add another argument to the callback - only 2 places must be changed if you are using this library - callback type and the call

More applications

  • Callback that are called in more general callbacks which are called in even more general callback
  • Callback array/vector (since all types are the same after conversion)

Brief Docs

sq::convw::convw<Callback> function

Wraps provided callable type into Convenient Callback

sq::convw::Convw<Callback> class

Automatically wraps its constructor argument into Convenient callback. Quite useful as a function argument, since automatically wraps lambdas and other callable types

Contains a single std::function object and mimics its behavior

Performance

Yes, we lose it. There should be a balance between development time and execution performance, in this case its negligible. By ineffectively using this library the worst achieved performance loss was 30%.

That said, if we store wrapped callback and not regenerating it, the benchmark shows following results (BM_Target) is a wrapped callback

Benchmark            Time(ns)    CPU(ns) Iterations
BM_Hardcoded_Full        1072       1072     648148
BM_Hardcoded_Wrap        1065       1067     654206
BM_Hardcoded_Empty       1065       1067     654206
BM_Target_Full           1081       1083     648148
BM_Target_Wrap           1141       1143     619469
BM_Target_Empty          1121       1122     614035

When compiled with -O3 performance loss isn't noticeable

Benchmark            Time(ns)    CPU(ns) Iterations
BM_Hardcoded_Full         133        133    5263158
BM_Hardcoded_Wrap         132        132    5185185
BM_Hardcoded_Empty        132        133    5303030
BM_Target_Full            133        133    5223881
BM_Target_Wrap            134        135    5223881
BM_Target_Empty           135        135    5223881

How many object copy/moves are performed

  • Copy/Moves - reference/pointer passing which may take place are not taken into account
  • Function either match in signature or arguments are omitted. Either way callable is wrapped at least once (not necessarily by this library) which affects performance
  • Left side shows how parameters are passed into the callback
  • Typically callback can only receive values the same way the are passed
match omitted
value* 1 / 1 1 / 3
ref** 0 / 0 0 / 0
rvalue 0 / 0 0 / 0
rvalue*** 0 / 2 0 / 2

* can also be received by rvalue

** includes const ref, pointer and const pointer

*** if received by value

Requirements

Build all tests and benchmarks

mkdir -p build && cd build && cmake .. && make
  • Benchmarks will reside in /benchmark-bin
  • Tests will reside in /test-bin
  • Testing and benchmarking was only done on linux using GCC 5.3

Run All Tests

Build first

cd build # have to be in build directory
make test

convw's People

Contributors

squ1rr avatar

Watchers

 avatar

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.