[DEV] function

This commit is contained in:
Edouard DUPIN 2017-09-01 22:40:04 +02:00
parent 628146c380
commit 4abbcad222
8 changed files with 162 additions and 84 deletions

View File

@ -9,27 +9,120 @@
#pragma once
namespace etk {
/**
* @brief Generic Thread interface (OS independent)
*/
template<class ETK_TYPE_FUNCTION>
class Function {
private:
#ifdef __TARGET_OS__Windows
#else
pthread_mutex_t m_thread;
#endif
uint32_t m_uid; //!< unique id of the thread
etk::String m_name; //!< Name of the thread (do not get it on the system ==> more portable)
etk::Function<void()> m_function; //!< Function to call every cycle of the thead running
public:
Thread(etk::Function<void()>&& _call, const std::string& _name);
~Thread();
void join();
bool detach();
void setName(const std::string& _name);
const std::string& setName() const;
uint32_t getIdentifier() const;
template <typename ETK_TYPE_FUNCTION>
class Function;
template <typename ETK_TYPE_FUNCTION_RETURN, typename... ETK_TYPE_FUNCTION_ARGS>
class Function<ETK_TYPE_FUNCTION_RETURN(ETK_TYPE_FUNCTION_ARGS...)> {
// function pointer types for the type-erasure behaviors
// all these char* parameters are actually casted from some functor type
typedef ETK_TYPE_FUNCTION_RETURN (*invoke_fn_t)(char*, ETK_TYPE_FUNCTION_ARGS&&...);
typedef void (*construct_fn_t)(char*, char*);
typedef void (*destroy_fn_t)(char*);
// type-aware generic functions for invoking
// the specialization of these functions won't be capable with
// the above function pointer types, so we need some cast
template <typename ETK_TYPE_FUNCTION_FUNCTOR>
static ETK_TYPE_FUNCTION_RETURN invoke_fn(ETK_TYPE_FUNCTION_FUNCTOR* _functor,
ETK_TYPE_FUNCTION_ARGS&&... _args) {
return (*_functor)(std::forward<ETK_TYPE_FUNCTION_ARGS>(_args)...);
}
template <typename ETK_TYPE_FUNCTION_FUNCTOR>
static void construct_fn(ETK_TYPE_FUNCTION_FUNCTOR* _constructDestination,
ETK_TYPE_FUNCTION_FUNCTOR* _constructSource) {
// 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;
}
*/

View File

@ -324,7 +324,9 @@ const etk::String::Iterator etk::String::end() const {
void etk::String::resize(size_t _newSize, char _value) {
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);
// in all case ==> we have the last element that is '\0'
m_data[_newSize] = '\0';

View File

@ -190,7 +190,6 @@ namespace etk {
* @return the reference on the current Element
*/
ETK_VECTOR_TYPE* operator-> () const {
//TK_CHECK_INOUT(m_current < m_vector->size());
return &m_vector->get(m_current);
}
/**
@ -198,7 +197,6 @@ namespace etk {
* @return the reference on the current Element
*/
ETK_VECTOR_TYPE& operator* () const {
//TK_CHECK_INOUT(m_current < m_vector->size());
return m_vector->get(m_current);
}
private:
@ -228,15 +226,13 @@ namespace etk {
* @brief Re-copy constructor (copy all needed data)
* @param[in] _obj Vector that might be copy
*/
Vector(const etk::Vector<ETK_VECTOR_TYPE>& _obj) {
m_allocated = _obj.m_allocated;
m_size = _obj.m_size;
m_data = nullptr;
//TK_DEBUG("USE Specific vector allocator ... Evb.m_size=" << Evb.m_size << " Evb.m_increment=" << Evb.m_increment);
Vector(const etk::Vector<ETK_VECTOR_TYPE>& _obj):
m_data(nullptr),
m_size(_obj.m_size),
m_allocated(_obj.m_allocated) {
// allocate all same data
m_data = new ETK_VECTOR_TYPE[m_allocated];
if (m_data == nullptr) {
//TK_CRITICAL("Vector : Error in data allocation ... might nor work correctly anymore");
return;
}
// Copy all data ...
@ -245,6 +241,12 @@ namespace etk {
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
*/
@ -280,7 +282,6 @@ namespace etk {
* @return reference on the current re-copy vector
*/
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 (m_data != nullptr) {
delete[] m_data;
@ -292,12 +293,11 @@ namespace etk {
// allocate all same data
m_data = new ETK_VECTOR_TYPE[m_allocated];
if (m_data == nullptr) {
//TK_CRITICAL("Vector : Error in data allocation ... might nor work correctly anymore");
return *this;
}
for(size_t iii=0; iii<m_allocated; iii++) {
// copy operator ...
m_data[iii] = _obj.m_data[iii];
m_data[iii] = etk::move(_obj.m_data[iii]);
}
}
// Return the current pointer

View File

@ -28,7 +28,8 @@ def configure(target, my_module):
my_module.add_src_file([
'test/main.cpp',
'test/testColor.cpp',
'test/testHash.cpp',
'test/testMapUnordered.cpp',
'test/testMap.cpp',
'test/testMatrix3x3.cpp',
'test/testRegExp.cpp',
'test/testTransform.cpp',
@ -37,7 +38,6 @@ def configure(target, my_module):
'test/testFSNode.cpp',
'test/testMatrix2x2.cpp',
'test/testQuaternion.cpp',
'test/testStdShared.cpp',
'test/testVector2_f.cpp',
'test/testString.cpp',
])

0
test/testFunction.cpp Normal file
View File

View 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");
}

View File

@ -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>;
}
*/