| @@ -75,7 +75,8 @@ source/tests/CarlaString | |||
| source/tests/DGL1 | |||
| source/tests/DGL2 | |||
| source/tests/Print | |||
| source/tests/RtList | |||
| source/tests/RtLinkedList | |||
| source/tests/RtLinkedListGnu | |||
| source/tests/Utils | |||
| source/tests/Widgets | |||
| @@ -50,7 +50,7 @@ | |||
| * | |||
| */ | |||
| #define container_of(ptr, type, member) ({ \ | |||
| const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | |||
| typeof( ((type *)0)->member ) *__mptr = (ptr); \ | |||
| (type *)( (char *)__mptr - offsetof(type, member) );}) | |||
| #define container_of_const(ptr, type, member) ({ \ | |||
| @@ -304,7 +304,7 @@ static inline void list_splice_tail_init(struct list_head *list, struct list_hea | |||
| * @type: the type of the struct this is embedded in. | |||
| * @member: the name of the list_struct within the struct. | |||
| */ | |||
| #if defined(__GNUC__) && ! (defined(BUILD_ANSI_TEST) || defined(QTCREATOR_TEST)) | |||
| #if defined(__GNUC__) && ! defined(__STRICT_ANSI__) | |||
| # define list_entry(ptr, type, member) \ | |||
| container_of(ptr, type, member) | |||
| # define list_entry_const(ptr, type, member) \ | |||
| @@ -75,9 +75,13 @@ Print: Print.cpp | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||
| # valgrind ./Print | |||
| RtList: RtList.cpp ../utils/RtList.hpp ../modules/rtmempool.a | |||
| RtLinkedList: RtLinkedList.cpp ../utils/LinkedList.hpp ../utils/RtLinkedList.hpp ../modules/rtmempool.a | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -lpthread -o $@ | |||
| # valgrind ./RtList | |||
| valgrind ./RtLinkedList | |||
| RtLinkedListGnu: RtLinkedList.cpp ../utils/LinkedList.hpp ../utils/RtLinkedList.hpp ../modules/rtmempool.a | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) -std=gnu++11 $(LINK_FLAGS) -lpthread -o $@ | |||
| valgrind ./RtLinkedListGnu | |||
| Utils: Utils.cpp | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(ANSI_CXX_FLAGS) -std=c++11 -Wzero-as-null-pointer-constant $(LINK_FLAGS) -ldl -lpthread -o $@ | |||
| @@ -1,195 +0,0 @@ | |||
| /* | |||
| * Carla Tests | |||
| * Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #include "RtList.hpp" | |||
| #include "CarlaString.hpp" | |||
| #include "CarlaMutex.hpp" | |||
| const unsigned short MIN_RT_EVENTS = 5; | |||
| const unsigned short MAX_RT_EVENTS = 10; | |||
| struct MyData { | |||
| CarlaString str; | |||
| int idStr; | |||
| MyData() | |||
| : idStr(-1) {} | |||
| MyData(int id) | |||
| : str(id), | |||
| idStr(id) {} | |||
| }; | |||
| struct PostRtEvents { | |||
| CarlaMutex mutex; | |||
| RtList<MyData>::Pool dataPool; | |||
| RtList<MyData> data; | |||
| RtList<MyData> dataPendingRT; | |||
| PostRtEvents() | |||
| : dataPool(MIN_RT_EVENTS, MAX_RT_EVENTS), | |||
| data(dataPool), | |||
| dataPendingRT(dataPool) {} | |||
| ~PostRtEvents() | |||
| { | |||
| clear(); | |||
| } | |||
| void appendRT(const MyData& event) | |||
| { | |||
| dataPendingRT.append(event); | |||
| } | |||
| void clear() | |||
| { | |||
| mutex.lock(); | |||
| data.clear(); | |||
| dataPendingRT.clear(); | |||
| mutex.unlock(); | |||
| } | |||
| void trySplice() | |||
| { | |||
| if (mutex.tryLock()) | |||
| { | |||
| dataPendingRT.spliceAppend(data); | |||
| mutex.unlock(); | |||
| } | |||
| } | |||
| } postRtEvents; | |||
| void run5Tests() | |||
| { | |||
| unsigned short k = 0; | |||
| MyData allMyData[MAX_RT_EVENTS]; | |||
| // Make a safe copy of events while clearing them | |||
| postRtEvents.mutex.lock(); | |||
| while (! postRtEvents.data.isEmpty()) | |||
| { | |||
| const MyData& my(postRtEvents.data.getFirst(true)); | |||
| allMyData[k++] = my; | |||
| } | |||
| postRtEvents.mutex.unlock(); | |||
| printf("Post-Rt Event Count: %i\n", k); | |||
| assert(k == 5); | |||
| // data should be empty now | |||
| assert(postRtEvents.data.count() == 0); | |||
| assert(postRtEvents.data.isEmpty()); | |||
| assert(postRtEvents.dataPendingRT.count() == 0); | |||
| assert(postRtEvents.dataPendingRT.isEmpty()); | |||
| // Handle events now | |||
| for (unsigned short i=0; i < k; ++i) | |||
| { | |||
| const MyData& my(allMyData[i]); | |||
| printf("Got data: %i %s\n", my.idStr, (const char*)my.str); | |||
| } | |||
| } | |||
| int main() | |||
| { | |||
| MyData m1(1); | |||
| MyData m2(2); | |||
| MyData m3(3); | |||
| MyData m4(4); | |||
| MyData m5(5); | |||
| // start | |||
| assert(postRtEvents.data.count() == 0); | |||
| assert(postRtEvents.data.isEmpty()); | |||
| assert(postRtEvents.dataPendingRT.count() == 0); | |||
| assert(postRtEvents.dataPendingRT.isEmpty()); | |||
| // single append | |||
| postRtEvents.appendRT(m1); | |||
| postRtEvents.trySplice(); | |||
| assert(postRtEvents.data.count() == 1); | |||
| assert(postRtEvents.dataPendingRT.count() == 0); | |||
| // +3 appends | |||
| postRtEvents.appendRT(m2); | |||
| postRtEvents.appendRT(m4); | |||
| postRtEvents.appendRT(m3); | |||
| assert(postRtEvents.data.count() == 1); | |||
| assert(postRtEvents.dataPendingRT.count() == 3); | |||
| postRtEvents.trySplice(); | |||
| assert(postRtEvents.data.count() == 4); | |||
| assert(postRtEvents.dataPendingRT.count() == 0); | |||
| for (RtList<MyData>::Itenerator it = postRtEvents.data.begin(); it.valid(); it.next()) | |||
| { | |||
| MyData& my(*it); | |||
| printf("FOR DATA!!!: %i %s\n", my.idStr, (const char*)my.str); | |||
| if (my.idStr == 1) | |||
| { | |||
| // +1 append at | |||
| postRtEvents.dataPendingRT.insertAt(m5, it); | |||
| assert(postRtEvents.data.count() == 4); | |||
| assert(postRtEvents.dataPendingRT.count() == 1); | |||
| postRtEvents.trySplice(); | |||
| assert(postRtEvents.data.count() == 5); | |||
| assert(postRtEvents.dataPendingRT.count() == 0); | |||
| } | |||
| } | |||
| run5Tests(); | |||
| // reset | |||
| postRtEvents.clear(); | |||
| assert(postRtEvents.data.count() == 0); | |||
| assert(postRtEvents.data.isEmpty()); | |||
| assert(postRtEvents.dataPendingRT.count() == 0); | |||
| assert(postRtEvents.dataPendingRT.isEmpty()); | |||
| // test non-rt | |||
| const unsigned int CARLA_EVENT_DATA_ATOM = 0x01; | |||
| const unsigned int CARLA_EVENT_DATA_MIDI_LL = 0x04; | |||
| NonRtList<uint32_t> evIns, evOuts; | |||
| evIns.append(CARLA_EVENT_DATA_ATOM); | |||
| evOuts.append(CARLA_EVENT_DATA_ATOM); | |||
| evOuts.append(CARLA_EVENT_DATA_MIDI_LL); | |||
| if (evIns.count() > 0) | |||
| { | |||
| for (uint32_t j=0, count=evIns.count(); j < count; ++j) | |||
| { | |||
| const uint32_t& type(evIns.getAt(j)); | |||
| if (type == CARLA_EVENT_DATA_ATOM) | |||
| pass(); | |||
| else if (type == CARLA_EVENT_DATA_MIDI_LL) | |||
| pass(); | |||
| } | |||
| } | |||
| evIns.clear(); | |||
| evOuts.clear(); | |||
| return 0; | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * High-level, templated, C++ doubly-linked list | |||
| * Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU General Public License as | |||
| @@ -15,8 +15,8 @@ | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #ifndef LIST_HPP_INCLUDED | |||
| #define LIST_HPP_INCLUDED | |||
| #ifndef LINKED_LIST_HPP_INCLUDED | |||
| #define LINKED_LIST_HPP_INCLUDED | |||
| #include "CarlaUtils.hpp" | |||
| @@ -28,26 +28,26 @@ extern "C" { | |||
| // Declare non copyable and prevent heap allocation | |||
| #ifdef CARLA_PROPER_CPP11_SUPPORT | |||
| # define LIST_DECLARATIONS(ClassName) \ | |||
| # define LINKED_LIST_DECLARATIONS(ClassName) \ | |||
| ClassName(ClassName&) = delete; \ | |||
| ClassName(const ClassName&) = delete; \ | |||
| ClassName& operator=(const ClassName&) = delete; \ | |||
| static void* operator new(size_t) = delete; | |||
| #else | |||
| # define LIST_DECLARATIONS(ClassName) \ | |||
| ClassName(ClassName&); \ | |||
| ClassName(const ClassName&); \ | |||
| # define LINKED_LIST_DECLARATIONS(ClassName) \ | |||
| ClassName(ClassName&); \ | |||
| ClassName(const ClassName&); \ | |||
| ClassName& operator=(const ClassName&); | |||
| #endif | |||
| typedef struct list_head k_list_head; | |||
| // ----------------------------------------------------------------------- | |||
| // Abstract List class | |||
| // Abstract Linked List class | |||
| // _allocate() and _deallocate are virtual calls provided by subclasses | |||
| template<typename T> | |||
| class AbstractList | |||
| class AbstractLinkedList | |||
| { | |||
| protected: | |||
| struct Data { | |||
| @@ -55,26 +55,26 @@ protected: | |||
| k_list_head siblings; | |||
| }; | |||
| AbstractList() | |||
| AbstractLinkedList() | |||
| : fDataSize(sizeof(Data)), | |||
| fCount(0) | |||
| { | |||
| _init(); | |||
| } | |||
| virtual ~AbstractList() | |||
| public: | |||
| virtual ~AbstractLinkedList() | |||
| { | |||
| CARLA_ASSERT(fCount == 0); | |||
| } | |||
| public: | |||
| class Itenerator { | |||
| public: | |||
| Itenerator(const k_list_head* queue) | |||
| : fEntry(queue->next), | |||
| : fData(nullptr), | |||
| fEntry(queue->next), | |||
| fEntry2(fEntry->next), | |||
| fQueue(queue), | |||
| fData(nullptr) | |||
| fQueue(queue) | |||
| { | |||
| CARLA_ASSERT(fEntry != nullptr); | |||
| CARLA_ASSERT(fEntry2 != nullptr); | |||
| @@ -99,31 +99,13 @@ public: | |||
| return fData->value; | |||
| } | |||
| const T& getConstValue() | |||
| { | |||
| fConstData = list_entry_const(fEntry, Data, siblings); | |||
| CARLA_ASSERT(fConstData != nullptr); | |||
| return fConstData->value; | |||
| } | |||
| #if 0 | |||
| T& operator*() const | |||
| { | |||
| return getValue(); | |||
| } | |||
| #endif | |||
| private: | |||
| Data* fData; | |||
| k_list_head* fEntry; | |||
| k_list_head* fEntry2; | |||
| const k_list_head* const fQueue; | |||
| union { | |||
| Data* fData; | |||
| const Data* fConstData; | |||
| }; | |||
| friend class AbstractList; | |||
| friend class AbstractLinkedList; | |||
| }; | |||
| Itenerator begin() const | |||
| @@ -151,35 +133,6 @@ public: | |||
| _init(); | |||
| } | |||
| // temporary fix for some const issue in midi-base.hpp | |||
| void clear_const() | |||
| { | |||
| if (fCount != 0) | |||
| { | |||
| k_list_head* entry; | |||
| k_list_head* entry2; | |||
| list_for_each_safe(entry, entry2, &fQueue) | |||
| { | |||
| if (const Data* data = list_entry_const(entry, Data, siblings)) | |||
| { | |||
| data->~Data(); | |||
| union CData { | |||
| const Data* cdata; | |||
| Data* data; | |||
| }; | |||
| CData d; | |||
| d.cdata = data; | |||
| _deallocate(d.data); | |||
| } | |||
| } | |||
| } | |||
| _init(); | |||
| } | |||
| size_t count() const noexcept | |||
| { | |||
| return fCount; | |||
| @@ -356,7 +309,7 @@ public: | |||
| } | |||
| } | |||
| void spliceAppend(AbstractList& list, const bool init = true) | |||
| void spliceAppend(AbstractLinkedList& list, const bool init = true) | |||
| { | |||
| if (init) | |||
| { | |||
| @@ -371,7 +324,7 @@ public: | |||
| } | |||
| } | |||
| void spliceInsert(AbstractList& list, const bool init = true) | |||
| void spliceInsert(AbstractLinkedList& list, const bool init = true) | |||
| { | |||
| if (init) | |||
| { | |||
| @@ -429,27 +382,25 @@ private: | |||
| return fRetValue; | |||
| } | |||
| LIST_DECLARATIONS(AbstractList) | |||
| LINKED_LIST_DECLARATIONS(AbstractLinkedList) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // List | |||
| // LinkedList | |||
| template<typename T> | |||
| class List : public AbstractList<T> | |||
| class LinkedList : public AbstractLinkedList<T> | |||
| { | |||
| public: | |||
| List() | |||
| { | |||
| } | |||
| LinkedList() {} | |||
| private: | |||
| typename AbstractList<T>::Data* _allocate() override | |||
| typename AbstractLinkedList<T>::Data* _allocate() override | |||
| { | |||
| return (typename AbstractList<T>::Data*)std::malloc(this->fDataSize); | |||
| return (typename AbstractLinkedList<T>::Data*)std::malloc(this->fDataSize); | |||
| } | |||
| void _deallocate(typename AbstractList<T>::Data*& dataPtr) override | |||
| void _deallocate(typename AbstractLinkedList<T>::Data*& dataPtr) override | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,); | |||
| @@ -457,9 +408,9 @@ private: | |||
| dataPtr = nullptr; | |||
| } | |||
| LIST_DECLARATIONS(List) | |||
| LINKED_LIST_DECLARATIONS(LinkedList) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| #endif // LIST_HPP_INCLUDED | |||
| #endif // LINKED_LIST_HPP_INCLUDED | |||
| @@ -15,20 +15,20 @@ | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #ifndef RT_LIST_HPP_INCLUDED | |||
| #define RT_LIST_HPP_INCLUDED | |||
| #ifndef RT_LINKED_LIST_HPP_INCLUDED | |||
| #define RT_LINKED_LIST_HPP_INCLUDED | |||
| #include "List.hpp" | |||
| #include "LinkedList.hpp" | |||
| extern "C" { | |||
| #include "rtmempool/rtmempool.h" | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Realtime safe list | |||
| // Realtime safe linkedlist | |||
| template<typename T> | |||
| class RtList : public AbstractList<T> | |||
| class RtLinkedList : public AbstractLinkedList<T> | |||
| { | |||
| public: | |||
| // ------------------------------------------------------------------- | |||
| @@ -39,7 +39,7 @@ public: | |||
| public: | |||
| Pool(const size_t minPreallocated, const size_t maxPreallocated) | |||
| : fHandle(nullptr), | |||
| fDataSize(sizeof(typename AbstractList<T>::Data)) | |||
| fDataSize(sizeof(typename AbstractLinkedList<T>::Data)) | |||
| { | |||
| resize(minPreallocated, maxPreallocated); | |||
| } | |||
| @@ -96,18 +96,16 @@ public: | |||
| }; | |||
| // ------------------------------------------------------------------- | |||
| // Now the actual rt-list code | |||
| // Now the actual rt-linkedlist code | |||
| RtList(Pool& memPool) | |||
| : fMemPool(memPool) | |||
| { | |||
| } | |||
| RtLinkedList(Pool& memPool) | |||
| : fMemPool(memPool) {} | |||
| void append_sleepy(const T& value) | |||
| { | |||
| if (typename AbstractList<T>::Data* const data = _allocate_sleepy()) | |||
| if (typename AbstractLinkedList<T>::Data* const data = _allocate_sleepy()) | |||
| { | |||
| new(data)typename AbstractList<T>::Data(); | |||
| new(data)typename AbstractLinkedList<T>::Data(); | |||
| data->value = value; | |||
| list_add_tail(&data->siblings, &this->fQueue); | |||
| ++(this->fCount); | |||
| @@ -116,9 +114,9 @@ public: | |||
| void insert_sleepy(const T& value) | |||
| { | |||
| if (typename AbstractList<T>::Data* const data = _allocate_sleepy()) | |||
| if (typename AbstractLinkedList<T>::Data* const data = _allocate_sleepy()) | |||
| { | |||
| new(data)typename AbstractList<T>::Data(); | |||
| new(data)typename AbstractLinkedList<T>::Data(); | |||
| data->value = value; | |||
| list_add(&data->siblings, &this->fQueue); | |||
| ++(this->fCount); | |||
| @@ -132,34 +130,34 @@ public: | |||
| fMemPool.resize(minPreallocated, maxPreallocated); | |||
| } | |||
| void spliceAppend(RtList& list, const bool init = true) | |||
| void spliceAppend(RtLinkedList& list, const bool init = true) | |||
| { | |||
| CARLA_ASSERT(fMemPool == list.fMemPool); | |||
| AbstractList<T>::spliceAppend(list, init); | |||
| AbstractLinkedList<T>::spliceAppend(list, init); | |||
| } | |||
| void spliceInsert(RtList& list, const bool init = true) | |||
| void spliceInsert(RtLinkedList& list, const bool init = true) | |||
| { | |||
| CARLA_ASSERT(fMemPool == list.fMemPool); | |||
| AbstractList<T>::spliceInsert(list, init); | |||
| AbstractLinkedList<T>::spliceInsert(list, init); | |||
| } | |||
| private: | |||
| Pool& fMemPool; | |||
| typename AbstractList<T>::Data* _allocate() override | |||
| typename AbstractLinkedList<T>::Data* _allocate() override | |||
| { | |||
| return (typename AbstractList<T>::Data*)fMemPool.allocate_atomic(); | |||
| return (typename AbstractLinkedList<T>::Data*)fMemPool.allocate_atomic(); | |||
| } | |||
| typename AbstractList<T>::Data* _allocate_sleepy() | |||
| typename AbstractLinkedList<T>::Data* _allocate_sleepy() | |||
| { | |||
| return (typename AbstractList<T>::Data*)fMemPool.allocate_sleepy(); | |||
| return (typename AbstractLinkedList<T>::Data*)fMemPool.allocate_sleepy(); | |||
| } | |||
| void _deallocate(typename AbstractList<T>::Data*& dataPtr) override | |||
| void _deallocate(typename AbstractLinkedList<T>::Data*& dataPtr) override | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,); | |||
| @@ -167,9 +165,9 @@ private: | |||
| dataPtr = nullptr; | |||
| } | |||
| LIST_DECLARATIONS(RtList) | |||
| LINKED_LIST_DECLARATIONS(RtLinkedList) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| #endif // RT_LIST_HPP_INCLUDED | |||
| #endif // RT_LINKED_LIST_HPP_INCLUDED | |||