[DEV] function
This commit is contained in:
parent
628146c380
commit
4abbcad222
137
etk/Function.hpp
137
etk/Function.hpp
@ -9,27 +9,120 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace etk {
|
namespace etk {
|
||||||
/**
|
template <typename ETK_TYPE_FUNCTION>
|
||||||
* @brief Generic Thread interface (OS independent)
|
class Function;
|
||||||
*/
|
template <typename ETK_TYPE_FUNCTION_RETURN, typename... ETK_TYPE_FUNCTION_ARGS>
|
||||||
template<class ETK_TYPE_FUNCTION>
|
class Function<ETK_TYPE_FUNCTION_RETURN(ETK_TYPE_FUNCTION_ARGS...)> {
|
||||||
class Function {
|
// function pointer types for the type-erasure behaviors
|
||||||
private:
|
// all these char* parameters are actually casted from some functor type
|
||||||
#ifdef __TARGET_OS__Windows
|
typedef ETK_TYPE_FUNCTION_RETURN (*invoke_fn_t)(char*, ETK_TYPE_FUNCTION_ARGS&&...);
|
||||||
|
typedef void (*construct_fn_t)(char*, char*);
|
||||||
#else
|
typedef void (*destroy_fn_t)(char*);
|
||||||
pthread_mutex_t m_thread;
|
|
||||||
#endif
|
// type-aware generic functions for invoking
|
||||||
uint32_t m_uid; //!< unique id of the thread
|
// the specialization of these functions won't be capable with
|
||||||
etk::String m_name; //!< Name of the thread (do not get it on the system ==> more portable)
|
// the above function pointer types, so we need some cast
|
||||||
etk::Function<void()> m_function; //!< Function to call every cycle of the thead running
|
template <typename ETK_TYPE_FUNCTION_FUNCTOR>
|
||||||
public:
|
static ETK_TYPE_FUNCTION_RETURN invoke_fn(ETK_TYPE_FUNCTION_FUNCTOR* _functor,
|
||||||
Thread(etk::Function<void()>&& _call, const std::string& _name);
|
ETK_TYPE_FUNCTION_ARGS&&... _args) {
|
||||||
~Thread();
|
return (*_functor)(std::forward<ETK_TYPE_FUNCTION_ARGS>(_args)...);
|
||||||
void join();
|
}
|
||||||
bool detach();
|
template <typename ETK_TYPE_FUNCTION_FUNCTOR>
|
||||||
void setName(const std::string& _name);
|
static void construct_fn(ETK_TYPE_FUNCTION_FUNCTOR* _constructDestination,
|
||||||
const std::string& setName() const;
|
ETK_TYPE_FUNCTION_FUNCTOR* _constructSource) {
|
||||||
uint32_t getIdentifier() const;
|
// the functor type must be copy-constructible
|
||||||
|
new (_constructDestination) Functor(*_constructSource);
|
||||||
|
}
|
||||||
|
template <typename ETK_TYPE_FUNCTION_FUNCTOR>
|
||||||
|
static void destroy_fn(ETK_TYPE_FUNCTION_FUNCTOR* _functor) {
|
||||||
|
_functor->~Functor();
|
||||||
|
}
|
||||||
|
// These pointers are storing behaviors.
|
||||||
|
invoke_fn_t invoke_f;
|
||||||
|
construct_fn_t construct_f;
|
||||||
|
destroy_fn_t destroy_f;
|
||||||
|
// Erase the type of any functor and store it into a char*
|
||||||
|
// so the storage size should be obtained as well
|
||||||
|
std::unique_ptr<char[]> m_dataPointer;
|
||||||
|
size_t m_dataSize;
|
||||||
|
public:
|
||||||
|
function()
|
||||||
|
: invoke_f(nullptr)
|
||||||
|
, construct_f(nullptr)
|
||||||
|
, destroy_f(nullptr)
|
||||||
|
, m_dataPointer(nullptr)
|
||||||
|
, m_dataSize(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// construct from any functor type
|
||||||
|
template <typename ETK_TYPE_FUNCTION_FUNCTOR>
|
||||||
|
Function(ETK_TYPE_FUNCTION_FUNCTOR _funtor)
|
||||||
|
// specialize functions and erase their type info by casting
|
||||||
|
: invoke_f(reinterpret_cast<invoke_fn_t>(invoke_fn<ETK_TYPE_FUNCTION_FUNCTOR>))
|
||||||
|
, construct_f(reinterpret_cast<construct_fn_t>(construct_fn<ETK_TYPE_FUNCTION_FUNCTOR>))
|
||||||
|
, destroy_f(reinterpret_cast<destroy_fn_t>(destroy_fn<ETK_TYPE_FUNCTION_FUNCTOR>))
|
||||||
|
, m_dataPointer(new char[sizeof(ETK_TYPE_FUNCTION_FUNCTOR)])
|
||||||
|
, m_dataSize(sizeof(ETK_TYPE_FUNCTION_FUNCTOR))
|
||||||
|
{
|
||||||
|
// copy the functor to internal storage
|
||||||
|
this->construct_f(this->m_dataPointer.get(), reinterpret_cast<char*>(&_functor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy constructor
|
||||||
|
Function(Function const& rhs):
|
||||||
|
invoke_f(rhs.invoke_f),
|
||||||
|
construct_f(rhs.construct_f)
|
||||||
|
destroy_f(rhs.destroy_f),
|
||||||
|
dataSize(rhs.dataSize) {
|
||||||
|
if (this->invoke_f) {
|
||||||
|
// when the source is not a null function, copy its internal functor
|
||||||
|
this->m_dataPointer.reset(new char[this->m_dataSize]);
|
||||||
|
this->construct_f(this->m_dataPointer.get(), rhs.m_dataPointer.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Function() {
|
||||||
|
if (m_dataPointer != nullptr) {
|
||||||
|
this->destroy_f(this->m_dataPointer.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// other constructors, from nullptr, from function pointers
|
||||||
|
|
||||||
|
ETK_TYPE_FUNCTION_RETURN operator()(ETK_TYPE_FUNCTION_ARGS&&... _args) {
|
||||||
|
return this->invoke_f(this->m_dataPointer.get(),
|
||||||
|
std::forward<ETK_TYPE_FUNCTION_ARGS>(_args)...);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
// examples
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
auto fn = [i](etk::String const& s) mutable
|
||||||
|
{
|
||||||
|
std::cout << ++i << ". " << s << std::endl;
|
||||||
|
};
|
||||||
|
fn("first"); // 1. first
|
||||||
|
fn("second"); // 2. second
|
||||||
|
|
||||||
|
// construct from lambda
|
||||||
|
::function<void(std::string const&)> f(fn);
|
||||||
|
f("third"); // 3. third
|
||||||
|
|
||||||
|
// copy from another function
|
||||||
|
::function<void(std::string const&)> g(f);
|
||||||
|
f("forth - f"); // 4. forth - f
|
||||||
|
g("forth - g"); // 4. forth - g
|
||||||
|
|
||||||
|
// capture and copy non-trivial types like std::string
|
||||||
|
std::string x("xxxx");
|
||||||
|
::function<void()> h([x]() { std::cout << x << std::endl; });
|
||||||
|
h();
|
||||||
|
|
||||||
|
::function<void()> k(h);
|
||||||
|
k();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
@ -324,7 +324,9 @@ const etk::String::Iterator etk::String::end() const {
|
|||||||
|
|
||||||
void etk::String::resize(size_t _newSize, char _value) {
|
void etk::String::resize(size_t _newSize, char _value) {
|
||||||
size_t oldSize = m_data.size();
|
size_t oldSize = m_data.size();
|
||||||
m_data[m_data.size()-1] = _value;
|
if (oldSize != 0) {
|
||||||
|
m_data[m_data.size()-1] = _value;
|
||||||
|
}
|
||||||
m_data.resize(_newSize + 1, _value);
|
m_data.resize(_newSize + 1, _value);
|
||||||
// in all case ==> we have the last element that is '\0'
|
// in all case ==> we have the last element that is '\0'
|
||||||
m_data[_newSize] = '\0';
|
m_data[_newSize] = '\0';
|
||||||
|
@ -190,7 +190,6 @@ namespace etk {
|
|||||||
* @return the reference on the current Element
|
* @return the reference on the current Element
|
||||||
*/
|
*/
|
||||||
ETK_VECTOR_TYPE* operator-> () const {
|
ETK_VECTOR_TYPE* operator-> () const {
|
||||||
//TK_CHECK_INOUT(m_current < m_vector->size());
|
|
||||||
return &m_vector->get(m_current);
|
return &m_vector->get(m_current);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -198,7 +197,6 @@ namespace etk {
|
|||||||
* @return the reference on the current Element
|
* @return the reference on the current Element
|
||||||
*/
|
*/
|
||||||
ETK_VECTOR_TYPE& operator* () const {
|
ETK_VECTOR_TYPE& operator* () const {
|
||||||
//TK_CHECK_INOUT(m_current < m_vector->size());
|
|
||||||
return m_vector->get(m_current);
|
return m_vector->get(m_current);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
@ -228,15 +226,13 @@ namespace etk {
|
|||||||
* @brief Re-copy constructor (copy all needed data)
|
* @brief Re-copy constructor (copy all needed data)
|
||||||
* @param[in] _obj Vector that might be copy
|
* @param[in] _obj Vector that might be copy
|
||||||
*/
|
*/
|
||||||
Vector(const etk::Vector<ETK_VECTOR_TYPE>& _obj) {
|
Vector(const etk::Vector<ETK_VECTOR_TYPE>& _obj):
|
||||||
m_allocated = _obj.m_allocated;
|
m_data(nullptr),
|
||||||
m_size = _obj.m_size;
|
m_size(_obj.m_size),
|
||||||
m_data = nullptr;
|
m_allocated(_obj.m_allocated) {
|
||||||
//TK_DEBUG("USE Specific vector allocator ... Evb.m_size=" << Evb.m_size << " Evb.m_increment=" << Evb.m_increment);
|
|
||||||
// allocate all same data
|
// allocate all same data
|
||||||
m_data = new ETK_VECTOR_TYPE[m_allocated];
|
m_data = new ETK_VECTOR_TYPE[m_allocated];
|
||||||
if (m_data == nullptr) {
|
if (m_data == nullptr) {
|
||||||
//TK_CRITICAL("Vector : Error in data allocation ... might nor work correctly anymore");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Copy all data ...
|
// Copy all data ...
|
||||||
@ -245,6 +241,12 @@ namespace etk {
|
|||||||
m_data[iii] = _obj.m_data[iii];
|
m_data[iii] = _obj.m_data[iii];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Vector(const etk::Vector<ETK_VECTOR_TYPE>&& _obj):
|
||||||
|
m_data(etk::move(_obj.m_data)),
|
||||||
|
m_size(etk::move(_obj.m_size)),
|
||||||
|
m_allocated(etk::move(_obj.m_allocated)) {
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Destructor of the current Class
|
* @brief Destructor of the current Class
|
||||||
*/
|
*/
|
||||||
@ -280,7 +282,6 @@ namespace etk {
|
|||||||
* @return reference on the current re-copy vector
|
* @return reference on the current re-copy vector
|
||||||
*/
|
*/
|
||||||
Vector& operator=(const etk::Vector<ETK_VECTOR_TYPE> & _obj) {
|
Vector& operator=(const etk::Vector<ETK_VECTOR_TYPE> & _obj) {
|
||||||
//TK_DEBUG("USE RECOPY vector ... Evb.m_size=" << Evb.m_size << " Evb.m_increment=" << Evb.m_increment);
|
|
||||||
if (this != &_obj) {
|
if (this != &_obj) {
|
||||||
if (m_data != nullptr) {
|
if (m_data != nullptr) {
|
||||||
delete[] m_data;
|
delete[] m_data;
|
||||||
@ -292,12 +293,11 @@ namespace etk {
|
|||||||
// allocate all same data
|
// allocate all same data
|
||||||
m_data = new ETK_VECTOR_TYPE[m_allocated];
|
m_data = new ETK_VECTOR_TYPE[m_allocated];
|
||||||
if (m_data == nullptr) {
|
if (m_data == nullptr) {
|
||||||
//TK_CRITICAL("Vector : Error in data allocation ... might nor work correctly anymore");
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
for(size_t iii=0; iii<m_allocated; iii++) {
|
for(size_t iii=0; iii<m_allocated; iii++) {
|
||||||
// copy operator ...
|
// copy operator ...
|
||||||
m_data[iii] = _obj.m_data[iii];
|
m_data[iii] = etk::move(_obj.m_data[iii]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Return the current pointer
|
// Return the current pointer
|
||||||
|
@ -28,7 +28,8 @@ def configure(target, my_module):
|
|||||||
my_module.add_src_file([
|
my_module.add_src_file([
|
||||||
'test/main.cpp',
|
'test/main.cpp',
|
||||||
'test/testColor.cpp',
|
'test/testColor.cpp',
|
||||||
'test/testHash.cpp',
|
'test/testMapUnordered.cpp',
|
||||||
|
'test/testMap.cpp',
|
||||||
'test/testMatrix3x3.cpp',
|
'test/testMatrix3x3.cpp',
|
||||||
'test/testRegExp.cpp',
|
'test/testRegExp.cpp',
|
||||||
'test/testTransform.cpp',
|
'test/testTransform.cpp',
|
||||||
@ -37,7 +38,6 @@ def configure(target, my_module):
|
|||||||
'test/testFSNode.cpp',
|
'test/testFSNode.cpp',
|
||||||
'test/testMatrix2x2.cpp',
|
'test/testMatrix2x2.cpp',
|
||||||
'test/testQuaternion.cpp',
|
'test/testQuaternion.cpp',
|
||||||
'test/testStdShared.cpp',
|
|
||||||
'test/testVector2_f.cpp',
|
'test/testVector2_f.cpp',
|
||||||
'test/testString.cpp',
|
'test/testString.cpp',
|
||||||
])
|
])
|
||||||
|
0
test/testFunction.cpp
Normal file
0
test/testFunction.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* @author Edouard DUPIN
|
||||||
|
*
|
||||||
|
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||||
|
*
|
||||||
|
* @license MPL v2.0 (see license file)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <etk/Map.hpp>
|
||||||
|
#include <test-debug/debug.hpp>
|
||||||
|
#define NAME "Map"
|
||||||
|
|
||||||
|
TEST(TestEtkMap, Creation) {
|
||||||
|
etk::Map<uint32_t, etk::String> testData(0,true);
|
||||||
|
EXPECT_EQ(testData.size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestEtkMap, add_ordered) {
|
||||||
|
etk::Map<uint32_t, etk::String> testData(0,true);
|
||||||
|
EXPECT_EQ(testData.size(), 0);
|
||||||
|
testData.add(2, "a 2");
|
||||||
|
testData.add(19, "b 19");
|
||||||
|
testData.add(1, "c 1");
|
||||||
|
testData.add(5, "d 5");
|
||||||
|
testData.add(66, "e 66");
|
||||||
|
EXPECT_EQ(testData.size(), 5);
|
||||||
|
EXPECT_EQ(testData[1], "c 1");
|
||||||
|
EXPECT_EQ(testData.getValue(0), "c 1");
|
||||||
|
}
|
@ -1,48 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author Edouard DUPIN
|
|
||||||
*
|
|
||||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
|
||||||
*
|
|
||||||
* @license MPL v2.0 (see license file)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <ememory/memory.hpp>
|
|
||||||
#include <test-debug/debug.hpp>
|
|
||||||
#define NAME "Shared_ptr"
|
|
||||||
|
|
||||||
class Example : public ememory::EnableSharedFromThis<Example> {
|
|
||||||
protected:
|
|
||||||
int32_t m_id;
|
|
||||||
public:
|
|
||||||
Example() {
|
|
||||||
static int32_t mid = 0;
|
|
||||||
m_id = mid++;
|
|
||||||
std::cout << "create Example [" << m_id << "]" << std::endl;
|
|
||||||
}
|
|
||||||
~Example() {
|
|
||||||
std::cout << "Remove Example [" << m_id << "]" << std::endl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TEST(TestSTDSharedPtr, testBaseLocal) {
|
|
||||||
Example();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TestSTDSharedPtr, testBaseShared) {
|
|
||||||
ememory::SharedPtr<Example> tmp = ememory::makeShared<Example>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST(TestSTDSharedPtr, testBaseSharedDouble) {
|
|
||||||
ememory::SharedPtr<Example> tmp = ememory::makeShared<Example>();
|
|
||||||
ememory::SharedPtr<Example> tmp2 = tmp;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
TEST(TestSTDSharedPtr, testBaseSharedDirectAndShared) {
|
|
||||||
Example tmp;
|
|
||||||
ememory::SharedPtr<Example> tmp2 = ememory::makeShared<tmp>;
|
|
||||||
}
|
|
||||||
*/
|
|
Loading…
Reference in New Issue
Block a user