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

View File

@ -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';

View File

@ -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

View File

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