Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F114748
qfunctionutils.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
5 KB
Referenced Files
None
Subscribers
None
qfunctionutils.hpp
View Options
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2019 juangburgos <https://github.com/juangburgos/>
* SPDX-License-Identifier: MIT
*/
/// https://github.com/juangburgos/QFunctionUtils/blob/master/src/qfunctionutils.h
#pragma once
#include
<kazv-defs.hpp>
#include
<functional>
#include
<QSharedPointer>
#include
<QTimer>
namespace
QFunctionUtils
{
// function used to cache user arguments to be able to use them once timer times out
template
<
typename
R
,
class
...
Args
>
void
debounce_args_cache
(
const
std
::
function
<
R
(
Args
(...
args
))
>
&
funcFinish
,
Args
(
&
...
args
))
{
funcFinish
(
args
...);
}
typedef
QSharedPointer
<
QMetaObject
::
Connection
>
QMetaConnPtr
;
// debounce implementation
// gets a user defined function as an argument and a 'delay' in miliseconds
// returns a new function that the user can call many times, but will only execute the last
// call after 'delay' miliseconds have passed
template
<
typename
R
,
class
...
Args
>
std
::
function
<
R
(
Args
(...
args
))
>
debounce_internal
(
const
std
::
function
<
R
(
Args
(...
args
))
>
&
callback
,
const
int
&
delay
)
{
QTimer
*
timer
=
new
QTimer
;
QMetaConnPtr
conn
=
QMetaConnPtr
(
new
QMetaObject
::
Connection
,
[
timer
](
QMetaObject
::
Connection
*
pConn
)
mutable
{
// connection will be deleted when returned function goes out of scope, but not the timer
// so we need to delete it manually
delete
pConn
;
delete
timer
;
});
timer
->
setInterval
(
delay
);
// return function that the user can call
return
[
callback
,
timer
,
conn
](
Args
(...
args
))
{
// disconnect old timer callback, stop timer
QObject
::
disconnect
(
*
conn
);
timer
->
stop
();
// create function that caches user arguments
std
::
function
<
void
(
std
::
function
<
R
(
Args
(...
args
))
>
)
>
funcCache
=
std
::
bind
(
debounce_args_cache
<
R
,
Args
...
>
,
std
::
placeholders
::
_1
,
args
...);
// connect new timer callback, restart timer
*
conn
=
QObject
::
connect
(
timer
,
&
QTimer
::
timeout
,
[
callback
,
timer
,
funcCache
]()
{
// stop timer
timer
->
stop
();
// call after delay
funcCache
(
callback
);
});
timer
->
start
();
// return default constructed return type (just to support any return type)
return
R
();
};
}
// throttle implementation
// same as debounce, but also calls the given function the first time is called
template
<
typename
R
,
class
...
Args
>
std
::
function
<
R
(
Args
(...
args
))
>
throttle_internal
(
const
std
::
function
<
R
(
Args
(...
args
))
>
&
callback
,
const
int
&
delay
)
{
QTimer
*
timer
=
new
QTimer
;
QMetaConnPtr
conn
=
QMetaConnPtr
(
new
QMetaObject
::
Connection
,
[
timer
](
QMetaObject
::
Connection
*
pConn
)
mutable
{
// same logic as in debounce_internal
delete
pConn
;
delete
timer
;
});
timer
->
setInterval
(
delay
);
// return function that the user can call
return
[
callback
,
timer
,
conn
](
Args
(...
args
))
{
// disconnect old timer callback
QObject
::
disconnect
(
*
conn
);
// check timer (throttle) state
if
(
!
timer
->
isActive
())
{
// connect new timer callback
*
conn
=
QObject
::
connect
(
timer
,
&
QTimer
::
timeout
,
[
timer
]()
{
// stop timer only (this happens if user did not call the function during the delay)
timer
->
stop
();
});
// start timer to start throttle
timer
->
start
();
// call inmediatly and return
return
callback
(
args
...);
}
// create function that caches user arguments
std
::
function
<
void
(
std
::
function
<
R
(
Args
(...
args
))
>
)
>
funcCache
=
std
::
bind
(
debounce_args_cache
<
R
,
Args
...
>
,
std
::
placeholders
::
_1
,
args
...);
// connect new timer callback
*
conn
=
QObject
::
connect
(
timer
,
&
QTimer
::
timeout
,
[
callback
,
timer
,
funcCache
]()
{
// stop timer
timer
->
stop
();
// call after delay
funcCache
(
callback
);
});
// return default constructed return type (just to support any return type)
return
R
();
};
}
// for any class implementing operator() (e.g. lambdas)
template
<
typename
T
>
struct
functor_traits
:
functor_traits
<
decltype
(
&
T
::
operator
())
>
{
};
// specialization - lambda
template
<
typename
C
,
typename
R
,
typename
...
Args
>
struct
functor_traits
<
R
(
C
::*
)(
Args
...)
const
>
{
using
lambda_type
=
std
::
function
<
R
(
Args
...)
>
;
};
// specialization - lambda mutable
template
<
typename
C
,
typename
R
,
typename
...
Args
>
struct
functor_traits
<
R
(
C
::*
)(
Args
...)
>
{
using
lambda_type
=
std
::
function
<
R
(
Args
...)
>
;
};
// specialization - function pointer
template
<
class
R
,
class
...
Args
>
struct
functor_traits
<
R
(
*
)(
Args
...)
>
{
using
lambda_type
=
std
::
function
<
R
(
Args
...)
>
;
};
// wrap any of the specializations above into an std::function
template
<
typename
T
>
auto
make_std_function
(
const
T
&
fn
)
->
typename
functor_traits
<
T
>::
lambda_type
{
return
typename
functor_traits
<
T
>::
lambda_type
(
fn
);
}
// convert callback into std::function and call internal debounce
template
<
typename
T
>
auto
Debounce
(
T
callback
,
const
int
&
delay
)
->
typename
functor_traits
<
T
>::
lambda_type
{
return
debounce_internal
(
make_std_function
(
callback
),
delay
);
}
// convert callback into std::function and call internal throttle
template
<
typename
T
>
auto
Throttle
(
T
callback
,
const
int
&
delay
)
->
typename
functor_traits
<
T
>::
lambda_type
{
return
throttle_internal
(
make_std_function
(
callback
),
delay
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Tue, Nov 26, 2:17 PM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40372
Default Alt Text
qfunctionutils.hpp (5 KB)
Attached To
Mode
rK kazv
Attached
Detach File
Event Timeline
Log In to Comment