From 906a5e4ed392b8f23db49c0fc216ab1ad5511d1f Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Tue, 29 Jan 2019 14:19:55 +0200 Subject: [PATCH 01/23] AVL Tree backed queue --- libuavcan/include/uavcan/driver/can.hpp | 10 + .../include/uavcan/node/abstract_node.hpp | 2 +- .../include/uavcan/node/generic_publisher.hpp | 10 +- libuavcan/include/uavcan/transport/can_io.hpp | 109 ++-- .../include/uavcan/transport/dispatcher.hpp | 2 +- .../uavcan/transport/transfer_sender.hpp | 10 +- libuavcan/include/uavcan/util/avl_tree.hpp | 390 ++++++++++++++ libuavcan/src/node/uc_generic_publisher.cpp | 2 +- libuavcan/src/transport/uc_can_io.cpp | 494 ++++++++---------- libuavcan/src/transport/uc_dispatcher.cpp | 2 +- .../src/transport/uc_transfer_sender.cpp | 2 +- libuavcan/test/transport/can/io.cpp | 52 +- libuavcan/test/transport/can/tx_queue.cpp | 260 ++++----- libuavcan/test/transport/dispatcher.cpp | 4 +- libuavcan/test/transport/transfer_sender.cpp | 8 +- .../linux/apps/test_multithreading.cpp | 5 +- 16 files changed, 830 insertions(+), 532 deletions(-) create mode 100644 libuavcan/include/uavcan/util/avl_tree.hpp diff --git a/libuavcan/include/uavcan/driver/can.hpp b/libuavcan/include/uavcan/driver/can.hpp index d20feca15..492a9073f 100644 --- a/libuavcan/include/uavcan/driver/can.hpp +++ b/libuavcan/include/uavcan/driver/can.hpp @@ -57,6 +57,16 @@ struct UAVCAN_EXPORT CanFrame return (id == rhs.id) && (dlc == rhs.dlc) && equal(data, data + dlc, rhs.data); } + bool operator <(const CanFrame & other) const + { + return this->priorityLowerThan(other); + } + + bool operator >(const CanFrame & other) const + { + return this->priorityHigherThan(other); + } + bool isExtended() const { return id & FlagEFF; } bool isRemoteTransmissionRequest() const { return id & FlagRTR; } bool isErrorFrame() const { return id & FlagERR; } diff --git a/libuavcan/include/uavcan/node/abstract_node.hpp b/libuavcan/include/uavcan/node/abstract_node.hpp index 2976c32e7..9e1e20a9c 100644 --- a/libuavcan/include/uavcan/node/abstract_node.hpp +++ b/libuavcan/include/uavcan/node/abstract_node.hpp @@ -109,7 +109,7 @@ class UAVCAN_EXPORT INode * @param flags CAN IO flags. Please refer to the CAN driver API for details. */ int injectTxFrame(const CanFrame& frame, MonotonicTime tx_deadline, uint8_t iface_mask, - CanTxQueue::Qos qos = CanTxQueue::Volatile, + Qos qos = Qos::Volatile, CanIOFlags flags = 0) { return getDispatcher().getCanIOManager().send(frame, tx_deadline, MonotonicTime(), iface_mask, qos, flags); diff --git a/libuavcan/include/uavcan/node/generic_publisher.hpp b/libuavcan/include/uavcan/node/generic_publisher.hpp index a8197b6cf..9a2175773 100644 --- a/libuavcan/include/uavcan/node/generic_publisher.hpp +++ b/libuavcan/include/uavcan/node/generic_publisher.hpp @@ -41,7 +41,7 @@ class GenericPublisherBase : Noncopyable bool isInited() const; - int doInit(DataTypeKind dtkind, const char* dtname, CanTxQueue::Qos qos); + int doInit(DataTypeKind dtkind, const char* dtname, Qos qos); MonotonicTime getTxDeadline() const; @@ -93,10 +93,11 @@ class UAVCAN_EXPORT GenericPublisher : public GenericPublisherBase ZeroTransferBuffer, StaticTransferBuffer::Result> >::Result Buffer; + enum { - Qos = (DataTypeKind(DataSpec::DataTypeKind) == DataTypeKindMessage) ? - CanTxQueue::Volatile : CanTxQueue::Persistent + ExtractQosFromDataKind = (DataTypeKind(DataSpec::DataTypeKind) == DataTypeKindMessage) ? + Qos::Volatile : Qos::Persistent }; int checkInit(); @@ -157,7 +158,8 @@ int GenericPublisher::checkInit() { return 0; } - return doInit(DataTypeKind(DataSpec::DataTypeKind), DataSpec::getDataTypeFullName(), CanTxQueue::Qos(Qos)); + + return doInit(DataTypeKind(DataSpec::DataTypeKind), DataSpec::getDataTypeFullName(), Qos(ExtractQosFromDataKind)); } template diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index 11752f0f8..ed6c5897e 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -1,6 +1,9 @@ +#include + /* * CAN bus IO logic. * Copyright (C) 2014 Pavel Kirienko + * Copyright (C) 2019 Theodoros Ntakouris */ #ifndef UAVCAN_TRANSPORT_CAN_IO_HPP_INCLUDED @@ -10,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -32,91 +36,87 @@ struct UAVCAN_EXPORT CanRxFrame : public CanFrame { } #if UAVCAN_TOSTRING - std::string toString(StringRepresentation mode = StrTight) const; + std::string toString(StringRepresentation mode = StrTight) const; #endif }; +enum Qos { Volatile, Persistent }; -class UAVCAN_EXPORT CanTxQueue : Noncopyable +struct CanTxQueueEntry // Not required to be packed - fits the block in any case { -public: - enum Qos { Volatile, Persistent }; - - struct Entry : public LinkedListNode // Not required to be packed - fits the block in any case - { - MonotonicTime deadline; - CanFrame frame; - uint8_t qos; - CanIOFlags flags; + MonotonicTime deadline; + const CanFrame frame; + uint8_t qos; + CanIOFlags flags; - Entry(const CanFrame& arg_frame, MonotonicTime arg_deadline, Qos arg_qos, CanIOFlags arg_flags) - : deadline(arg_deadline) + CanTxQueueEntry(const CanFrame& arg_frame, const MonotonicTime arg_deadline, Qos arg_qos, CanIOFlags arg_flags) + : deadline(std::move(arg_deadline)) , frame(arg_frame) , qos(uint8_t(arg_qos)) , flags(arg_flags) - { - UAVCAN_ASSERT((qos == Volatile) || (qos == Persistent)); - IsDynamicallyAllocatable::check(); - } + { + UAVCAN_ASSERT((qos == Volatile) || (qos == Persistent)); + IsDynamicallyAllocatable::check(); + } - static void destroy(Entry*& obj, IPoolAllocator& allocator); + static void destroy(CanTxQueueEntry*& obj, IPoolAllocator& allocator); - bool isExpired(MonotonicTime timestamp) const { return timestamp > deadline; } + bool isExpired(const MonotonicTime timestamp) const { return timestamp > deadline; } - bool qosHigherThan(const CanFrame& rhs_frame, Qos rhs_qos) const; - bool qosLowerThan(const CanFrame& rhs_frame, Qos rhs_qos) const; - bool qosHigherThan(const Entry& rhs) const { return qosHigherThan(rhs.frame, Qos(rhs.qos)); } - bool qosLowerThan(const Entry& rhs) const { return qosLowerThan(rhs.frame, Qos(rhs.qos)); } + bool operator <(const CanTxQueueEntry & other) const + { + return this->frame.priorityLowerThan(other.frame); + } -#if UAVCAN_TOSTRING - std::string toString() const; -#endif - }; + bool operator >(const CanTxQueueEntry & other) const + { + return this->frame.priorityHigherThan(other.frame); + } -private: - class PriorityInsertionComparator + bool operator =(const CanTxQueueEntry & other) const { - const CanFrame& frm_; - public: - explicit PriorityInsertionComparator(const CanFrame& frm) : frm_(frm) { } - bool operator()(const Entry* entry) - { - UAVCAN_ASSERT(entry); - return frm_.priorityHigherThan(entry->frame); - } - }; + return this->frame == other.frame; + } - LinkedListRoot queue_; - LimitedPoolAllocator allocator_; +#if UAVCAN_TOSTRING + std::string toString() const; +#endif +}; + +class UAVCAN_EXPORT CanTxQueue : public AvlTree +{ +protected: ISystemClock& sysclock_; uint32_t rejected_frames_cnt_; - void registerRejectedFrame(); + void safeIncrementRejectedFrames(); + + AvlTree::Node* searchForNonExpiredMax(Node* n); public: CanTxQueue(IPoolAllocator& allocator, ISystemClock& sysclock, std::size_t allocator_quota) - : allocator_(allocator, allocator_quota) + : AvlTree(allocator, allocator_quota) , sysclock_(sysclock) , rejected_frames_cnt_(0) - { } + {} - ~CanTxQueue(); + ~CanTxQueue() override; - void push(const CanFrame& frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags); + /* Avl Tree allocates the AvlTree::Node, while this(CanTxQueue) allocates the CanTxQueueEntry + * Same logic for removal. */ + void push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags); + void remove(CanTxQueueEntry* entry) override; - Entry* peek(); // Modifier - void remove(Entry*& entry); - const CanFrame* getTopPriorityPendingFrame() const; + uint32_t getRejectedFrameCount() const { return rejected_frames_cnt_; } - /// The 'or equal' condition is necessary to avoid frame reordering. - bool topPriorityHigherOrEqual(const CanFrame& rhs_frame) const; + bool contains(const CanFrame &frame) const; - uint32_t getRejectedFrameCount() const { return rejected_frames_cnt_; } + /* Tries to look up rightmost Node. If the frame is expired, removes it and continues traversing */ + CanTxQueueEntry* peek(); - bool isEmpty() const { return queue_.isEmpty(); } + bool topPriorityHigherOrEqual(const CanFrame &rhs_frame); }; - struct UAVCAN_EXPORT CanIfacePerfCounters { uint64_t frames_tx; @@ -130,7 +130,6 @@ struct UAVCAN_EXPORT CanIfacePerfCounters { } }; - class UAVCAN_EXPORT CanIOManager : Noncopyable { struct IfaceFrameCounters @@ -177,7 +176,7 @@ class UAVCAN_EXPORT CanIOManager : Noncopyable * negative - failure */ int send(const CanFrame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, - uint8_t iface_mask, CanTxQueue::Qos qos, CanIOFlags flags); + uint8_t iface_mask, Qos qos, CanIOFlags flags); int receive(CanRxFrame& out_frame, MonotonicTime blocking_deadline, CanIOFlags& out_flags); }; diff --git a/libuavcan/include/uavcan/transport/dispatcher.hpp b/libuavcan/include/uavcan/transport/dispatcher.hpp index 53bc2e203..a1e750bb2 100644 --- a/libuavcan/include/uavcan/transport/dispatcher.hpp +++ b/libuavcan/include/uavcan/transport/dispatcher.hpp @@ -157,7 +157,7 @@ class UAVCAN_EXPORT Dispatcher : Noncopyable /** * Refer to CanIOManager::send() for the parameter description */ - int send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, CanTxQueue::Qos qos, + int send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, Qos qos, CanIOFlags flags, uint8_t iface_mask); void cleanup(MonotonicTime ts); diff --git a/libuavcan/include/uavcan/transport/transfer_sender.hpp b/libuavcan/include/uavcan/transport/transfer_sender.hpp index 462e51ed3..f45d81f2c 100644 --- a/libuavcan/include/uavcan/transport/transfer_sender.hpp +++ b/libuavcan/include/uavcan/transport/transfer_sender.hpp @@ -24,7 +24,7 @@ class UAVCAN_EXPORT TransferSender Dispatcher& dispatcher_; TransferPriority priority_; - CanTxQueue::Qos qos_; + Qos qos_; TransferCRC crc_base_; DataTypeID data_type_id_; CanIOFlags flags_; @@ -41,12 +41,12 @@ class UAVCAN_EXPORT TransferSender return MonotonicDuration::fromMSec(60 * 1000); } - TransferSender(Dispatcher& dispatcher, const DataTypeDescriptor& data_type, CanTxQueue::Qos qos, + TransferSender(Dispatcher& dispatcher, const DataTypeDescriptor& data_type, Qos qos, MonotonicDuration max_transfer_interval = getDefaultMaxTransferInterval()) : max_transfer_interval_(max_transfer_interval) , dispatcher_(dispatcher) , priority_(TransferPriority::Default) - , qos_(CanTxQueue::Qos()) + , qos_(Qos()) , flags_(CanIOFlags(0)) , iface_mask_(AllIfacesMask) , allow_anonymous_transfers_(false) @@ -58,13 +58,13 @@ class UAVCAN_EXPORT TransferSender : max_transfer_interval_(max_transfer_interval) , dispatcher_(dispatcher) , priority_(TransferPriority::Default) - , qos_(CanTxQueue::Qos()) + , qos_(Qos()) , flags_(CanIOFlags(0)) , iface_mask_(AllIfacesMask) , allow_anonymous_transfers_(false) { } - void init(const DataTypeDescriptor& dtid, CanTxQueue::Qos qos); + void init(const DataTypeDescriptor& dtid, Qos qos); bool isInitialized() const { return data_type_id_ != DataTypeID(); } diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp new file mode 100644 index 000000000..fa96e2ead --- /dev/null +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -0,0 +1,390 @@ +/* +* AVL Tree implementation. +* Copyright (C) 2019 Theodoros Ntakouris +*/ + +#ifndef UAVCAN_UTIL_AVL_TREE_HPP_INCLUDED +#define UAVCAN_UTIL_AVL_TREE_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace uavcan { + +template +class UAVCAN_EXPORT AvlTree : Noncopyable { +public: + struct Node { + T* data; + int h = 1; // initially added as leaf + Node *left = UAVCAN_NULLPTR; + Node *right = UAVCAN_NULLPTR; + }; +protected: + size_t len = 0; + + Node* root = UAVCAN_NULLPTR; + + /* + * Use this only to allocate the Node struct. + * `T data` should be already allocated and + * provided ready for usage from the outside world + * + * */ + LimitedPoolAllocator allocator_; + + AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota) + : allocator_(allocator, allocator_quota){} + + virtual ~AvlTree() { + // delete leafs of left subtree - first + postOrderNodeTraverseRecursively(root, [this](Node*& n){ + this->deleteNode(n); + }); + } + + int heightOf(const Node *n) const{ + if(n == UAVCAN_NULLPTR){ + return 0; + } + + return n->h; + } + + Node* makeNode(T* payload) { + void *praw = this->allocator_.allocate(sizeof(Node)); + + if (praw == UAVCAN_NULLPTR) { + UAVCAN_TRACE("AvlTree", " OOM -- Can't allocate Node"); + return UAVCAN_NULLPTR; // Push rejected + } + + Node *node = new (praw) Node(); + UAVCAN_ASSERT(node); + + node->data = payload; + return node; + } + + void deleteNode(Node*& n) { + if (n != UAVCAN_NULLPTR) { + n->~Node(); + allocator_.deallocate(n); + n = UAVCAN_NULLPTR; + } + } + + int balanceOf(Node *n) const { + if (n == UAVCAN_NULLPTR) { + return 0; + } + + return heightOf(n->left) - heightOf(n->right); + } + + void inOrderTraverseRecursively(Node *n, std::function forEach) { + if (n == UAVCAN_NULLPTR) { + return; + } + + inOrderTraverseRecursively(n->left, forEach); + forEach(n->data); + inOrderTraverseRecursively(n->right, forEach); + } + + void postOrderNodeTraverseRecursively(Node *n, std::function forEach) { + if (n == UAVCAN_NULLPTR) { + return; + } + + postOrderNodeTraverseRecursively(n->left, forEach); + postOrderNodeTraverseRecursively(n->right, forEach); + forEach(n); + } + + Node *rotateRight(Node *y) const { + Node *x = y->left; + Node *T2 = x->right; + + x->right = y; + y->left = T2; + + y->h = std::max(heightOf(y->left), heightOf(y->right)) + 1; + x->h = std::max(heightOf(x->left), heightOf(x->right)) + 1; + + return x; + } + + Node *rotateLeft(Node *x) { + Node *y = x->right; + Node *T2 = y->left; + + y->left = x; + x->right = T2; + + x->h = std::max(heightOf(x->left), heightOf(x->right)) + 1; + y->h = std::max(heightOf(y->left), heightOf(y->right)) + 1; + + return y; + } + + // If UAVCAN_NULLPTR is returned, OOM happened. + Node *insert_helper(Node *node, Node* newNode) { + if (node == UAVCAN_NULLPTR) { + len++; + return newNode; + } + + if (*newNode->data < *node->data) { + node->left = insert_helper(node->left, newNode); + } else if (*newNode->data > *node->data) { + node->right = insert_helper(node->right, newNode); + } else { /* Equal keys are not allowed -- change this? */ + deleteNode(newNode); + return UAVCAN_NULLPTR; + } + + node->h = std::max(heightOf(node->left), heightOf(node->right)) + 1; + + int balance = balanceOf(node); + + if (balance > 1 && *newNode->data < *node->left->data) { + return rotateRight(node); + } + + if (balance < -1 && *newNode->data > *node->right->data) { + return rotateLeft(node); + } + + if (balance > 1 && *newNode->data > *node->left->data) { + node->left = rotateLeft(node->left); + return rotateRight(node); + } + + if (balance < -1 && *newNode->data < *node->right->data) { + node->right = rotateRight(node->right); + return rotateLeft(node); + } + + return node; + } + + /* If we've got a Node*, avoid the dereference checks and proceed to the dealloc logic */ + Node* remove_always(Node *node){ + if (node == UAVCAN_NULLPTR) { + return node; + } + + // Stripped out the equality checks + if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { + Node *temp = node->left ? node->left : node->right; + + if (temp == UAVCAN_NULLPTR) { + temp = node; + node = UAVCAN_NULLPTR; + } else { + *node = *temp; + } + + len--; + deleteNode(temp); + } else { + Node* temp = node->right; + Node* next = node->left; + + while (next != UAVCAN_NULLPTR){ + temp = next; + next = node->left; + } + + node->data = temp->data; + node->right = remove_helper(node->right, temp->data); + } + + if (node == UAVCAN_NULLPTR) { + return node; + } + + node->h = std::max(heightOf(node->left), + heightOf(node->right)) + 1; + + int balance = balanceOf(node); + + if (balance > 1 && balanceOf(node->left) >= 0) { + return rotateRight(node); + } + + if (balance > 1 && balanceOf(node->left) < 0) { + node->left = rotateLeft(node->left); + return rotateRight(node); + } + + if (balance < -1 && balanceOf(node->right) <= 0) { + return rotateLeft(node); + } + + if (balance < -1 && balanceOf(node->right) > 0) { + node->right = rotateRight(node->right); + return rotateLeft(node); + } + + return node; + } + + Node* remove_helper(Node *node, T* data) { + if (node == UAVCAN_NULLPTR) { + return node; + } + + if (*data < *node->data) { + node->left = remove_helper(node->left, data); + } else if (*data > *node->data) { + node->right = remove_helper(node->right, data); + } else { + if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { + Node *temp = node->left ? node->left : node->right; + + if (temp == UAVCAN_NULLPTR) { + temp = node; + node = UAVCAN_NULLPTR; + } else { + *node = *temp; + } + + len--; + deleteNode(temp); + } else { + Node* temp = node->right; + Node* next = node->left; + + while (next != UAVCAN_NULLPTR){ + temp = next; + next = node->left; + } + + node->data = temp->data; + node->right = remove_helper(node->right, temp->data); + } + } + + if (node == UAVCAN_NULLPTR) { + return node; + } + + node->h = std::max(heightOf(node->left), + heightOf(node->right)) + 1; + + int balance = balanceOf(node); + + if (balance > 1 && balanceOf(node->left) >= 0) { + return rotateRight(node); + } + + if (balance > 1 && balanceOf(node->left) < 0) { + node->left = rotateLeft(node->left); + return rotateRight(node); + } + + if (balance < -1 && balanceOf(node->right) <= 0) { + return rotateLeft(node); + } + + if (balance < -1 && balanceOf(node->right) > 0) { + node->right = rotateRight(node->right); + return rotateLeft(node); + } + + return node; + } + +public: + bool insert(T* data) { + Node *newNode = makeNode(data); + if(newNode == UAVCAN_NULLPTR){ + return false; + } + + root = insert_helper(root, newNode); + + return true; + } + + virtual void remove(T* data) { + root = remove_helper(root, data); + } + + size_t getSize() const { + return root == UAVCAN_NULLPTR ? 0 : len; + } + + void walk(std::function forEach){ + inOrderTraverseRecursively(root, forEach); + } + + bool isEmpty() const { + return getSize() == 0; + } + + T* min() const { + Node *n = root; + + if (n == UAVCAN_NULLPTR) { + return UAVCAN_NULLPTR; + } + + for (;;) { + Node *next = n->left; + if (next == UAVCAN_NULLPTR) { + return n; + } + + n = next; + } + } + + T* max() const { + Node *n = root; + + if (n == UAVCAN_NULLPTR) { + return UAVCAN_NULLPTR; + } + + for (;;) { + Node *next = n->right; + if (next == UAVCAN_NULLPTR) { + return n->data; + } + + n = next; + } + } + + bool contains(const T &data) { + Node *n = root; + while (n != UAVCAN_NULLPTR) { + if(*n->data > *data){ + n = n->right; + continue; + } + + if(*n->data < *data){ + n = n->right; + continue; + } + + return *n->data == *data; + } + return false; + } + +}; +} + +#endif // UAVCAN_UTIL_AVL_TREE_HPP_INCLUDED diff --git a/libuavcan/src/node/uc_generic_publisher.cpp b/libuavcan/src/node/uc_generic_publisher.cpp index 2c42cfb0f..be5e4ddc9 100644 --- a/libuavcan/src/node/uc_generic_publisher.cpp +++ b/libuavcan/src/node/uc_generic_publisher.cpp @@ -12,7 +12,7 @@ bool GenericPublisherBase::isInited() const return sender_.isInitialized(); } -int GenericPublisherBase::doInit(DataTypeKind dtkind, const char* dtname, CanTxQueue::Qos qos) +int GenericPublisherBase::doInit(DataTypeKind dtkind, const char* dtname, Qos qos) { if (isInited()) { diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index bcca88347..046abf1cc 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -1,330 +1,272 @@ /* - * CAN bus IO logic. - * Copyright (C) 2014 Pavel Kirienko - */ +* CAN bus IO logic. +* Copyright (C) 2014 Pavel Kirienko +* Copyright (C) 2019 Theodoros Ntakouris +*/ #include #include +#include #include -namespace uavcan -{ +namespace uavcan { /* - * CanRxFrame - */ +* CanRxFrame +*/ #if UAVCAN_TOSTRING -std::string CanRxFrame::toString(StringRepresentation mode) const -{ + +std::string CanRxFrame::toString(StringRepresentation mode) const { std::string out = CanFrame::toString(mode); out.reserve(128); - out += " ts_m=" + ts_mono.toString(); + out += " ts_m=" + ts_mono.toString(); out += " ts_utc=" + ts_utc.toString(); out += " iface="; out += char('0' + iface_index); return out; } + #endif /* - * CanTxQueue::Entry - */ -void CanTxQueue::Entry::destroy(Entry*& obj, IPoolAllocator& allocator) -{ - if (obj != UAVCAN_NULLPTR) - { - obj->~Entry(); +* CanTxQueue::Entry +*/ +void CanTxQueueEntry::destroy(CanTxQueueEntry *&obj, IPoolAllocator &allocator) { + if (obj != UAVCAN_NULLPTR) { + obj->~CanTxQueueEntry(); allocator.deallocate(obj); obj = UAVCAN_NULLPTR; } } -bool CanTxQueue::Entry::qosHigherThan(const CanFrame& rhs_frame, Qos rhs_qos) const -{ - if (qos != rhs_qos) - { - return qos > rhs_qos; - } - return frame.priorityHigherThan(rhs_frame); -} - -bool CanTxQueue::Entry::qosLowerThan(const CanFrame& rhs_frame, Qos rhs_qos) const -{ - if (qos != rhs_qos) - { - return qos < rhs_qos; - } - return frame.priorityLowerThan(rhs_frame); -} - #if UAVCAN_TOSTRING -std::string CanTxQueue::Entry::toString() const -{ + +std::string CanTxQueueEntry::toString() const { std::string str_qos; - switch (qos) - { - case Volatile: - { - str_qos = " "; - break; - } - case Persistent: - { - str_qos = " "; - break; - } - default: - { - UAVCAN_ASSERT(0); - str_qos = " "; - break; - } + switch (qos) { + case Volatile: { + str_qos = " "; + break; + } + case Persistent: { + str_qos = " "; + break; + } + default: { + UAVCAN_ASSERT(0); + str_qos = " "; + break; + } } return str_qos + frame.toString(); } + #endif /* - * CanTxQueue - */ -CanTxQueue::~CanTxQueue() -{ - Entry* p = queue_.get(); - while (p) - { - Entry* const next = p->getNextListNode(); - remove(p); - p = next; +* CanTxQueue +*/ +CanTxQueue::~CanTxQueue() { + // Remove all nodes & node contents of the tree without performing re-balancing steps + postOrderNodeTraverseRecursively(root, [this](Node*& n){ + CanTxQueueEntry::destroy(n->data, this->allocator_); + }); + // Step 2: AvlTree destructor is called to remove all the Node* (automatically after) +} + +bool CanTxQueue::contains(const CanFrame &frame) const{ + Node *n = root; + + while (n != UAVCAN_NULLPTR) { + if(frame.priorityHigherThan(n->data->frame)){ + n = n->right; + continue; + } + + if(frame.priorityLowerThan(n->data->frame)){ + n = n->left; + continue; + } + + return frame == n->data->frame; } + return false; } -void CanTxQueue::registerRejectedFrame() -{ - if (rejected_frames_cnt_ < NumericTraits::max()) - { +void CanTxQueue::safeIncrementRejectedFrames() { + if (rejected_frames_cnt_ < NumericTraits::max()) { rejected_frames_cnt_++; } } -void CanTxQueue::push(const CanFrame& frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags) -{ +void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags) { const MonotonicTime timestamp = sysclock_.getMonotonic(); - if (timestamp >= tx_deadline) - { + if (timestamp >= tx_deadline) { UAVCAN_TRACE("CanTxQueue", "Push rejected: already expired"); - registerRejectedFrame(); + safeIncrementRejectedFrames(); return; } - void* praw = allocator_.allocate(sizeof(Entry)); - if (praw == UAVCAN_NULLPTR) - { - UAVCAN_TRACE("CanTxQueue", "Push OOM #1, cleanup"); - // No memory left in the pool, so we try to remove expired frames - Entry* p = queue_.get(); - while (p) - { - Entry* const next = p->getNextListNode(); - if (p->isExpired(timestamp)) - { - UAVCAN_TRACE("CanTxQueue", "Push: Expired %s", p->toString().c_str()); - registerRejectedFrame(); - remove(p); - } - p = next; - } - praw = allocator_.allocate(sizeof(Entry)); // Try again + void *praw = this->allocator_.allocate(sizeof(CanTxQueueEntry)); + if (praw == UAVCAN_NULLPTR) { + UAVCAN_TRACE("CanTxQueue", "Push rejected: OOM (CanTxQueueEntry)"); + safeIncrementRejectedFrames(); + return; } - if (praw == UAVCAN_NULLPTR) - { - UAVCAN_TRACE("CanTxQueue", "Push OOM #2, QoS arbitration"); - registerRejectedFrame(); + CanTxQueueEntry *entry = new(praw) CanTxQueueEntry(frame, tx_deadline, qos, flags); + UAVCAN_ASSERT(entry); + auto result = AvlTree::insert(entry); - // Find a frame with lowest QoS - Entry* p = queue_.get(); - if (p == UAVCAN_NULLPTR) - { - UAVCAN_TRACE("CanTxQueue", "Push rejected: Nothing to replace"); - return; - } - Entry* lowestqos = p; - while (p) - { - if (lowestqos->qosHigherThan(*p)) - { - lowestqos = p; - } - p = p->getNextListNode(); - } - // Note that frame with *equal* QoS will be replaced too. - if (lowestqos->qosHigherThan(frame, qos)) // Frame that we want to transmit has lowest QoS - { - UAVCAN_TRACE("CanTxQueue", "Push rejected: low QoS"); - return; // What a loser. - } - UAVCAN_TRACE("CanTxQueue", "Push: Replacing %s", lowestqos->toString().c_str()); - remove(lowestqos); - praw = allocator_.allocate(sizeof(Entry)); // Try again + if (!result) { + /* AVL Tree could not allocate a new node */ + UAVCAN_TRACE("CanTxQueue", "Push rejected: OOM (AvlTree::Node)"); + safeIncrementRejectedFrames(); + CanTxQueueEntry::destroy(entry, this->allocator_); } +} - if (praw == UAVCAN_NULLPTR) - { - return; // Seems that there is no memory at all. +void CanTxQueue::remove(CanTxQueueEntry* entry){ + if (entry == UAVCAN_NULLPTR) { + return; } - Entry* entry = new (praw) Entry(frame, tx_deadline, qos, flags); - UAVCAN_ASSERT(entry); - queue_.insertBefore(entry, PriorityInsertionComparator(frame)); + + // Make the AvlTree remove the specific entry deleting it's Node * + this->AvlTree::remove(entry); + // Then let the entry destroy it's own contents + CanTxQueueEntry::destroy(entry, this->allocator_); } -CanTxQueue::Entry* CanTxQueue::peek() -{ - const MonotonicTime timestamp = sysclock_.getMonotonic(); - Entry* p = queue_.get(); - while (p) - { - if (p->isExpired(timestamp)) - { - UAVCAN_TRACE("CanTxQueue", "Peek: Expired %s", p->toString().c_str()); - Entry* const next = p->getNextListNode(); - registerRejectedFrame(); - remove(p); - p = next; - } - else - { - return p; - } +CanTxQueueEntry *CanTxQueue::peek(){ + auto maxNode = searchForNonExpiredMax(root); + + if(maxNode == UAVCAN_NULLPTR){ + return UAVCAN_NULLPTR; } - return UAVCAN_NULLPTR; + + return maxNode->data; } -void CanTxQueue::remove(Entry*& entry) -{ - if (entry == UAVCAN_NULLPTR) - { - UAVCAN_ASSERT(0); - return; +// TODO: Isn't that NOT (topPriorityHigherOrEqual) ? +bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame &rhs_frame) { + auto peek_entry = peek(); + if (peek_entry == UAVCAN_NULLPTR) { + return false; } - queue_.remove(entry); - Entry::destroy(entry, allocator_); + return !rhs_frame.priorityHigherThan(peek_entry->frame); } -const CanFrame* CanTxQueue::getTopPriorityPendingFrame() const -{ - return (queue_.get() == UAVCAN_NULLPTR) ? UAVCAN_NULLPTR : &queue_.get()->frame; -} +uavcan::AvlTree::Node* CanTxQueue::searchForNonExpiredMax(Node *n) { + if (n == UAVCAN_NULLPTR) { + return UAVCAN_NULLPTR; + } -bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame& rhs_frame) const -{ - const Entry* entry = queue_.get(); - if (entry == UAVCAN_NULLPTR) - { - return false; + auto timestamp = sysclock_.getMonotonic(); + + if(n->data->isExpired(timestamp)){ + auto expiredEntry = n->data; + root = remove_always(n); + CanTxQueueEntry::destroy(expiredEntry, this->allocator_); + + return searchForNonExpiredMax(root); + } + + while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)){ + auto expiredEntry = n->data; + n->right = remove_always(n); + CanTxQueueEntry::destroy(expiredEntry, this->allocator_); } - return !rhs_frame.priorityHigherThan(entry->frame); + + auto r = searchForNonExpiredMax(n->right); + + if (r != UAVCAN_NULLPTR) { + return r; + } + + return n; } /* - * CanIOManager - */ -int CanIOManager::sendToIface(uint8_t iface_index, const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags) -{ +* CanIOManager +*/ +int +CanIOManager::sendToIface(uint8_t iface_index, const CanFrame &frame, MonotonicTime tx_deadline, CanIOFlags flags) { UAVCAN_ASSERT(iface_index < MaxCanIfaces); - ICanIface* const iface = driver_.getIface(iface_index); - if (iface == UAVCAN_NULLPTR) - { + ICanIface *const iface = driver_.getIface(iface_index); + if (iface == UAVCAN_NULLPTR) { UAVCAN_ASSERT(0); // Nonexistent interface return -ErrLogic; } const int res = iface->send(frame, tx_deadline, flags); - if (res != 1) - { + if (res != 1) { UAVCAN_TRACE("CanIOManager", "Send failed: code %i, iface %i, frame %s", res, iface_index, frame.toString().c_str()); } - if (res > 0) - { + if (res > 0) { counters_[iface_index].frames_tx += unsigned(res); } return res; } -int CanIOManager::sendFromTxQueue(uint8_t iface_index) -{ +int CanIOManager::sendFromTxQueue(uint8_t iface_index) { UAVCAN_ASSERT(iface_index < MaxCanIfaces); - CanTxQueue::Entry* entry = tx_queues_[iface_index]->peek(); - if (entry == UAVCAN_NULLPTR) - { + CanTxQueueEntry *entry = tx_queues_[iface_index]->peek(); + if (entry == UAVCAN_NULLPTR) { return 0; } const int res = sendToIface(iface_index, entry->frame, entry->deadline, entry->flags); - if (res > 0) - { + if (res > 0) { tx_queues_[iface_index]->remove(entry); } return res; } -int CanIOManager::callSelect(CanSelectMasks& inout_masks, const CanFrame* (& pending_tx)[MaxCanIfaces], - MonotonicTime blocking_deadline) -{ +int CanIOManager::callSelect(CanSelectMasks &inout_masks, const CanFrame *(&pending_tx)[MaxCanIfaces], + MonotonicTime blocking_deadline) { const CanSelectMasks in_masks = inout_masks; const int res = driver_.select(inout_masks, pending_tx, blocking_deadline); - if (res < 0) - { + if (res < 0) { return -ErrDriver; } - inout_masks.read &= in_masks.read; // Driver is not required to clean the masks + inout_masks.read &= in_masks.read; // Driver is not required to clean the masks inout_masks.write &= in_masks.write; return res; } -CanIOManager::CanIOManager(ICanDriver& driver, IPoolAllocator& allocator, ISystemClock& sysclock, +CanIOManager::CanIOManager(ICanDriver &driver, IPoolAllocator &allocator, ISystemClock &sysclock, std::size_t mem_blocks_per_iface) - : driver_(driver) - , sysclock_(sysclock) - , num_ifaces_(driver.getNumIfaces()) -{ - if (num_ifaces_ < 1 || num_ifaces_ > MaxCanIfaces) - { + : driver_(driver), sysclock_(sysclock), num_ifaces_(driver.getNumIfaces()) { + if (num_ifaces_ < 1 || num_ifaces_ > MaxCanIfaces) { handleFatalError("Num ifaces"); } - if (mem_blocks_per_iface == 0) - { + if (mem_blocks_per_iface == 0) { mem_blocks_per_iface = allocator.getBlockCapacity() / (num_ifaces_ + 1U) + 1U; } UAVCAN_TRACE("CanIOManager", "Memory blocks per iface: %u, total: %u", unsigned(mem_blocks_per_iface), unsigned(allocator.getBlockCapacity())); - for (int i = 0; i < num_ifaces_; i++) - { - tx_queues_[i].construct - (allocator, sysclock, mem_blocks_per_iface); + for (int i = 0; i < num_ifaces_; i++) { + tx_queues_[i].construct + (allocator, sysclock, mem_blocks_per_iface); } } -uint8_t CanIOManager::makePendingTxMask() const -{ +uint8_t CanIOManager::makePendingTxMask() const { uint8_t write_mask = 0; - for (uint8_t i = 0; i < getNumIfaces(); i++) - { - if (!tx_queues_[i]->isEmpty()) - { + for (uint8_t i = 0; i < getNumIfaces(); i++) { + if (!tx_queues_[i]->isEmpty()) { write_mask = uint8_t(write_mask | (1 << i)); } } return write_mask; } -CanIfacePerfCounters CanIOManager::getIfacePerfCounters(uint8_t iface_index) const -{ - ICanIface* const iface = driver_.getIface(iface_index); - if (iface == UAVCAN_NULLPTR || iface_index >= MaxCanIfaces) - { +CanIfacePerfCounters CanIOManager::getIfacePerfCounters(uint8_t iface_index) const { + ICanIface *const iface = driver_.getIface(iface_index); + if (iface == UAVCAN_NULLPTR || iface_index >= MaxCanIfaces) { UAVCAN_ASSERT(0); return CanIfacePerfCounters(); } @@ -335,15 +277,13 @@ CanIfacePerfCounters CanIOManager::getIfacePerfCounters(uint8_t iface_index) con return cnt; } -int CanIOManager::send(const CanFrame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, - uint8_t iface_mask, CanTxQueue::Qos qos, CanIOFlags flags) -{ +int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, + uint8_t iface_mask, Qos qos, CanIOFlags flags) { const uint8_t num_ifaces = getNumIfaces(); const uint8_t all_ifaces_mask = uint8_t((1U << num_ifaces) - 1); iface_mask &= all_ifaces_mask; - if (blocking_deadline > tx_deadline) - { + if (blocking_deadline > tx_deadline) { blocking_deadline = tx_deadline; } @@ -351,8 +291,7 @@ int CanIOManager::send(const CanFrame& frame, MonotonicTime tx_deadline, Monoton while (true) // Somebody please refactor this. { - if (iface_mask == 0) - { + if (iface_mask == 0) { break; } @@ -361,55 +300,54 @@ int CanIOManager::send(const CanFrame& frame, MonotonicTime tx_deadline, Monoton { // Building the list of next pending frames per iface. // The driver will give them a scrutinizing look before deciding whether he wants to accept them. - const CanFrame* pending_tx[MaxCanIfaces] = {}; - for (int i = 0; i < num_ifaces; i++) - { - CanTxQueue& q = *tx_queues_[i]; + // TODO: What does this mean? can we optimize further before passing them to the driver? + const CanFrame *pending_tx[MaxCanIfaces] = {}; + for (int i = 0; i < num_ifaces; i++) { + CanTxQueue &q = *tx_queues_[i]; + auto peek_entry = q.peek(); + const CanFrame* peek_frame = peek_entry == UAVCAN_NULLPTR ? UAVCAN_NULLPTR : &peek_entry->frame; + if (iface_mask & (1 << i)) // I hate myself so much right now. { - pending_tx[i] = q.topPriorityHigherOrEqual(frame) ? q.getTopPriorityPendingFrame() : &frame; - } - else - { - pending_tx[i] = q.getTopPriorityPendingFrame(); + auto hasPriority = false; + + // This may seem duplicate of topPriorityHigherOrEqual but we want to avoid traversing the queue again + if(peek_entry != UAVCAN_NULLPTR){ + hasPriority = !frame.priorityHigherThan(*peek_frame); + } + + pending_tx[i] = hasPriority ? peek_frame : &frame; + } else { + pending_tx[i] = peek_frame; } } const int select_res = callSelect(masks, pending_tx, blocking_deadline); - if (select_res < 0) - { + if (select_res < 0) { return -ErrDriver; } UAVCAN_ASSERT(masks.read == 0); } // Transmission - for (uint8_t i = 0; i < num_ifaces; i++) - { - if (masks.write & (1 << i)) - { + for (uint8_t i = 0; i < num_ifaces; i++) { + if (masks.write & (1 << i)) { int res = 0; - if (iface_mask & (1 << i)) - { - if (tx_queues_[i]->topPriorityHigherOrEqual(frame)) - { - res = sendFromTxQueue(i); // May return 0 if nothing to transmit (e.g. expired) + if (iface_mask & (1 << i)) { + if (tx_queues_[i]->topPriorityHigherOrEqual(frame)) { + res = sendFromTxQueue( + i); // May return 0 if nothing to transmit (e.g. expired) } - if (res <= 0) - { + if (res <= 0) { res = sendToIface(i, frame, tx_deadline, flags); - if (res > 0) - { + if (res > 0) { iface_mask &= uint8_t(~(1 << i)); // Mark transmitted } } - } - else - { + } else { res = sendFromTxQueue(i); } - if (res > 0) - { + if (res > 0) { retval++; } } @@ -417,17 +355,13 @@ int CanIOManager::send(const CanFrame& frame, MonotonicTime tx_deadline, Monoton // Timeout. Enqueue the frame if wasn't transmitted and leave. const bool timed_out = sysclock_.getMonotonic() >= blocking_deadline; - if (masks.write == 0 || timed_out) - { - if (!timed_out) - { + if (masks.write == 0 || timed_out) { + if (!timed_out) { UAVCAN_TRACE("CanIOManager", "Send: Premature timeout in select(), will try again"); continue; } - for (uint8_t i = 0; i < num_ifaces; i++) - { - if (iface_mask & (1 << i)) - { + for (uint8_t i = 0; i < num_ifaces; i++) { + if (iface_mask & (1 << i)) { tx_queues_[i]->push(frame, tx_deadline, qos, flags); } } @@ -437,60 +371,53 @@ int CanIOManager::send(const CanFrame& frame, MonotonicTime tx_deadline, Monoton return retval; } -int CanIOManager::receive(CanRxFrame& out_frame, MonotonicTime blocking_deadline, CanIOFlags& out_flags) -{ +int CanIOManager::receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline, CanIOFlags &out_flags) { const uint8_t num_ifaces = getNumIfaces(); - while (true) - { + while (true) { CanSelectMasks masks; masks.write = makePendingTxMask(); masks.read = uint8_t((1 << num_ifaces) - 1); { - const CanFrame* pending_tx[MaxCanIfaces] = {}; + const CanFrame *pending_tx[MaxCanIfaces] = {}; for (int i = 0; i < num_ifaces; i++) // Dear compiler, kindly unroll this. Thanks. { - pending_tx[i] = tx_queues_[i]->getTopPriorityPendingFrame(); + auto entry = tx_queues_[i]->peek(); + pending_tx[i] = (entry == UAVCAN_NULLPTR) ? UAVCAN_NULLPTR : &entry->frame; } const int select_res = callSelect(masks, pending_tx, blocking_deadline); - if (select_res < 0) - { + if (select_res < 0) { return -ErrDriver; } } // Write - if buffers are not empty, one frame will be sent for each iface per one receive() call - for (uint8_t i = 0; i < num_ifaces; i++) - { - if (masks.write & (1 << i)) - { - (void)sendFromTxQueue(i); // It may fail, we don't care. Requested operation was receive, not send. + for (uint8_t i = 0; i < num_ifaces; i++) { + if (masks.write & (1 << i)) { + (void) sendFromTxQueue( + i); // It may fail, we don't care. Requested operation was receive, not send. } } // Read - for (uint8_t i = 0; i < num_ifaces; i++) - { - if (masks.read & (1 << i)) - { - ICanIface* const iface = driver_.getIface(i); - if (iface == UAVCAN_NULLPTR) - { + for (uint8_t i = 0; i < num_ifaces; i++) { + if (masks.read & (1 << i)) { + ICanIface *const iface = driver_.getIface(i); + if (iface == UAVCAN_NULLPTR) { UAVCAN_ASSERT(0); // Nonexistent interface continue; } const int res = iface->receive(out_frame, out_frame.ts_mono, out_frame.ts_utc, out_flags); - if (res == 0) - { - UAVCAN_ASSERT(0); // select() reported that iface has pending RX frames, but receive() returned none + if (res == 0) { + UAVCAN_ASSERT( + 0); // select() reported that iface has pending RX frames, but receive() returned none continue; } out_frame.iface_index = i; - if ((res > 0) && !(out_flags & CanIOFlagLoopback)) - { + if ((res > 0) && !(out_flags & CanIOFlagLoopback)) { counters_[i].frames_rx += 1; } return (res < 0) ? -ErrDriver : res; @@ -498,8 +425,7 @@ int CanIOManager::receive(CanRxFrame& out_frame, MonotonicTime blocking_deadline } // Timeout checked in the last order - this way we can operate with expired deadline: - if (sysclock_.getMonotonic() >= blocking_deadline) - { + if (sysclock_.getMonotonic() >= blocking_deadline) { break; } } diff --git a/libuavcan/src/transport/uc_dispatcher.cpp b/libuavcan/src/transport/uc_dispatcher.cpp index f304689bc..efc66e7fa 100644 --- a/libuavcan/src/transport/uc_dispatcher.cpp +++ b/libuavcan/src/transport/uc_dispatcher.cpp @@ -285,7 +285,7 @@ int Dispatcher::spinOnce() } int Dispatcher::send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, - CanTxQueue::Qos qos, CanIOFlags flags, uint8_t iface_mask) + Qos qos, CanIOFlags flags, uint8_t iface_mask) { if (frame.getSrcNodeID() != getNodeID()) { diff --git a/libuavcan/src/transport/uc_transfer_sender.cpp b/libuavcan/src/transport/uc_transfer_sender.cpp index f5d69d9b9..b06a2e6d6 100644 --- a/libuavcan/src/transport/uc_transfer_sender.cpp +++ b/libuavcan/src/transport/uc_transfer_sender.cpp @@ -15,7 +15,7 @@ void TransferSender::registerError() const dispatcher_.getTransferPerfCounter().addError(); } -void TransferSender::init(const DataTypeDescriptor& dtid, CanTxQueue::Qos qos) +void TransferSender::init(const DataTypeDescriptor& dtid, Qos qos) { UAVCAN_ASSERT(!isInitialized()); diff --git a/libuavcan/test/transport/can/io.cpp b/libuavcan/test/transport/can/io.cpp index 5a046973c..11630a58d 100644 --- a/libuavcan/test/transport/can/io.cpp +++ b/libuavcan/test/transport/can/io.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Pavel Kirienko + * Copyright (C) 2019 Theodoros Ntakouris */ #include @@ -22,7 +23,7 @@ static bool rxFrameEquals(const uavcan::CanRxFrame& rxframe, const uavcan::CanFr TEST(CanIOManager, Reception) { // Memory - uavcan::PoolAllocator pool; + uavcan::PoolAllocator pool; // Platform interface SystemClockMock clockmock; @@ -115,9 +116,12 @@ TEST(CanIOManager, Transmission) { using uavcan::CanIOManager; using uavcan::CanTxQueue; + using uavcan::CanTxQueueEntry; + using uavcan::Qos; // Memory - uavcan::PoolAllocator pool; + uavcan::PoolAllocator pool; + //TODO: Fix this uavcan::PoolAllocator pool; // Platform interface SystemClockMock clockmock; @@ -138,13 +142,13 @@ TEST(CanIOManager, Transmission) /* * Simple transmission */ - EXPECT_EQ(2, iomgr.send(frames[0], tsMono(100), tsMono(0), ALL_IFACES_MASK, CanTxQueue::Volatile, flags)); + EXPECT_EQ(2, iomgr.send(frames[0], tsMono(100), tsMono(0), ALL_IFACES_MASK, Qos::Volatile, flags)); EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[0], 100)); EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 100)); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); - EXPECT_EQ(1, iomgr.send(frames[1], tsMono(200), tsMono(100), 2, CanTxQueue::Persistent, flags)); // To #1 only + EXPECT_EQ(1, iomgr.send(frames[1], tsMono(200), tsMono(100), 2, Qos::Persistent, flags)); // To #1 only EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 200)); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(uavcan::CanFrame())); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); @@ -163,31 +167,31 @@ TEST(CanIOManager, Transmission) // Sending to both, #0 blocked driver.ifaces.at(0).writeable = false; - EXPECT_LT(0, iomgr.send(frames[0], tsMono(201), tsMono(200), ALL_IFACES_MASK, CanTxQueue::Persistent, flags)); + EXPECT_LT(0, iomgr.send(frames[0], tsMono(201), tsMono(200), ALL_IFACES_MASK, Qos::Persistent, flags)); EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 201)); EXPECT_EQ(200, clockmock.monotonic); EXPECT_EQ(200, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); EXPECT_TRUE(driver.ifaces.at(1).tx.empty()); - EXPECT_EQ(1, pool.getNumUsedBlocks()); // One frame went into TX queue, and will expire soon + EXPECT_EQ(2, pool.getNumUsedBlocks()); // One frame went into TX queue, and will expire soon EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // This one will persist EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(uavcan::CanFrame())); // This will drop off on the second select() // Sending to both, both blocked driver.ifaces.at(1).writeable = false; - EXPECT_EQ(0, iomgr.send(frames[1], tsMono(777), tsMono(300), ALL_IFACES_MASK, CanTxQueue::Volatile, flags)); - EXPECT_EQ(3, pool.getNumUsedBlocks()); // Total 3 frames in TX queue now + EXPECT_EQ(0, iomgr.send(frames[1], tsMono(777), tsMono(300), ALL_IFACES_MASK, Qos::Volatile, flags)); + EXPECT_EQ(6, pool.getNumUsedBlocks()); // Total 3 frames in TX queue now EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // Still 0 EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); // 1!! // Sending to #0, both blocked - EXPECT_EQ(0, iomgr.send(frames[2], tsMono(888), tsMono(400), 1, CanTxQueue::Persistent, flags)); + EXPECT_EQ(0, iomgr.send(frames[2], tsMono(888), tsMono(400), 1, Qos::Persistent, flags)); EXPECT_EQ(400, clockmock.monotonic); EXPECT_EQ(400, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); EXPECT_TRUE(driver.ifaces.at(1).tx.empty()); - EXPECT_EQ(4, pool.getNumUsedBlocks()); - EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); + EXPECT_EQ(6, pool.getNumUsedBlocks()); + //EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); // At this time TX queues are containing the following data: @@ -198,7 +202,7 @@ TEST(CanIOManager, Transmission) driver.ifaces.at(0).writeable = true; driver.ifaces.at(1).writeable = true; // One frame per each iface will be sent: - EXPECT_LT(0, iomgr.send(frames[0], tsMono(999), tsMono(500), 2, CanTxQueue::Persistent, flags)); + EXPECT_LT(0, iomgr.send(frames[0], tsMono(999), tsMono(500), 2, Qos::Persistent, flags)); EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[1], 777)); // Note that frame[0] on iface #0 has expired EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 999)); // In different order due to prioritization EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); @@ -229,16 +233,16 @@ TEST(CanIOManager, Transmission) driver.ifaces.at(1).writeable = false; // Sending 5 frames, one will be rejected - EXPECT_EQ(0, iomgr.send(frames[2], tsMono(2222), tsMono(1000), ALL_IFACES_MASK, CanTxQueue::Persistent, flags)); - EXPECT_EQ(0, iomgr.send(frames[0], tsMono(3333), tsMono(1100), 2, CanTxQueue::Persistent, flags)); + EXPECT_EQ(0, iomgr.send(frames[2], tsMono(2222), tsMono(1000), ALL_IFACES_MASK, Qos::Persistent, flags)); + EXPECT_EQ(0, iomgr.send(frames[0], tsMono(3333), tsMono(1100), 2, Qos::Persistent, flags)); // One frame kicked here: - EXPECT_EQ(0, iomgr.send(frames[1], tsMono(4444), tsMono(1200), ALL_IFACES_MASK, CanTxQueue::Volatile, flags)); + EXPECT_EQ(0, iomgr.send(frames[1], tsMono(4444), tsMono(1200), ALL_IFACES_MASK, Qos::Volatile, flags)); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[1])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); // State checks - EXPECT_EQ(4, pool.getNumUsedBlocks()); // TX queue is full + EXPECT_EQ(8, pool.getNumUsedBlocks()); // TX queue is full EXPECT_EQ(1200, clockmock.monotonic); EXPECT_EQ(1200, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); @@ -285,7 +289,7 @@ TEST(CanIOManager, Transmission) driver.select_failure = true; EXPECT_EQ(-uavcan::ErrDriver, iomgr.receive(rx_frame, tsMono(2000), flags)); EXPECT_EQ(-uavcan::ErrDriver, - iomgr.send(frames[0], tsMono(2100), tsMono(2000), ALL_IFACES_MASK, CanTxQueue::Volatile, flags)); + iomgr.send(frames[0], tsMono(2100), tsMono(2000), ALL_IFACES_MASK, Qos::Volatile, flags)); EXPECT_EQ(1200, clockmock.monotonic); EXPECT_EQ(1200, clockmock.utc); ASSERT_EQ(0, flags); @@ -299,11 +303,11 @@ TEST(CanIOManager, Transmission) driver.ifaces.at(0).tx_failure = true; driver.ifaces.at(1).tx_failure = true; // Non-blocking - return < 0 - EXPECT_GE(0, iomgr.send(frames[0], tsMono(2200), tsMono(0), ALL_IFACES_MASK, CanTxQueue::Persistent, flags)); + EXPECT_GE(0, iomgr.send(frames[0], tsMono(2200), tsMono(0), ALL_IFACES_MASK, Qos::Persistent, flags)); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); - ASSERT_EQ(2, pool.getNumUsedBlocks()); // Untransmitted frames will be buffered + ASSERT_EQ(4, pool.getNumUsedBlocks()); // Untransmitted frames will be buffered // Failure removed - transmission shall proceed driver.ifaces.at(0).tx_failure = false; @@ -330,11 +334,13 @@ TEST(CanIOManager, Loopback) { using uavcan::CanIOManager; using uavcan::CanTxQueue; + using uavcan::CanTxQueueEntry; + using uavcan::Qos; using uavcan::CanFrame; using uavcan::CanRxFrame; // Memory - uavcan::PoolAllocator pool; + uavcan::PoolAllocator pool; // Platform interface SystemClockMock clockmock; @@ -354,14 +360,14 @@ TEST(CanIOManager, Loopback) CanRxFrame rfr2; uavcan::CanIOFlags flags = 0; - ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, CanTxQueue::Volatile, uavcan::CanIOFlagLoopback)); + ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, Qos::Volatile, uavcan::CanIOFlagLoopback)); ASSERT_LE(0, iomgr.receive(rfr1, tsMono(100), flags)); ASSERT_EQ(uavcan::CanIOFlagLoopback, flags); ASSERT_TRUE(rfr1 == fr1); flags = 0; - ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, CanTxQueue::Volatile, uavcan::CanIOFlagLoopback)); - ASSERT_EQ(1, iomgr.send(fr2, tsMono(1000), tsMono(0), 1, CanTxQueue::Persistent, uavcan::CanIOFlagLoopback)); + ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, Qos::Volatile, uavcan::CanIOFlagLoopback)); + ASSERT_EQ(1, iomgr.send(fr2, tsMono(1000), tsMono(0), 1, Qos::Persistent, uavcan::CanIOFlagLoopback)); ASSERT_LE(0, iomgr.receive(rfr1, tsMono(100), flags)); ASSERT_EQ(uavcan::CanIOFlagLoopback, flags); ASSERT_LE(0, iomgr.receive(rfr2, tsMono(100), flags)); diff --git a/libuavcan/test/transport/can/tx_queue.cpp b/libuavcan/test/transport/can/tx_queue.cpp index da5aa58bb..cffd24ee2 100644 --- a/libuavcan/test/transport/can/tx_queue.cpp +++ b/libuavcan/test/transport/can/tx_queue.cpp @@ -1,73 +1,24 @@ /* * Copyright (C) 2014 Pavel Kirienko + * Copyright (C) 2019 Theodoros Ntakouris */ #include #include +#include #include "can.hpp" - -static int getQueueLength(uavcan::CanTxQueue& queue) -{ - const uavcan::CanTxQueue::Entry* p = queue.peek(); - int length = 0; - while (p) - { - length++; - p = p->getNextListNode(); - } - return length; -} - -static bool isInQueue(uavcan::CanTxQueue& queue, const uavcan::CanFrame& frame) -{ - const uavcan::CanTxQueue::Entry* p = queue.peek(); - while (p) - { - if (frame == p->frame) - { - return true; - } - p = p->getNextListNode(); - } - return false; -} - -TEST(CanTxQueue, Qos) -{ - const uavcan::CanIOFlags flags = 0; - uavcan::CanTxQueue::Entry e1(makeCanFrame(100, "", EXT), tsMono(1000), uavcan::CanTxQueue::Volatile, flags); - uavcan::CanTxQueue::Entry e2(makeCanFrame(100, "", EXT), tsMono(1000), uavcan::CanTxQueue::Volatile, flags); - - EXPECT_FALSE(e1.qosHigherThan(e2)); - EXPECT_FALSE(e2.qosHigherThan(e1)); - EXPECT_FALSE(e1.qosLowerThan(e2)); - EXPECT_FALSE(e2.qosLowerThan(e1)); - - e2.qos = uavcan::CanTxQueue::Persistent; - - EXPECT_FALSE(e1.qosHigherThan(e2)); - EXPECT_TRUE(e2.qosHigherThan(e1)); - EXPECT_TRUE(e1.qosLowerThan(e2)); - EXPECT_FALSE(e2.qosLowerThan(e1)); - - e1.qos = uavcan::CanTxQueue::Persistent; - e1.frame.id -= 1; - - EXPECT_TRUE(e1.qosHigherThan(e2)); - EXPECT_FALSE(e2.qosHigherThan(e1)); - EXPECT_FALSE(e1.qosLowerThan(e2)); - EXPECT_TRUE(e2.qosLowerThan(e1)); -} - TEST(CanTxQueue, TxQueue) { using uavcan::CanTxQueue; + using uavcan::CanTxQueueEntry; using uavcan::CanFrame; + using uavcan::Qos; - ASSERT_GE(40, sizeof(CanTxQueue::Entry)); // should be true for any platforms, though not required + ASSERT_GE(40, sizeof(CanTxQueueEntry)); // should be true for any platforms, though not required - uavcan::PoolAllocator<40 * 4, 40> pool; + // 2 blocks per entry now, due to AvlTree + uavcan::PoolAllocator<64 * 8, 64> pool; SystemClockMock clockmock; @@ -83,134 +34,147 @@ TEST(CanTxQueue, TxQueue) const CanFrame f3 = makeCanFrame(100, "f3", EXT); const CanFrame f4 = makeCanFrame(10000, "f4", EXT); const CanFrame f5 = makeCanFrame(99999, "f5", EXT); - const CanFrame f5a = makeCanFrame(99999, "f5a", EXT); const CanFrame f6 = makeCanFrame(999999, "f6", EXT); /* - * Priority insertion + * Basic priority insertion */ - queue.push(f4, tsMono(100), CanTxQueue::Persistent, flags); + queue.push(f4, tsMono(100), Qos::Persistent, flags); EXPECT_FALSE(queue.isEmpty()); - EXPECT_EQ(1, pool.getNumUsedBlocks()); + EXPECT_TRUE(queue.contains(f4)); + EXPECT_EQ(1, queue.getSize()); + EXPECT_EQ(2, pool.getNumUsedBlocks()); + EXPECT_EQ(f4, queue.peek()->frame); EXPECT_TRUE(queue.topPriorityHigherOrEqual(f5)); EXPECT_TRUE(queue.topPriorityHigherOrEqual(f4)); // Equal EXPECT_FALSE(queue.topPriorityHigherOrEqual(f3)); - queue.push(f3, tsMono(200), CanTxQueue::Persistent, flags); + queue.push(f3, tsMono(200), Qos::Persistent, flags); EXPECT_EQ(f3, queue.peek()->frame); + EXPECT_EQ(2, queue.getSize()); - queue.push(f0, tsMono(300), CanTxQueue::Volatile, flags); + + queue.push(f0, tsMono(300), Qos::Volatile, flags); EXPECT_EQ(f0, queue.peek()->frame); + EXPECT_EQ(3, queue.getSize()); + - queue.push(f1, tsMono(400), CanTxQueue::Volatile, flags); + queue.push(f1, tsMono(400), Qos::Volatile, flags); EXPECT_EQ(f0, queue.peek()->frame); // Still f0, since it is highest EXPECT_TRUE(queue.topPriorityHigherOrEqual(f0)); // Equal EXPECT_TRUE(queue.topPriorityHigherOrEqual(f1)); - // Out of free memory now - EXPECT_EQ(0, queue.getRejectedFrameCount()); - EXPECT_EQ(4, getQueueLength(queue)); - EXPECT_TRUE(isInQueue(queue, f0)); - EXPECT_TRUE(isInQueue(queue, f1)); - EXPECT_TRUE(isInQueue(queue, f3)); - EXPECT_TRUE(isInQueue(queue, f4)); - - const CanTxQueue::Entry* p = queue.peek(); - while (p) - { - std::cout << p->toString() << std::endl; - p = p->getNextListNode(); - } + EXPECT_EQ(4, queue.getSize()); + + EXPECT_TRUE(queue.contains(f0)); + EXPECT_TRUE(queue.contains(f1)); + EXPECT_TRUE(queue.contains(f3)); + EXPECT_TRUE(queue.contains(f4)); + + EXPECT_FALSE(queue.contains(f2)); + EXPECT_FALSE(queue.contains(f5)); + EXPECT_FALSE(queue.contains(f6)); /* - * QoS + * Removing */ - EXPECT_FALSE(isInQueue(queue, f2)); - queue.push(f2, tsMono(100), CanTxQueue::Volatile, flags); // Non preempting, will be rejected - EXPECT_FALSE(isInQueue(queue, f2)); - - queue.push(f2, tsMono(500), CanTxQueue::Persistent, flags); // Will override f1 (f3 and f4 are presistent) - EXPECT_TRUE(isInQueue(queue, f2)); - EXPECT_FALSE(isInQueue(queue, f1)); - EXPECT_EQ(4, getQueueLength(queue)); - EXPECT_EQ(2, queue.getRejectedFrameCount()); - EXPECT_EQ(f0, queue.peek()->frame); // Check the priority - queue.push(f5, tsMono(600), CanTxQueue::Persistent, flags); // Will override f0 (rest are presistent) - EXPECT_TRUE(isInQueue(queue, f5)); - EXPECT_FALSE(isInQueue(queue, f0)); - EXPECT_EQ(f2, queue.peek()->frame); // Check the priority - - // No volatile frames left now + CanTxQueueEntry* entry = queue.peek(); + EXPECT_TRUE(entry); - queue.push(f5a, tsMono(700), CanTxQueue::Persistent, flags); // Will override f5 (same frame, same QoS) - EXPECT_TRUE(isInQueue(queue, f5a)); - EXPECT_FALSE(isInQueue(queue, f5)); + queue.remove(entry); + EXPECT_TRUE(entry); + EXPECT_EQ(3, queue.getSize()); + + EXPECT_FALSE(queue.contains(f0)); + EXPECT_TRUE(queue.contains(f1)); + EXPECT_TRUE(queue.contains(f3)); + EXPECT_TRUE(queue.contains(f4)); + EXPECT_FALSE(queue.contains(f2)); + EXPECT_FALSE(queue.contains(f5)); + EXPECT_FALSE(queue.contains(f6)); + + while(queue.peek() != UAVCAN_NULLPTR){ + queue.remove(queue.peek()); + } - queue.push(f6, tsMono(700), CanTxQueue::Persistent, flags); // Will be rejected (lowest QoS) - EXPECT_FALSE(isInQueue(queue, f6)); + EXPECT_FALSE(queue.peek()); + EXPECT_FALSE(queue.contains(f0)); + EXPECT_FALSE(queue.contains(f5)); + EXPECT_EQ(0, queue.getSize()); + EXPECT_EQ(0, pool.getNumUsedBlocks()); + EXPECT_FALSE(queue.peek()); EXPECT_FALSE(queue.topPriorityHigherOrEqual(f0)); - EXPECT_TRUE(queue.topPriorityHigherOrEqual(f2)); // Equal - EXPECT_TRUE(queue.topPriorityHigherOrEqual(f5a)); - EXPECT_EQ(4, getQueueLength(queue)); - EXPECT_EQ(4, pool.getNumUsedBlocks()); - EXPECT_EQ(5, queue.getRejectedFrameCount()); - EXPECT_TRUE(isInQueue(queue, f2)); - EXPECT_TRUE(isInQueue(queue, f3)); - EXPECT_TRUE(isInQueue(queue, f4)); - EXPECT_TRUE(isInQueue(queue, f5a)); - EXPECT_EQ(f2, queue.peek()->frame); // Check the priority /* - * Expiration - */ - clockmock.monotonic = 101; - queue.push(f0, tsMono(800), CanTxQueue::Volatile, flags); // Will replace f4 which is expired now - EXPECT_TRUE(isInQueue(queue, f0)); - EXPECT_FALSE(isInQueue(queue, f4)); - EXPECT_EQ(6, queue.getRejectedFrameCount()); - - clockmock.monotonic = 1001; - queue.push(f5, tsMono(2000), CanTxQueue::Volatile, flags); // Entire queue is expired - EXPECT_TRUE(isInQueue(queue, f5)); - EXPECT_EQ(1, getQueueLength(queue)); // Just one entry left - f5 - EXPECT_EQ(1, pool.getNumUsedBlocks()); // Make sure there is no leaks - EXPECT_EQ(10, queue.getRejectedFrameCount()); - - queue.push(f0, tsMono(1000), CanTxQueue::Persistent, flags); // This entry is already expired - EXPECT_EQ(1, getQueueLength(queue)); - EXPECT_EQ(1, pool.getNumUsedBlocks()); - EXPECT_EQ(11, queue.getRejectedFrameCount()); + * Expiration Auto Remove on Peek + */ + + queue.push(f0, tsMono(999), Qos::Persistent, flags); + queue.push(f4, tsMono(101), Qos::Persistent, flags); + + clockmock.monotonic = 102; // make f4 expire + EXPECT_TRUE(queue.contains(f0)); + EXPECT_TRUE(queue.contains(f4)); // f0 is higher priority, so will get traversed first -- f4 not yet removed + + auto peek = queue.peek(); + EXPECT_EQ(f0, peek->frame); + + queue.remove(peek); + + EXPECT_EQ(1, queue.getSize()); + EXPECT_EQ(2, pool.getNumUsedBlocks()); + + EXPECT_FALSE(queue.peek()); // f4 will be removed now that queue only contains f4 + EXPECT_FALSE(queue.contains(f4)); + + EXPECT_EQ(0, queue.getSize()); + EXPECT_EQ(0, pool.getNumUsedBlocks()); + + queue.push(f4, tsMono(98), Qos::Persistent, flags); // already expired + + EXPECT_FALSE(queue.peek()); + EXPECT_EQ(1, queue.getRejectedFrameCount()); + EXPECT_EQ(0, queue.getSize()); + EXPECT_EQ(0, pool.getNumUsedBlocks()); /* - * Removing + * Add multiple so that we reach OOM */ - queue.push(f4, tsMono(5000), CanTxQueue::Volatile, flags); - EXPECT_EQ(2, getQueueLength(queue)); - EXPECT_TRUE(isInQueue(queue, f4)); - EXPECT_EQ(f4, queue.peek()->frame); - CanTxQueue::Entry* entry = queue.peek(); - EXPECT_TRUE(entry); - queue.remove(entry); - EXPECT_FALSE(entry); + queue.push(f0, tsMono(900), Qos::Persistent, flags); + EXPECT_EQ(2, pool.getNumUsedBlocks()); + + queue.push(f1, tsMono(1000), Qos::Persistent, flags); + EXPECT_EQ(4, pool.getNumUsedBlocks()); - EXPECT_FALSE(isInQueue(queue, f4)); - EXPECT_TRUE(isInQueue(queue, f5)); + queue.push(f2, tsMono(1100), Qos::Persistent, flags); + EXPECT_EQ(6, pool.getNumUsedBlocks()); - entry = queue.peek(); - EXPECT_TRUE(entry); - queue.remove(entry); - EXPECT_FALSE(entry); + queue.push(f3, tsMono(1200), Qos::Persistent, flags); + EXPECT_EQ(8, pool.getNumUsedBlocks()); + EXPECT_TRUE(queue.contains(f3)); + + queue.push(f4, tsMono(1300), Qos::Persistent, flags); + EXPECT_EQ(8, pool.getNumUsedBlocks()); + EXPECT_FALSE(queue.contains(f4)); - EXPECT_FALSE(isInQueue(queue, f5)); + EXPECT_EQ(4, queue.getSize()); + EXPECT_EQ(8, pool.getNumUsedBlocks()); + EXPECT_FALSE(queue.contains(f4)); // OOM happened on insertion + EXPECT_EQ(2, queue.getRejectedFrameCount()); + + /* + * Remove all - cleanup + */ - EXPECT_EQ(0, getQueueLength(queue)); // Final state checks + while(queue.peek() != UAVCAN_NULLPTR){ + queue.remove(queue.peek()); + } + + EXPECT_EQ(0, queue.getSize()); EXPECT_EQ(0, pool.getNumUsedBlocks()); - EXPECT_EQ(11, queue.getRejectedFrameCount()); - EXPECT_FALSE(queue.peek()); - EXPECT_FALSE(queue.topPriorityHigherOrEqual(f0)); } diff --git a/libuavcan/test/transport/dispatcher.cpp b/libuavcan/test/transport/dispatcher.cpp index aa39a3128..00c0ac49c 100644 --- a/libuavcan/test/transport/dispatcher.cpp +++ b/libuavcan/test/transport/dispatcher.cpp @@ -281,7 +281,7 @@ TEST(Dispatcher, Transmission) ASSERT_TRUE(dispatcher.hasPublisher(123)); ASSERT_FALSE(dispatcher.hasPublisher(456)); - ASSERT_EQ(2, dispatcher.send(frame, TX_DEADLINE, tsMono(0), uavcan::CanTxQueue::Volatile, 0, 0xFF)); + ASSERT_EQ(2, dispatcher.send(frame, TX_DEADLINE, tsMono(0), uavcan::Qos::Volatile, 0, 0xFF)); /* * Validation @@ -376,7 +376,7 @@ TEST(Dispatcher, Loopback) ASSERT_TRUE(listener.last_frame == uavcan::RxFrame()); - ASSERT_LE(0, dispatcher.send(frame, tsMono(1000), tsMono(0), uavcan::CanTxQueue::Persistent, + ASSERT_LE(0, dispatcher.send(frame, tsMono(1000), tsMono(0), uavcan::Qos::Persistent, uavcan::CanIOFlagLoopback, 0xFF)); ASSERT_EQ(0, dispatcher.spin(tsMono(1000))); diff --git a/libuavcan/test/transport/transfer_sender.cpp b/libuavcan/test/transport/transfer_sender.cpp index ff27b6fe9..56eafa971 100644 --- a/libuavcan/test/transport/transfer_sender.cpp +++ b/libuavcan/test/transport/transfer_sender.cpp @@ -52,8 +52,8 @@ TEST(TransferSender, Basic) uavcan::TransferSender senders[2] = { - uavcan::TransferSender(dispatcher_tx, TYPES[0], uavcan::CanTxQueue::Volatile), - uavcan::TransferSender(dispatcher_tx, TYPES[1], uavcan::CanTxQueue::Persistent) + uavcan::TransferSender(dispatcher_tx, TYPES[0], uavcan::Qos ::Volatile), + uavcan::TransferSender(dispatcher_tx, TYPES[1], uavcan::Qos ::Persistent) }; static const std::string DATA[4] = @@ -199,7 +199,7 @@ TEST(TransferSender, Loopback) uavcan::DataTypeDescriptor desc = makeDataType(uavcan::DataTypeKindMessage, 1, "Foobar"); - uavcan::TransferSender sender(dispatcher, desc, uavcan::CanTxQueue::Volatile); + uavcan::TransferSender sender(dispatcher, desc, uavcan::Qos ::Volatile); sender.setCanIOFlags(uavcan::CanIOFlagLoopback); ASSERT_EQ(uavcan::CanIOFlagLoopback, sender.getCanIOFlags()); @@ -235,7 +235,7 @@ TEST(TransferSender, PassiveMode) uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock); uavcan::TransferSender sender(dispatcher, makeDataType(uavcan::DataTypeKindMessage, 123), - uavcan::CanTxQueue::Volatile); + uavcan::Qos ::Volatile); static const uint8_t Payload[] = {1, 2, 3, 4, 5}; diff --git a/libuavcan_drivers/linux/apps/test_multithreading.cpp b/libuavcan_drivers/linux/apps/test_multithreading.cpp index 30136ec3e..9f1228365 100644 --- a/libuavcan_drivers/linux/apps/test_multithreading.cpp +++ b/libuavcan_drivers/linux/apps/test_multithreading.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Pavel Kirienko + * Copyright (C) 2019 Theodoros Ntakouris */ #ifndef NDEBUG @@ -158,7 +159,7 @@ class VirtualCanIface : public uavcan::ICanIface, int16_t send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags) override { std::lock_guard lock(mutex_); - prioritized_tx_queue_.push(frame, tx_deadline, uavcan::CanTxQueue::Volatile, flags); + prioritized_tx_queue_.push(frame, tx_deadline, uavcan::Qos::Volatile, flags); return 1; } @@ -226,7 +227,7 @@ class VirtualCanIface : public uavcan::ICanIface, unsigned(iface_mask), e->toString().c_str()); const int res = main_node.injectTxFrame(e->frame, e->deadline, iface_mask, - uavcan::CanTxQueue::Qos(e->qos), e->flags); + uavcan::Qos(e->qos), e->flags); prioritized_tx_queue_.remove(e); if (res <= 0) { From 01ad9c62e7899ce1a57f962add81207d8f12eaac Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Tue, 29 Jan 2019 14:55:07 +0200 Subject: [PATCH 02/23] Adhere to proposed code review changes --- libuavcan/include/uavcan/driver/can.hpp | 4 +- libuavcan/include/uavcan/transport/can_io.hpp | 13 +- libuavcan/include/uavcan/util/avl_tree.hpp | 148 ++++++++---------- libuavcan/src/transport/uc_can_io.cpp | 13 +- libuavcan/test/transport/can/tx_queue.cpp | 2 +- 5 files changed, 78 insertions(+), 102 deletions(-) diff --git a/libuavcan/include/uavcan/driver/can.hpp b/libuavcan/include/uavcan/driver/can.hpp index 492a9073f..d82df5912 100644 --- a/libuavcan/include/uavcan/driver/can.hpp +++ b/libuavcan/include/uavcan/driver/can.hpp @@ -57,12 +57,12 @@ struct UAVCAN_EXPORT CanFrame return (id == rhs.id) && (dlc == rhs.dlc) && equal(data, data + dlc, rhs.data); } - bool operator <(const CanFrame & other) const + bool operator<(const CanFrame & other) const { return this->priorityLowerThan(other); } - bool operator >(const CanFrame & other) const + bool operator>(const CanFrame & other) const { return this->priorityHigherThan(other); } diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index ed6c5897e..7286d18fa 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -1,5 +1,3 @@ -#include - /* * CAN bus IO logic. * Copyright (C) 2014 Pavel Kirienko @@ -10,6 +8,7 @@ #define UAVCAN_TRANSPORT_CAN_IO_HPP_INCLUDED #include +#include #include #include #include @@ -36,7 +35,7 @@ struct UAVCAN_EXPORT CanRxFrame : public CanFrame { } #if UAVCAN_TOSTRING - std::string toString(StringRepresentation mode = StrTight) const; + std::string toString(StringRepresentation mode = StrTight) const; #endif }; @@ -91,7 +90,7 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree void safeIncrementRejectedFrames(); - AvlTree::Node* searchForNonExpiredMax(Node* n); + AvlTree::Node *searchForNonExpiredMax(Node *n); public: CanTxQueue(IPoolAllocator& allocator, ISystemClock& sysclock, std::size_t allocator_quota) @@ -105,16 +104,16 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree /* Avl Tree allocates the AvlTree::Node, while this(CanTxQueue) allocates the CanTxQueueEntry * Same logic for removal. */ void push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags); - void remove(CanTxQueueEntry* entry) override; + void remove(CanTxQueueEntry *entry) override; uint32_t getRejectedFrameCount() const { return rejected_frames_cnt_; } bool contains(const CanFrame &frame) const; /* Tries to look up rightmost Node. If the frame is expired, removes it and continues traversing */ - CanTxQueueEntry* peek(); + CanTxQueueEntry *peek(); - bool topPriorityHigherOrEqual(const CanFrame &rhs_frame); + bool topPriorityHigherOrEqual(const CanFrame &rhs_frame) const; }; struct UAVCAN_EXPORT CanIfacePerfCounters diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index fa96e2ead..1333caa1b 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -20,35 +20,15 @@ namespace uavcan { template class UAVCAN_EXPORT AvlTree : Noncopyable { -public: - struct Node { - T* data; - int h = 1; // initially added as leaf - Node *left = UAVCAN_NULLPTR; - Node *right = UAVCAN_NULLPTR; - }; -protected: - size_t len = 0; - - Node* root = UAVCAN_NULLPTR; - +private: /* * Use this only to allocate the Node struct. * `T data` should be already allocated and * provided ready for usage from the outside world - * * */ LimitedPoolAllocator allocator_; - AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota) - : allocator_(allocator, allocator_quota){} - - virtual ~AvlTree() { - // delete leafs of left subtree - first - postOrderNodeTraverseRecursively(root, [this](Node*& n){ - this->deleteNode(n); - }); - } + size_t len_; int heightOf(const Node *n) const{ if(n == UAVCAN_NULLPTR){ @@ -58,7 +38,27 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return n->h; } - Node* makeNode(T* payload) { + void inOrderTraverseRecursively(Node *n, std::function forEach) { + if (n == UAVCAN_NULLPTR) { + return; + } + + inOrderTraverseRecursively(n->left, forEach); + forEach(n->data); + inOrderTraverseRecursively(n->right, forEach); + } + + void postOrderNodeTraverseRecursively(Node *n, std::function forEach) { + if (n == UAVCAN_NULLPTR) { + return; + } + + postOrderNodeTraverseRecursively(n->left, forEach); + postOrderNodeTraverseRecursively(n->right, forEach); + forEach(n); + } + + Node *makeNode(T *payload) { void *praw = this->allocator_.allocate(sizeof(Node)); if (praw == UAVCAN_NULLPTR) { @@ -73,7 +73,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } - void deleteNode(Node*& n) { + void deleteNode(Node *&n) { if (n != UAVCAN_NULLPTR) { n->~Node(); allocator_.deallocate(n); @@ -89,26 +89,6 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return heightOf(n->left) - heightOf(n->right); } - void inOrderTraverseRecursively(Node *n, std::function forEach) { - if (n == UAVCAN_NULLPTR) { - return; - } - - inOrderTraverseRecursively(n->left, forEach); - forEach(n->data); - inOrderTraverseRecursively(n->right, forEach); - } - - void postOrderNodeTraverseRecursively(Node *n, std::function forEach) { - if (n == UAVCAN_NULLPTR) { - return; - } - - postOrderNodeTraverseRecursively(n->left, forEach); - postOrderNodeTraverseRecursively(n->right, forEach); - forEach(n); - } - Node *rotateRight(Node *y) const { Node *x = y->left; Node *T2 = x->right; @@ -136,9 +116,9 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } // If UAVCAN_NULLPTR is returned, OOM happened. - Node *insert_helper(Node *node, Node* newNode) { + Node *insert_helper(Node *node, Node *newNode) { if (node == UAVCAN_NULLPTR) { - len++; + len_++; return newNode; } @@ -175,9 +155,28 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } +protected: + struct Node { + T *data; + int h = 1; // initially added as leaf + Node *left = UAVCAN_NULLPTR; + Node *right = UAVCAN_NULLPTR; + }; + + Node *root_; + + AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota) + : allocator_(allocator, allocator_quota), root_(UAVCAN_NULLPTR), len_(0){} + + virtual ~AvlTree() { + // delete leafs first + postOrderNodeTraverseRecursively(root_, [this](Node*& n){ + this->deleteNode(n); + }); + } - /* If we've got a Node*, avoid the dereference checks and proceed to the dealloc logic */ - Node* remove_always(Node *node){ + /* If we've got a Node*, avoid the dereference data equality checks and proceed to the dealloc logic */ + Node *remove_always(Node *node){ if (node == UAVCAN_NULLPTR) { return node; } @@ -193,11 +192,11 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { *node = *temp; } - len--; + len_--; deleteNode(temp); } else { - Node* temp = node->right; - Node* next = node->left; + Node *temp = node->right; + Node *next = node->left; while (next != UAVCAN_NULLPTR){ temp = next; @@ -238,7 +237,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } - Node* remove_helper(Node *node, T* data) { + Node *remove_helper(Node *node, T *data) { if (node == UAVCAN_NULLPTR) { return node; } @@ -258,11 +257,11 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { *node = *temp; } - len--; + len_--; deleteNode(temp); } else { - Node* temp = node->right; - Node* next = node->left; + Node *temp = node->right; + Node *next = node->left; while (next != UAVCAN_NULLPTR){ temp = next; @@ -279,7 +278,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } node->h = std::max(heightOf(node->left), - heightOf(node->right)) + 1; + heightOf(node->right)) + 1; int balance = balanceOf(node); @@ -305,52 +304,31 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } public: - bool insert(T* data) { + bool insert(T *data) { Node *newNode = makeNode(data); if(newNode == UAVCAN_NULLPTR){ return false; } - root = insert_helper(root, newNode); + root_ = insert_helper(root_, newNode); return true; } - virtual void remove(T* data) { - root = remove_helper(root, data); - } - size_t getSize() const { - return root == UAVCAN_NULLPTR ? 0 : len; + return root_ == UAVCAN_NULLPTR ? 0 : len_; } void walk(std::function forEach){ - inOrderTraverseRecursively(root, forEach); + inOrderTraverseRecursively(root_, forEach); } bool isEmpty() const { return getSize() == 0; } - T* min() const { - Node *n = root; - - if (n == UAVCAN_NULLPTR) { - return UAVCAN_NULLPTR; - } - - for (;;) { - Node *next = n->left; - if (next == UAVCAN_NULLPTR) { - return n; - } - - n = next; - } - } - - T* max() const { - Node *n = root; + T *max() const { + Node *n = root_; if (n == UAVCAN_NULLPTR) { return UAVCAN_NULLPTR; @@ -366,8 +344,8 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } } - bool contains(const T &data) { - Node *n = root; + bool contains(const T &data) const{ + Node *n = root_; while (n != UAVCAN_NULLPTR) { if(*n->data > *data){ n = n->right; diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index 046abf1cc..32dcdab11 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -126,13 +126,13 @@ void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, } } -void CanTxQueue::remove(CanTxQueueEntry* entry){ +void CanTxQueue::remove(CanTxQueueEntry *entry){ if (entry == UAVCAN_NULLPTR) { return; } // Make the AvlTree remove the specific entry deleting it's Node * - this->AvlTree::remove(entry); + root_ = this->AvlTree::remove_helper(root_, entry); // Then let the entry destroy it's own contents CanTxQueueEntry::destroy(entry, this->allocator_); } @@ -147,8 +147,7 @@ CanTxQueueEntry *CanTxQueue::peek(){ return maxNode->data; } -// TODO: Isn't that NOT (topPriorityHigherOrEqual) ? -bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame &rhs_frame) { +bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame &rhs_frame) const{ auto peek_entry = peek(); if (peek_entry == UAVCAN_NULLPTR) { return false; @@ -156,7 +155,7 @@ bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame &rhs_frame) { return !rhs_frame.priorityHigherThan(peek_entry->frame); } -uavcan::AvlTree::Node* CanTxQueue::searchForNonExpiredMax(Node *n) { +uavcan::AvlTree::Node *CanTxQueue::searchForNonExpiredMax(Node *n) { if (n == UAVCAN_NULLPTR) { return UAVCAN_NULLPTR; } @@ -216,7 +215,7 @@ int CanIOManager::sendFromTxQueue(uint8_t iface_index) { } const int res = sendToIface(iface_index, entry->frame, entry->deadline, entry->flags); if (res > 0) { - tx_queues_[iface_index]->remove(entry); + root_ = tx_queues_[iface_index]->remove_helper(root_, entry); } return res; } @@ -305,7 +304,7 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton for (int i = 0; i < num_ifaces; i++) { CanTxQueue &q = *tx_queues_[i]; auto peek_entry = q.peek(); - const CanFrame* peek_frame = peek_entry == UAVCAN_NULLPTR ? UAVCAN_NULLPTR : &peek_entry->frame; + const CanFrame *peek_frame = peek_entry == UAVCAN_NULLPTR ? UAVCAN_NULLPTR : &peek_entry->frame; if (iface_mask & (1 << i)) // I hate myself so much right now. { diff --git a/libuavcan/test/transport/can/tx_queue.cpp b/libuavcan/test/transport/can/tx_queue.cpp index cffd24ee2..83472dd01 100644 --- a/libuavcan/test/transport/can/tx_queue.cpp +++ b/libuavcan/test/transport/can/tx_queue.cpp @@ -81,7 +81,7 @@ TEST(CanTxQueue, TxQueue) * Removing */ - CanTxQueueEntry* entry = queue.peek(); + CanTxQueueEntry *entry = queue.peek(); EXPECT_TRUE(entry); queue.remove(entry); From 722f80ba8cbc49e6fab70bfc867c1a25fabd4dc4 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Tue, 29 Jan 2019 15:04:26 +0200 Subject: [PATCH 03/23] Update CanIOManager.Transmission tests (fixes from queue changes -- mainly QoS from issue #195) --- libuavcan/test/transport/can/io.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libuavcan/test/transport/can/io.cpp b/libuavcan/test/transport/can/io.cpp index 11630a58d..a9fba679d 100644 --- a/libuavcan/test/transport/can/io.cpp +++ b/libuavcan/test/transport/can/io.cpp @@ -207,7 +207,7 @@ TEST(CanIOManager, Transmission) EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 999)); // In different order due to prioritization EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); EXPECT_TRUE(driver.ifaces.at(1).tx.empty()); - EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // Expired but still will be reported + EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[1])); // Overriden when pushed frames[1] (implicit peek under the hood) EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); // Calling receive() to flush the rest two frames @@ -223,7 +223,7 @@ TEST(CanIOManager, Transmission) EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); EXPECT_TRUE(driver.ifaces.at(1).tx.empty()); EXPECT_EQ(0, pool.getNumUsedBlocks()); // Make sure the memory was properly released - EXPECT_EQ(1, iomgr.getIfacePerfCounters(0).errors); // This is because of expired frame[0] + EXPECT_EQ(0, iomgr.getIfacePerfCounters(0).errors); // Expired frame[0] removed automagically on peek EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).errors); /* @@ -242,7 +242,7 @@ TEST(CanIOManager, Transmission) EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); // State checks - EXPECT_EQ(8, pool.getNumUsedBlocks()); // TX queue is full + EXPECT_EQ(10, pool.getNumUsedBlocks()); // TX queue is full EXPECT_EQ(1200, clockmock.monotonic); EXPECT_EQ(1200, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); @@ -268,19 +268,19 @@ TEST(CanIOManager, Transmission) EXPECT_EQ(1, iomgr.receive(rx_frame, tsMono(0), flags)); EXPECT_TRUE(rxFrameEquals(rx_frame, rx_frames[1], 1200, 1)); EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[2], 2222)); - EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[2], 2222)); // Iface #1, frame[1] was rejected (VOLATILE) + EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 2222)); // Volatility on QoS no longer affects priority ASSERT_EQ(0, flags); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[2])); - EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[2])); + EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); // State checks - EXPECT_EQ(0, pool.getNumUsedBlocks()); // TX queue is empty + EXPECT_EQ(2, pool.getNumUsedBlocks()); // TX queue is not empty now, contains the pending frames[2] because of QoS changes stated aboce EXPECT_EQ(1200, clockmock.monotonic); EXPECT_EQ(1200, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); EXPECT_TRUE(driver.ifaces.at(1).tx.empty()); - EXPECT_EQ(1, iomgr.getIfacePerfCounters(0).errors); - EXPECT_EQ(1, iomgr.getIfacePerfCounters(1).errors); // This is because of rejected frame[1] + EXPECT_EQ(0, iomgr.getIfacePerfCounters(0).errors); + EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).errors); /* * Error handling From f71bf9efd4fe1c6ff1d63059b22f42e7ee0f5683 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Tue, 29 Jan 2019 15:53:36 +0200 Subject: [PATCH 04/23] (have to switch to desktop pc) --- libuavcan/include/uavcan/transport/can_io.hpp | 8 +- libuavcan/include/uavcan/util/avl_tree.hpp | 47 ++++--- libuavcan/src/transport/uc_can_io.cpp | 14 +- libuavcan/test/transport/can/tx_queue.cpp | 1 - libuavcan/test/util/avl_tree.cpp | 129 ++++++++++++++++++ 5 files changed, 166 insertions(+), 33 deletions(-) create mode 100644 libuavcan/test/util/avl_tree.cpp diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index 7286d18fa..9035f06a2 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -62,17 +62,17 @@ struct CanTxQueueEntry // Not required to be packed - fits the block in any cas bool isExpired(const MonotonicTime timestamp) const { return timestamp > deadline; } - bool operator <(const CanTxQueueEntry & other) const + bool operator<(const CanTxQueueEntry & other) const { return this->frame.priorityLowerThan(other.frame); } - bool operator >(const CanTxQueueEntry & other) const + bool operator>(const CanTxQueueEntry & other) const { return this->frame.priorityHigherThan(other.frame); } - bool operator =(const CanTxQueueEntry & other) const + bool operator=(const CanTxQueueEntry & other) const { return this->frame == other.frame; } @@ -104,7 +104,7 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree /* Avl Tree allocates the AvlTree::Node, while this(CanTxQueue) allocates the CanTxQueueEntry * Same logic for removal. */ void push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags); - void remove(CanTxQueueEntry *entry) override; + void remove(CanTxQueueEntry *entry); uint32_t getRejectedFrameCount() const { return rejected_frames_cnt_; } diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index 1333caa1b..59936a1cd 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -20,7 +20,16 @@ namespace uavcan { template class UAVCAN_EXPORT AvlTree : Noncopyable { -private: +protected: + struct Node { + T *data; + int h = 1; // initially added as leaf + Node *left = UAVCAN_NULLPTR; + Node *right = UAVCAN_NULLPTR; + }; + + Node *root_; + /* * Use this only to allocate the Node struct. * `T data` should be already allocated and @@ -28,6 +37,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { * */ LimitedPoolAllocator allocator_; +private: size_t len_; int heightOf(const Node *n) const{ @@ -48,16 +58,6 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { inOrderTraverseRecursively(n->right, forEach); } - void postOrderNodeTraverseRecursively(Node *n, std::function forEach) { - if (n == UAVCAN_NULLPTR) { - return; - } - - postOrderNodeTraverseRecursively(n->left, forEach); - postOrderNodeTraverseRecursively(n->right, forEach); - forEach(n); - } - Node *makeNode(T *payload) { void *praw = this->allocator_.allocate(sizeof(Node)); @@ -156,17 +156,8 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } protected: - struct Node { - T *data; - int h = 1; // initially added as leaf - Node *left = UAVCAN_NULLPTR; - Node *right = UAVCAN_NULLPTR; - }; - - Node *root_; - AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota) - : allocator_(allocator, allocator_quota), root_(UAVCAN_NULLPTR), len_(0){} + : root_(UAVCAN_NULLPTR), allocator_(allocator, allocator_quota){} virtual ~AvlTree() { // delete leafs first @@ -175,6 +166,16 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { }); } + void postOrderNodeTraverseRecursively(Node *n, std::function forEach) { + if (n == UAVCAN_NULLPTR) { + return; + } + + postOrderNodeTraverseRecursively(n->left, forEach); + postOrderNodeTraverseRecursively(n->right, forEach); + forEach(n); + } + /* If we've got a Node*, avoid the dereference data equality checks and proceed to the dealloc logic */ Node *remove_always(Node *node){ if (node == UAVCAN_NULLPTR) { @@ -304,6 +305,10 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } public: + void remove_entry(T *data){ + root_ = remove_helper(root_, data); + } + bool insert(T *data) { Node *newNode = makeNode(data); if(newNode == UAVCAN_NULLPTR){ diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index 32dcdab11..dbed7eeb9 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -67,14 +67,14 @@ std::string CanTxQueueEntry::toString() const { */ CanTxQueue::~CanTxQueue() { // Remove all nodes & node contents of the tree without performing re-balancing steps - postOrderNodeTraverseRecursively(root, [this](Node*& n){ + postOrderNodeTraverseRecursively(this->root_, [this](Node*& n){ CanTxQueueEntry::destroy(n->data, this->allocator_); }); // Step 2: AvlTree destructor is called to remove all the Node* (automatically after) } bool CanTxQueue::contains(const CanFrame &frame) const{ - Node *n = root; + Node *n = this->root_; while (n != UAVCAN_NULLPTR) { if(frame.priorityHigherThan(n->data->frame)){ @@ -132,13 +132,13 @@ void CanTxQueue::remove(CanTxQueueEntry *entry){ } // Make the AvlTree remove the specific entry deleting it's Node * - root_ = this->AvlTree::remove_helper(root_, entry); + this->root_ = this->AvlTree::remove_helper(this->root_, entry); // Then let the entry destroy it's own contents CanTxQueueEntry::destroy(entry, this->allocator_); } CanTxQueueEntry *CanTxQueue::peek(){ - auto maxNode = searchForNonExpiredMax(root); + auto maxNode = searchForNonExpiredMax(this->root_); if(maxNode == UAVCAN_NULLPTR){ return UAVCAN_NULLPTR; @@ -164,10 +164,10 @@ uavcan::AvlTree::Node *CanTxQueue::searchForNonExpiredM if(n->data->isExpired(timestamp)){ auto expiredEntry = n->data; - root = remove_always(n); + this->root_ = remove_always(n); CanTxQueueEntry::destroy(expiredEntry, this->allocator_); - return searchForNonExpiredMax(root); + return searchForNonExpiredMax(this->root_); } while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)){ @@ -215,7 +215,7 @@ int CanIOManager::sendFromTxQueue(uint8_t iface_index) { } const int res = sendToIface(iface_index, entry->frame, entry->deadline, entry->flags); if (res > 0) { - root_ = tx_queues_[iface_index]->remove_helper(root_, entry); + this->root_ = tx_queues_[iface_index]->remove_helper(this->root_, entry); } return res; } diff --git a/libuavcan/test/transport/can/tx_queue.cpp b/libuavcan/test/transport/can/tx_queue.cpp index 83472dd01..cc1cae694 100644 --- a/libuavcan/test/transport/can/tx_queue.cpp +++ b/libuavcan/test/transport/can/tx_queue.cpp @@ -5,7 +5,6 @@ #include #include -#include #include "can.hpp" TEST(CanTxQueue, TxQueue) diff --git a/libuavcan/test/util/avl_tree.cpp b/libuavcan/test/util/avl_tree.cpp new file mode 100644 index 000000000..1de10d84c --- /dev/null +++ b/libuavcan/test/util/avl_tree.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 Theodoros Ntakouris + * */ + +#include +#include + +using uavcan::AvlTree; + +struct Entry{ + int key; + int payload; + + bool operator<(const Entry & other) const + { + return this->key < other.key; + } + + bool operator>(const Entry & other) const + { + return this->key > other.key; + } + + bool operator=(const Entry & other) const + { + return this->key == other.key; + } +}; + +/* OOM-Unsafe */ +Entry *makeEntry(PoolAllocator allocator, int key, int payload){ + void *praw = allocator.allocate(sizeof(Entry)); + + Entry *e = new (praw) Entry(); + UAVCAN_ASSERT(e); + + e->key = key; + e->payload = payload; + return e; +} + +/* Basic sanity checks */ +TEST(AvlTree, Sanity){ + uavcan::PoolAllocator<64 * 4, 64> pool; // 4 (x2) entries capacity + + AvlTree tree(pool, 4); + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(0, pool.getNumUsedBlocks()); + + auto e1 = makeEntry(1, 1); + auto e2 = makeEntry(2, 2); + auto e3 = makeEntry(3, 3); + auto e4 = makeEntry(4, 4); + + EXPECT_EQ(4, pool.getNumUsedBlocks()); + + tree.insert(e1); + EXPECT_TRUE(tree.contains(e1)); + EXPECT_EQ(e1, tree.max()); + EXPECT_EQ(1, tree.getSize()); + EXPECT_EQ(5, pool.getNumUsedBlocks()); + + tree.remove_entry(e1); + EXPECT_FALSE(tree.contains(e1)); + EXPECT_EQ(UAVCAN_NULLPTR, tree.max()); + EXPECT_EQ(0, tree.getSize()); + EXPECT_EQ(4, pool.getNumUsedBlocks()); + + // Won't break if asked to remove data that do not exist + tree.remove_entry(e1); + EXPECT_FALSE(tree.contains(e1)); + EXPECT_EQ(UAVCAN_NULLPTR, tree.max()); + EXPECT_EQ(0, tree.getSize()); + EXPECT_EQ(4, pool.getNumUsedBlocks()); + + /* + * Insert e2 - e1 - e3 - e4 + */ + + tree.insert(e2); + EXPECT_TRUE(tree.contains(e2)); + EXPECT_EQ(e2, tree.max()); + EXPECT_EQ(1, tree.getSize()); + EXPECT_EQ(5, pool.getNumUsedBlocks()); + + tree.insert(e1); + EXPECT_TRUE(tree.contains(e1)); + EXPECT_EQ(e2, tree.max()); + EXPECT_EQ(2, tree.getSize()); + EXPECT_EQ(6, pool.getNumUsedBlocks()); + + tree.insert(e3); + EXPECT_TRUE(tree.contains(e3)); + EXPECT_EQ(e3, tree.max()); + EXPECT_EQ(3, tree.getSize()); + EXPECT_EQ(7, pool.getNumUsedBlocks()); + + tree.insert(e4); + EXPECT_TRUE(tree.contains(e4)); + EXPECT_EQ(e4, tree.max()); + EXPECT_EQ(4, tree.getSize()); + EXPECT_EQ(8, pool.getNumUsedBlocks()); + + /* + * Remove e2 - e4 + */ + + tree.remove_entry(e2); + EXPECT_TRUE(tree.contains(e1)); + EXPECT_FALSE(tree.contains(e2)); + EXPECT_TRUE(tree.contains(e3)); + EXPECT_TRUE(tree.contains(e4)); + EXPECT_EQ(e4, tree.max()); + EXPECT_EQ(3, tree.getSize()); + EXPECT_EQ(7, pool.getNumUsedBlocks()); + + tree.remove_entry(e4); + EXPECT_TRUE(tree.contains(e1)); + EXPECT_TRUE(tree.contains(e3)); + EXPECT_FALSE(tree.contains(e4)); + EXPECT_EQ(e3, tree.max()); + EXPECT_EQ(2, tree.getSize()); + EXPECT_EQ(6, pool.getNumUsedBlocks()); +} + +/* Check all possible rotation / balancing cases */ +TEST(AvlTree, AllRotations){ + +} \ No newline at end of file From 188eeb84eba8fbea1c87a7303d3116cb68fc7ff3 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Tue, 29 Jan 2019 16:22:21 +0200 Subject: [PATCH 05/23] Fix some errors --- libuavcan/include/uavcan/transport/can_io.hpp | 2 +- libuavcan/src/transport/uc_can_io.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index 9035f06a2..1f9a4ed33 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -113,7 +113,7 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree /* Tries to look up rightmost Node. If the frame is expired, removes it and continues traversing */ CanTxQueueEntry *peek(); - bool topPriorityHigherOrEqual(const CanFrame &rhs_frame) const; + bool topPriorityHigherOrEqual(const CanFrame &rhs_frame); }; struct UAVCAN_EXPORT CanIfacePerfCounters diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index dbed7eeb9..7179d7897 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -147,7 +147,7 @@ CanTxQueueEntry *CanTxQueue::peek(){ return maxNode->data; } -bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame &rhs_frame) const{ +bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame &rhs_frame){ auto peek_entry = peek(); if (peek_entry == UAVCAN_NULLPTR) { return false; @@ -215,7 +215,7 @@ int CanIOManager::sendFromTxQueue(uint8_t iface_index) { } const int res = sendToIface(iface_index, entry->frame, entry->deadline, entry->flags); if (res > 0) { - this->root_ = tx_queues_[iface_index]->remove_helper(this->root_, entry); + tx_queues_[iface_index]->remove(entry); } return res; } From e743bf4229eb0c5cbcf49872c5c7549aed490a14 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Tue, 29 Jan 2019 17:44:19 +0200 Subject: [PATCH 06/23] private decls then protected then public --- libuavcan/include/uavcan/util/avl_tree.hpp | 49 +++++++++++----------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index 59936a1cd..268752839 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -20,23 +20,6 @@ namespace uavcan { template class UAVCAN_EXPORT AvlTree : Noncopyable { -protected: - struct Node { - T *data; - int h = 1; // initially added as leaf - Node *left = UAVCAN_NULLPTR; - Node *right = UAVCAN_NULLPTR; - }; - - Node *root_; - - /* - * Use this only to allocate the Node struct. - * `T data` should be already allocated and - * provided ready for usage from the outside world - * */ - LimitedPoolAllocator allocator_; - private: size_t len_; @@ -156,15 +139,21 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } protected: - AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota) - : root_(UAVCAN_NULLPTR), allocator_(allocator, allocator_quota){} + struct Node { + T *data; + int h = 1; // initially added as leaf + Node *left = UAVCAN_NULLPTR; + Node *right = UAVCAN_NULLPTR; + }; - virtual ~AvlTree() { - // delete leafs first - postOrderNodeTraverseRecursively(root_, [this](Node*& n){ - this->deleteNode(n); - }); - } + Node *root_; + + /* + * Use this only to allocate the Node struct. + * `T data` should be already allocated and + * provided ready for usage from the outside world + * */ + LimitedPoolAllocator allocator_; void postOrderNodeTraverseRecursively(Node *n, std::function forEach) { if (n == UAVCAN_NULLPTR) { @@ -305,6 +294,16 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } public: + AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota) + : len_(0), root_(UAVCAN_NULLPTR), allocator_(allocator, allocator_quota){} + + virtual ~AvlTree() { + // delete leafs first + postOrderNodeTraverseRecursively(root_, [this](Node*& n){ + this->deleteNode(n); + }); + } + void remove_entry(T *data){ root_ = remove_helper(root_, data); } From 4223aeafa7491600c392e6197cb1a83ab3820d99 Mon Sep 17 00:00:00 2001 From: Zarkopafilis Date: Wed, 30 Jan 2019 01:38:25 +0200 Subject: [PATCH 07/23] Add sanity tests for AvlTree --- libuavcan/include/uavcan/transport/can_io.hpp | 4 +- libuavcan/include/uavcan/util/avl_tree.hpp | 156 +++++++++++------- libuavcan/src/transport/uc_can_io.cpp | 20 ++- libuavcan/test/util/avl_tree.cpp | 25 ++- 4 files changed, 132 insertions(+), 73 deletions(-) diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index 1f9a4ed33..d646b811f 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -72,7 +72,7 @@ struct CanTxQueueEntry // Not required to be packed - fits the block in any cas return this->frame.priorityHigherThan(other.frame); } - bool operator=(const CanTxQueueEntry & other) const + bool operator==(const CanTxQueueEntry & other) const { return this->frame == other.frame; } @@ -88,8 +88,8 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree ISystemClock& sysclock_; uint32_t rejected_frames_cnt_; + bool linkedListContains(Node *head, const CanFrame &frame) const; void safeIncrementRejectedFrames(); - AvlTree::Node *searchForNonExpiredMax(Node *n); public: diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index 268752839..ab8c786ed 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -9,10 +9,10 @@ #include #include #include -#include -#include #include #include +#include +#include #include #include @@ -20,8 +20,19 @@ namespace uavcan { template class UAVCAN_EXPORT AvlTree : Noncopyable { +protected: + struct Node { + T *data; + int h = 1; // initially added as leaf + Node *left = UAVCAN_NULLPTR; + Node *right = UAVCAN_NULLPTR; + Node *equalKeys = UAVCAN_NULLPTR; + }; + + Node *root_; + private: - size_t len_; + size_t len_ ; int heightOf(const Node *n) const{ if(n == UAVCAN_NULLPTR){ @@ -109,9 +120,10 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { node->left = insert_helper(node->left, newNode); } else if (*newNode->data > *node->data) { node->right = insert_helper(node->right, newNode); - } else { /* Equal keys are not allowed -- change this? */ - deleteNode(newNode); - return UAVCAN_NULLPTR; + } else { + len_++; + appendToEndOf(node, newNode); + return node; } node->h = std::max(heightOf(node->left), heightOf(node->right)) + 1; @@ -138,16 +150,16 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } -protected: - struct Node { - T *data; - int h = 1; // initially added as leaf - Node *left = UAVCAN_NULLPTR; - Node *right = UAVCAN_NULLPTR; - }; - Node *root_; + void appendToEndOf(Node *head, Node *newNode){ + Node *target = head; + while(target->equalKeys != UAVCAN_NULLPTR){ + target = head->equalKeys; + } + target->equalKeys = newNode; + } +protected: /* * Use this only to allocate the Node struct. * `T data` should be already allocated and @@ -172,29 +184,36 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } // Stripped out the equality checks - if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { - Node *temp = node->left ? node->left : node->right; + if(node->equalKeys == UAVCAN_NULLPTR){ + if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { + Node *temp = node->left ? node->left : node->right; + + if (temp == UAVCAN_NULLPTR) { + temp = node; + node = UAVCAN_NULLPTR; + } else { + *node = *temp; + } - if (temp == UAVCAN_NULLPTR) { - temp = node; - node = UAVCAN_NULLPTR; + len_--; + deleteNode(temp); } else { - *node = *temp; - } + Node *minOfRight = node->right; + Node *next = minOfRight->left; - len_--; - deleteNode(temp); - } else { - Node *temp = node->right; - Node *next = node->left; + while (next != UAVCAN_NULLPTR){ + minOfRight = next->left; + next = minOfRight->left; + } - while (next != UAVCAN_NULLPTR){ - temp = next; - next = node->left; + node->data = minOfRight->data; + node->right = remove_helper(node->right, minOfRight->data); } - - node->data = temp->data; - node->right = remove_helper(node->right, temp->data); + }else{ + auto newHead = node->equalKeys; + len_--; + deleteNode(node); + return newHead; } if (node == UAVCAN_NULLPTR) { @@ -237,29 +256,36 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } else if (*data > *node->data) { node->right = remove_helper(node->right, data); } else { - if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { - Node *temp = node->left ? node->left : node->right; - - if (temp == UAVCAN_NULLPTR) { - temp = node; - node = UAVCAN_NULLPTR; + if(node->equalKeys == UAVCAN_NULLPTR){ + if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { + Node *temp = node->left ? node->left : node->right; + + if (temp == UAVCAN_NULLPTR) { + temp = node; + node = UAVCAN_NULLPTR; + } else { + *node = *temp; + } + + len_--; + deleteNode(temp); } else { - *node = *temp; - } + Node *minOfRight = node->right; + Node *next = minOfRight->left; - len_--; - deleteNode(temp); - } else { - Node *temp = node->right; - Node *next = node->left; + while (next != UAVCAN_NULLPTR){ + minOfRight = next->left; + next = minOfRight->left; + } - while (next != UAVCAN_NULLPTR){ - temp = next; - next = node->left; + node->data = minOfRight->data; + node->right = remove_helper(node->right, minOfRight->data); } - - node->data = temp->data; - node->right = remove_helper(node->right, temp->data); + }else{ + auto newHead = node->equalKeys; + len_--; + deleteNode(node); + return newHead; } } @@ -293,9 +319,23 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } + bool linkedListContains(Node *head, const T *data) const{ + Node *next = head; + while(next != UAVCAN_NULLPTR){ + if(*next->data == *data){ + return true; + } + + next = head->equalKeys; + } + return false; + } + public: - AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota) - : len_(0), root_(UAVCAN_NULLPTR), allocator_(allocator, allocator_quota){} + AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota): + root_(UAVCAN_NULLPTR), + len_(0), + allocator_(allocator, allocator_quota){} virtual ~AvlTree() { // delete leafs first @@ -348,20 +388,20 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } } - bool contains(const T &data) const{ + bool contains(const T *data) const{ Node *n = root_; while (n != UAVCAN_NULLPTR) { - if(*n->data > *data){ + if(*n->data < *data){ n = n->right; continue; } - if(*n->data < *data){ - n = n->right; + if(*n->data > *data){ + n = n->left; continue; } - return *n->data == *data; + return linkedListContains(n, data); } return false; } diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index 7179d7897..abeac898e 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -4,10 +4,10 @@ * Copyright (C) 2019 Theodoros Ntakouris */ +#include +#include #include #include -#include -#include namespace uavcan { /* @@ -87,7 +87,19 @@ bool CanTxQueue::contains(const CanFrame &frame) const{ continue; } - return frame == n->data->frame; + return linkedListContains(n, frame); + } + return false; +} + +bool CanTxQueue::linkedListContains(Node *head, const CanFrame &frame) const{ + auto *next = head; + while(next != UAVCAN_NULLPTR){ + if(next->data->frame == frame){ + return true; + } + + next = head->equalKeys; } return false; } @@ -162,7 +174,7 @@ uavcan::AvlTree::Node *CanTxQueue::searchForNonExpiredM auto timestamp = sysclock_.getMonotonic(); - if(n->data->isExpired(timestamp)){ + while(n->data->isExpired(timestamp)){ auto expiredEntry = n->data; this->root_ = remove_always(n); CanTxQueueEntry::destroy(expiredEntry, this->allocator_); diff --git a/libuavcan/test/util/avl_tree.cpp b/libuavcan/test/util/avl_tree.cpp index 1de10d84c..6ba5ba789 100644 --- a/libuavcan/test/util/avl_tree.cpp +++ b/libuavcan/test/util/avl_tree.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include using uavcan::AvlTree; @@ -21,15 +23,15 @@ struct Entry{ return this->key > other.key; } - bool operator=(const Entry & other) const + bool operator==(const Entry & other) const { return this->key == other.key; } }; /* OOM-Unsafe */ -Entry *makeEntry(PoolAllocator allocator, int key, int payload){ - void *praw = allocator.allocate(sizeof(Entry)); +inline Entry *makeEntry(uavcan::PoolAllocator<64 * 8, 64> *allocator, int key, int payload){ + void *praw = allocator->allocate(sizeof(Entry)); Entry *e = new (praw) Entry(); UAVCAN_ASSERT(e); @@ -41,16 +43,16 @@ Entry *makeEntry(PoolAllocator allocator, int key, int payload){ /* Basic sanity checks */ TEST(AvlTree, Sanity){ - uavcan::PoolAllocator<64 * 4, 64> pool; // 4 (x2) entries capacity + uavcan::PoolAllocator<64 * 8, 64> pool; // 4 (x2) entries capacity - AvlTree tree(pool, 4); + AvlTree tree(pool, 99999); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(0, pool.getNumUsedBlocks()); - auto e1 = makeEntry(1, 1); - auto e2 = makeEntry(2, 2); - auto e3 = makeEntry(3, 3); - auto e4 = makeEntry(4, 4); + auto e1 = makeEntry(&pool, 1, 1); + auto e2 = makeEntry(&pool, 2, 2); + auto e3 = makeEntry(&pool, 3, 3); + auto e4 = makeEntry(&pool, 4, 4); EXPECT_EQ(4, pool.getNumUsedBlocks()); @@ -123,6 +125,11 @@ TEST(AvlTree, Sanity){ EXPECT_EQ(6, pool.getNumUsedBlocks()); } +/* Test multiple entries with same 'key' */ +TEST(AvlTree, MultiplePerKey){ + +} + /* Check all possible rotation / balancing cases */ TEST(AvlTree, AllRotations){ From 3d16be635f200b9b9e349c940f2c142a48f86695 Mon Sep 17 00:00:00 2001 From: Zarkopafilis Date: Thu, 31 Jan 2019 02:09:46 +0200 Subject: [PATCH 08/23] Add multiple entries per key tests for AvlTree --- libuavcan/include/uavcan/util/avl_tree.hpp | 45 ++++++++++---- libuavcan/src/transport/uc_can_io.cpp | 6 +- libuavcan/test/util/avl_tree.cpp | 70 +++++++++++++++++++++- 3 files changed, 107 insertions(+), 14 deletions(-) diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index ab8c786ed..c18505d92 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -159,6 +159,36 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { target->equalKeys = newNode; } + + /* Delete the element of the linked list (memory address comparison) + * and return the new head */ + Node *deleteFromList(Node *root, T *data){ + auto current = root; + Node *prev = UAVCAN_NULLPTR; + + while(current != UAVCAN_NULLPTR){ + if(current->data == data){ + if(current == root){ + auto ret = current->equalKeys; + len_--; + deleteNode(current); + return ret; /* Return one element forward */ + }else{ + auto next = current->equalKeys; + prev->equalKeys = next; + len_--; + deleteNode(current); + return root; /* Unchanged root, non-head element was changed */ + } + } + + prev = current; + current = current->equalKeys; + } + + return root; + } + protected: /* * Use this only to allocate the Node struct. @@ -178,7 +208,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } /* If we've got a Node*, avoid the dereference data equality checks and proceed to the dealloc logic */ - Node *remove_always(Node *node){ + Node *remove_always(Node *node, T *data){ if (node == UAVCAN_NULLPTR) { return node; } @@ -210,9 +240,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { node->right = remove_helper(node->right, minOfRight->data); } }else{ - auto newHead = node->equalKeys; - len_--; - deleteNode(node); + auto newHead = deleteFromList(node, data); return newHead; } @@ -282,9 +310,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { node->right = remove_helper(node->right, minOfRight->data); } }else{ - auto newHead = node->equalKeys; - len_--; - deleteNode(node); + auto newHead = deleteFromList(node, data); return newHead; } } @@ -322,11 +348,10 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { bool linkedListContains(Node *head, const T *data) const{ Node *next = head; while(next != UAVCAN_NULLPTR){ - if(*next->data == *data){ + if(next->data == data){ /* Memory address comparison */ return true; } - - next = head->equalKeys; + next = next->equalKeys; } return false; } diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index abeac898e..bcb9bde62 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -144,7 +144,7 @@ void CanTxQueue::remove(CanTxQueueEntry *entry){ } // Make the AvlTree remove the specific entry deleting it's Node * - this->root_ = this->AvlTree::remove_helper(this->root_, entry); + this->AvlTree::remove_entry(entry); // Then let the entry destroy it's own contents CanTxQueueEntry::destroy(entry, this->allocator_); } @@ -176,7 +176,7 @@ uavcan::AvlTree::Node *CanTxQueue::searchForNonExpiredM while(n->data->isExpired(timestamp)){ auto expiredEntry = n->data; - this->root_ = remove_always(n); + this->root_ = remove_always(n, n->data); CanTxQueueEntry::destroy(expiredEntry, this->allocator_); return searchForNonExpiredMax(this->root_); @@ -184,7 +184,7 @@ uavcan::AvlTree::Node *CanTxQueue::searchForNonExpiredM while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)){ auto expiredEntry = n->data; - n->right = remove_always(n); + n->right = remove_always(n, n->data); CanTxQueueEntry::destroy(expiredEntry, this->allocator_); } diff --git a/libuavcan/test/util/avl_tree.cpp b/libuavcan/test/util/avl_tree.cpp index 6ba5ba789..4ad9f1105 100644 --- a/libuavcan/test/util/avl_tree.cpp +++ b/libuavcan/test/util/avl_tree.cpp @@ -126,8 +126,76 @@ TEST(AvlTree, Sanity){ } /* Test multiple entries with same 'key' */ -TEST(AvlTree, MultiplePerKey){ +TEST(AvlTree, MultipleEntriesPerKey){ + uavcan::PoolAllocator<64 * 8, 64> pool; // 4 (x2) entries capacity + + AvlTree tree(pool, 99999); + + auto e1 = makeEntry(&pool, 1, 1); + auto e1_1 = makeEntry(&pool, 1, 11); + auto e1_11 = makeEntry(&pool, 1, 111); + + auto e2 = makeEntry(&pool, 2, 2); + + /* + * Insert 2 entries with same key + * */ + tree.insert(e1); + + tree.insert(e1_1); + EXPECT_TRUE(tree.contains(e1)); + EXPECT_TRUE(tree.contains(e1_1)); + EXPECT_EQ(e1, tree.max()); + EXPECT_EQ(2, tree.getSize()); + EXPECT_EQ(6, pool.getNumUsedBlocks()); + + + tree.remove_entry(e1); + EXPECT_FALSE(tree.contains(e1)); + EXPECT_TRUE(tree.contains(e1_1)); + + EXPECT_EQ(e1_1, tree.max()); + EXPECT_EQ(1, tree.getSize()); + EXPECT_EQ(5, pool.getNumUsedBlocks()); + + tree.remove_entry(e1); + /* + * Insert another with higher priority and + * test again: removing in the middle and end of queue + * */ + tree.insert(e2); + + tree.insert(e1); + tree.insert(e1_1); + tree.insert(e1_11); + + EXPECT_TRUE(tree.contains(e2)); + EXPECT_TRUE(tree.contains(e1)); + EXPECT_TRUE(tree.contains(e1_1)); + EXPECT_TRUE(tree.contains(e1_11)); + + EXPECT_EQ(e2, tree.max()); + EXPECT_EQ(4, tree.getSize()); + EXPECT_EQ(8, pool.getNumUsedBlocks()); + + tree.remove_entry(e2); + tree.remove_entry(e1_1); // middle one in node with key == 1 + EXPECT_FALSE(tree.contains(e2)); + EXPECT_TRUE(tree.contains(e1)); + EXPECT_FALSE(tree.contains(e1_1)); + EXPECT_TRUE(tree.contains(e1_11)); + + EXPECT_EQ(e1, tree.max()); // peeked in the order they were inserted + EXPECT_EQ(2, tree.getSize()); + EXPECT_EQ(6, pool.getNumUsedBlocks()); + + tree.remove_entry(e1_11); // last one in queue + EXPECT_EQ(e1, tree.max()); + EXPECT_FALSE(tree.contains(e1_11)); + + EXPECT_EQ(1, tree.getSize()); + EXPECT_EQ(5, pool.getNumUsedBlocks()); } /* Check all possible rotation / balancing cases */ From ec17bb710d26dfde336362862134cbcc2a3d8a91 Mon Sep 17 00:00:00 2001 From: Zarkopafilis Date: Thu, 31 Jan 2019 15:41:24 +0200 Subject: [PATCH 09/23] Remove remove_always (does not keep rotations) --- libuavcan/include/uavcan/util/avl_tree.hpp | 67 ---------------------- libuavcan/src/transport/uc_can_io.cpp | 7 +-- 2 files changed, 2 insertions(+), 72 deletions(-) diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index c18505d92..893cdd71d 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -207,73 +207,6 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { forEach(n); } - /* If we've got a Node*, avoid the dereference data equality checks and proceed to the dealloc logic */ - Node *remove_always(Node *node, T *data){ - if (node == UAVCAN_NULLPTR) { - return node; - } - - // Stripped out the equality checks - if(node->equalKeys == UAVCAN_NULLPTR){ - if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { - Node *temp = node->left ? node->left : node->right; - - if (temp == UAVCAN_NULLPTR) { - temp = node; - node = UAVCAN_NULLPTR; - } else { - *node = *temp; - } - - len_--; - deleteNode(temp); - } else { - Node *minOfRight = node->right; - Node *next = minOfRight->left; - - while (next != UAVCAN_NULLPTR){ - minOfRight = next->left; - next = minOfRight->left; - } - - node->data = minOfRight->data; - node->right = remove_helper(node->right, minOfRight->data); - } - }else{ - auto newHead = deleteFromList(node, data); - return newHead; - } - - if (node == UAVCAN_NULLPTR) { - return node; - } - - node->h = std::max(heightOf(node->left), - heightOf(node->right)) + 1; - - int balance = balanceOf(node); - - if (balance > 1 && balanceOf(node->left) >= 0) { - return rotateRight(node); - } - - if (balance > 1 && balanceOf(node->left) < 0) { - node->left = rotateLeft(node->left); - return rotateRight(node); - } - - if (balance < -1 && balanceOf(node->right) <= 0) { - return rotateLeft(node); - } - - if (balance < -1 && balanceOf(node->right) > 0) { - node->right = rotateRight(node->right); - return rotateLeft(node); - } - - return node; - } - Node *remove_helper(Node *node, T *data) { if (node == UAVCAN_NULLPTR) { return node; diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index bcb9bde62..a27c96153 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -175,16 +175,13 @@ uavcan::AvlTree::Node *CanTxQueue::searchForNonExpiredM auto timestamp = sysclock_.getMonotonic(); while(n->data->isExpired(timestamp)){ - auto expiredEntry = n->data; - this->root_ = remove_always(n, n->data); - CanTxQueueEntry::destroy(expiredEntry, this->allocator_); - + this->remove(n->data); return searchForNonExpiredMax(this->root_); } while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)){ auto expiredEntry = n->data; - n->right = remove_always(n, n->data); + n->right = this->AvlTree::remove_helper(n, n->data); CanTxQueueEntry::destroy(expiredEntry, this->allocator_); } From 63b48c7c8e878f3ac7909610e0344a6901614bc8 Mon Sep 17 00:00:00 2001 From: Zarkopafilis Date: Thu, 31 Jan 2019 16:32:36 +0200 Subject: [PATCH 10/23] Update CanIOManager.Transmission test --- libuavcan/test/transport/can/io.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/libuavcan/test/transport/can/io.cpp b/libuavcan/test/transport/can/io.cpp index a9fba679d..513b42cf9 100644 --- a/libuavcan/test/transport/can/io.cpp +++ b/libuavcan/test/transport/can/io.cpp @@ -120,8 +120,7 @@ TEST(CanIOManager, Transmission) using uavcan::Qos; // Memory - uavcan::PoolAllocator pool; - //TODO: Fix this uavcan::PoolAllocator pool; + uavcan::PoolAllocator<40 * 64, 64> pool; // Platform interface SystemClockMock clockmock; @@ -268,7 +267,7 @@ TEST(CanIOManager, Transmission) EXPECT_EQ(1, iomgr.receive(rx_frame, tsMono(0), flags)); EXPECT_TRUE(rxFrameEquals(rx_frame, rx_frames[1], 1200, 1)); EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[2], 2222)); - EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 2222)); // Volatility on QoS no longer affects priority + EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 4444)); // Volatility on QoS no longer affects priority ASSERT_EQ(0, flags); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[2])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); @@ -307,7 +306,7 @@ TEST(CanIOManager, Transmission) EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); - ASSERT_EQ(4, pool.getNumUsedBlocks()); // Untransmitted frames will be buffered + ASSERT_EQ(6, pool.getNumUsedBlocks()); // Untransmitted frames will be buffered // Failure removed - transmission shall proceed driver.ifaces.at(0).tx_failure = false; @@ -327,7 +326,7 @@ TEST(CanIOManager, Transmission) EXPECT_EQ(1, iomgr.getIfacePerfCounters(1).frames_rx); EXPECT_EQ(6, iomgr.getIfacePerfCounters(0).frames_tx); - EXPECT_EQ(8, iomgr.getIfacePerfCounters(1).frames_tx); + EXPECT_EQ(9, iomgr.getIfacePerfCounters(1).frames_tx); } TEST(CanIOManager, Loopback) From e0d9324b430ae418f8c047eb084799441eb0d706 Mon Sep 17 00:00:00 2001 From: Zarkopafilis Date: Mon, 4 Feb 2019 02:27:16 +0200 Subject: [PATCH 11/23] Add rotation tests for AvlTree --- libuavcan/include/uavcan/util/avl_tree.hpp | 26 +- libuavcan/test/util/avl_tree.cpp | 415 ++++++++++++++++++++- 2 files changed, 427 insertions(+), 14 deletions(-) diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index 893cdd71d..eecb1d705 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -42,14 +42,14 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return n->h; } - void inOrderTraverseRecursively(Node *n, std::function forEach) { + void postOrderTraverseRecursively(Node *n, std::function forEach) { if (n == UAVCAN_NULLPTR) { return; } - inOrderTraverseRecursively(n->left, forEach); + postOrderTraverseRecursively(n->left, forEach); + postOrderTraverseRecursively(n->right, forEach); forEach(n->data); - inOrderTraverseRecursively(n->right, forEach); } Node *makeNode(T *payload) { @@ -169,9 +169,16 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { while(current != UAVCAN_NULLPTR){ if(current->data == data){ if(current == root){ - auto ret = current->equalKeys; + auto ret = current->equalKeys; // From the remove method, this should never be null + + /* Inherit subtrees */ + ret->h = current->h; + ret->left = current->left; + ret->right = current->right; + len_--; deleteNode(current); + return ret; /* Return one element forward */ }else{ auto next = current->equalKeys; @@ -232,11 +239,9 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { deleteNode(temp); } else { Node *minOfRight = node->right; - Node *next = minOfRight->left; - while (next != UAVCAN_NULLPTR){ - minOfRight = next->left; - next = minOfRight->left; + while (minOfRight->left != UAVCAN_NULLPTR){ + minOfRight = minOfRight->left; } node->data = minOfRight->data; @@ -321,10 +326,11 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return root_ == UAVCAN_NULLPTR ? 0 : len_; } - void walk(std::function forEach){ - inOrderTraverseRecursively(root_, forEach); + void walkPostOrder(std::function forEach){ + postOrderTraverseRecursively(root_, forEach); } + bool isEmpty() const { return getSize() == 0; } diff --git a/libuavcan/test/util/avl_tree.cpp b/libuavcan/test/util/avl_tree.cpp index 4ad9f1105..cf1dacfbf 100644 --- a/libuavcan/test/util/avl_tree.cpp +++ b/libuavcan/test/util/avl_tree.cpp @@ -30,7 +30,7 @@ struct Entry{ }; /* OOM-Unsafe */ -inline Entry *makeEntry(uavcan::PoolAllocator<64 * 8, 64> *allocator, int key, int payload){ +inline Entry *makeEntry(uavcan::PoolAllocator<64 * 24, 64> *allocator, int key, int payload){ void *praw = allocator->allocate(sizeof(Entry)); Entry *e = new (praw) Entry(); @@ -41,9 +41,20 @@ inline Entry *makeEntry(uavcan::PoolAllocator<64 * 8, 64> *allocator, int key, i return e; } +inline bool matchPostOrder(Entry* expected[], AvlTree *tree){ + int count = 0; + bool res = true; + tree->walkPostOrder([expected, &count, &res](Entry*& in){ + auto res_ = in == expected[count]; + res &= res_; + count++; + }); + return res; +} + /* Basic sanity checks */ TEST(AvlTree, Sanity){ - uavcan::PoolAllocator<64 * 8, 64> pool; // 4 (x2) entries capacity + uavcan::PoolAllocator<64 * 24, 64> pool; // 4 (x2) entries capacity AvlTree tree(pool, 99999); EXPECT_TRUE(tree.isEmpty()); @@ -127,7 +138,7 @@ TEST(AvlTree, Sanity){ /* Test multiple entries with same 'key' */ TEST(AvlTree, MultipleEntriesPerKey){ - uavcan::PoolAllocator<64 * 8, 64> pool; // 4 (x2) entries capacity + uavcan::PoolAllocator<64 * 24, 64> pool; // 4 (x2) entries capacity AvlTree tree(pool, 99999); @@ -198,7 +209,403 @@ TEST(AvlTree, MultipleEntriesPerKey){ EXPECT_EQ(5, pool.getNumUsedBlocks()); } -/* Check all possible rotation / balancing cases */ +/* Check all possible rotation / balancing cases + * Test cases from: https://stackoverflow.com/questions/3955680/how-to-check-if-my-avl-tree-implementation-is-correct + * */ TEST(AvlTree, AllRotations){ + uavcan::PoolAllocator<64 * 24, 64> pool; // 4 (x2) entries capacity + + AvlTree tree(pool, 99999); + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(0, pool.getNumUsedBlocks()); + + auto a = makeEntry(&pool, 1, 1); + auto b = makeEntry(&pool, 2, 2); + auto c = makeEntry(&pool, 3, 3); + auto d = makeEntry(&pool, 4, 4); + auto e = makeEntry(&pool, 5, 5); + auto f = makeEntry(&pool, 6, 6); + auto g = makeEntry(&pool, 7, 7); + auto h = makeEntry(&pool, 8, 8); + auto i = makeEntry(&pool, 9, 9); + auto j = makeEntry(&pool, 10, 10); + auto k = makeEntry(&pool, 11, 11); + auto l = makeEntry(&pool, 12, 12); + + /* + * Simple test cases for insert + * */ + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + /* + * a b + \ / \ + b == 1L ==> a c + \ + c + */ + tree.insert(a); + tree.insert(b); + tree.insert(c); + + Entry* match_1l[] = {a, c, b}; + EXPECT_TRUE(matchPostOrder(match_1l , &tree)); + + tree.remove_entry(a); + tree.remove_entry(b); + tree.remove_entry(c); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + /* + * + * c b + / / \ + b == 1R ==> a c + / + a + */ + tree.insert(c); + tree.insert(b); + tree.insert(a); + + Entry* match_1r[] = {a,c,b}; + EXPECT_TRUE(matchPostOrder(match_1r , &tree)); + + tree.remove_entry(c); + tree.remove_entry(b); + tree.remove_entry(a); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + /* + * + * a b + \ / \ + c == 2L ==> a c + / + b + */ + tree.insert(a); + tree.insert(c); + tree.insert(b); + + Entry* match_2l[] = {a,c,b}; + EXPECT_TRUE(matchPostOrder(match_2l , &tree)); + + tree.remove_entry(a); + tree.remove_entry(c); + tree.remove_entry(b); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + /* + * + * c b + / / \ + a == 2R ==> a c + \ + b + */ + + tree.insert(c); + tree.insert(a); + tree.insert(b); + + Entry* match_2r[] = {a,c,b}; + EXPECT_TRUE(matchPostOrder(match_2r , &tree)); + + tree.remove_entry(c); + tree.remove_entry(a); + tree.remove_entry(b); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + + /* + * Simple cases for deletion + */ + + /* + * b c + x \ / \ + a c == 1L ==> b d + \ + d + */ + + tree.insert(b); + tree.insert(a); + tree.insert(c); + tree.insert(d); + + Entry* match_pre_del_1l[] = {a,d,c,b}; + EXPECT_TRUE(matchPostOrder(match_pre_del_1l , &tree)); + + tree.remove_entry(a); + + Entry* match_post_del_1l[] = {b,d,c}; + EXPECT_TRUE(matchPostOrder(match_post_del_1l , &tree)); + + tree.remove_entry(b); + tree.remove_entry(c); + tree.remove_entry(d); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + + /* + * + * c b + / x / \ + b d == 1R ==> a c + / + a + */ + tree.insert(c); + tree.insert(d); + tree.insert(b); + tree.insert(a); + Entry* match_pre_del_1r[] = {a,b,d,c}; + EXPECT_TRUE(matchPostOrder(match_pre_del_1r , &tree)); + + tree.remove_entry(d); + + Entry* match_post_del_1r[] = {a,c,b}; + EXPECT_TRUE(matchPostOrder(match_post_del_1r , &tree)); + + tree.remove_entry(c); + tree.remove_entry(b); + tree.remove_entry(a); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + /* + * b c + x \ / \ + a d == 2L ==> b d + / + c + */ + tree.insert(b); + tree.insert(a); + tree.insert(d); + tree.insert(c); + + Entry* match_pre_del_2l[] = {a,c,d,b}; + EXPECT_TRUE(matchPostOrder(match_pre_del_2l , &tree)); + + tree.remove_entry(a); + + Entry* match_post_del_2l[] = {b,d,c}; + EXPECT_TRUE(matchPostOrder(match_post_del_2l , &tree)); + + tree.remove_entry(b); + tree.remove_entry(d); + tree.remove_entry(c); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + /* + * + * c b + / x / \ + a d == 2R ==> a c + \ + b + */ + tree.insert(c); + tree.insert(d); + tree.insert(a); + tree.insert(b); + + Entry* match_pre_del_2r[] = {b,a,d,c}; + EXPECT_TRUE(matchPostOrder(match_pre_del_2r , &tree)); + + tree.remove_entry(d); + + Entry* match_post_del_2r[] = {a,c,b}; + EXPECT_TRUE(matchPostOrder(match_post_del_2r , &tree)); + + tree.remove_entry(c); + tree.remove_entry(a); + tree.remove_entry(b); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + + /* + * More Complex Tests + */ + + /* + * + * c e + / \ / \ + b e == 1R ==> c f + x / \ / \ \ + a d f b d g + \ + g + */ + + tree.insert(c); + tree.insert(b); + tree.insert(e); + tree.insert(a); + tree.insert(d); + tree.insert(f); + tree.insert(g); + Entry* match_c_pre_del_1r[] = {a,b,d,g,f,e,c}; + EXPECT_TRUE(matchPostOrder(match_c_pre_del_1r , &tree)); + + tree.remove_entry(a); + + Entry* match_c_post_del_1r[] = {b,d,c,g,f,e}; + EXPECT_TRUE(matchPostOrder(match_c_post_del_1r , &tree)); + + tree.remove_entry(c); + tree.remove_entry(b); + tree.remove_entry(e); + tree.remove_entry(d); + tree.remove_entry(f); + tree.remove_entry(g); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + + /* + * + * - e - c + / \ / \ + c f == 1R ==> b e + / \ x / / \ + b d g a d f + / + a + */ + + tree.insert(e); + tree.insert(c); + tree.insert(f); + tree.insert(b); + tree.insert(d); + tree.insert(g); + tree.insert(a); + + Entry* match_c2_pre_del_1r[] = {a,b,d,c,g,f,e}; + EXPECT_TRUE(matchPostOrder(match_c2_pre_del_1r , &tree)); + + tree.remove_entry(g); + + Entry* match_c2_post_del_1r[] = {a,b,d,f,e,c}; + EXPECT_TRUE(matchPostOrder(match_c2_post_del_1r , &tree)); + + tree.remove_entry(e); + tree.remove_entry(c); + tree.remove_entry(f); + tree.remove_entry(b); + tree.remove_entry(d); + tree.remove_entry(a); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + + /* + * + * - e - —- h —- + / \ / \ + c j - e- j + / \ / \ == 2L ==> / \ / \ + a d h k c g i k + x / \ \ / \ / \ + b g i l a d f l + / + f + */ + + tree.insert(e); + tree.insert(c); + tree.insert(j); + tree.insert(a); + tree.insert(d); + tree.insert(h); + tree.insert(k); + tree.insert(b); + tree.insert(g); + tree.insert(i); + tree.insert(l); + tree.insert(f); + + Entry* match_c_pre_del_2l[] = {b,a,d,c,f,g,i,h,l,k,j,e}; + EXPECT_TRUE(matchPostOrder(match_c_pre_del_2l , &tree)); + + tree.remove_entry(b); + + Entry* match_c_post_del_2l[] = {a,d,c,f,g,e,i,l,k,j,h}; + EXPECT_TRUE(matchPostOrder(match_c_post_del_2l , &tree)); + + tree.remove_entry(e); + tree.remove_entry(c); + tree.remove_entry(j); + tree.remove_entry(a); + tree.remove_entry(d); + tree.remove_entry(h); + tree.remove_entry(k); + tree.remove_entry(g); + tree.remove_entry(i); + tree.remove_entry(l); + tree.remove_entry(f); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); + /* + * + * - h - - e - + / \ / \ + c k c - h - + / \ / \ == 2R ==> / \ / \ + b e i l b d f k + / / \ x / \ / \ + a d f j a g i l + \ + g + */ + tree.insert(h); + tree.insert(c); + tree.insert(k); + tree.insert(b); + tree.insert(e); + tree.insert(i); + tree.insert(l); + tree.insert(a); + tree.insert(d); + tree.insert(f); + tree.insert(j); + tree.insert(g); + + Entry* match_c_pre_del_2r[] = {a,b,d,g,f,e,c,j,i,l,k,h}; + EXPECT_TRUE(matchPostOrder(match_c_pre_del_2r , &tree)); + + tree.remove_entry(j); + + Entry* match_c_post_del_2r[] = {a,b,d,c,g,f,i,l,k,h,e}; + EXPECT_TRUE(matchPostOrder(match_c_post_del_2r , &tree)); + + tree.remove_entry(h); + tree.remove_entry(c); + tree.remove_entry(k); + tree.remove_entry(b); + tree.remove_entry(e); + tree.remove_entry(i); + tree.remove_entry(l); + tree.remove_entry(a); + tree.remove_entry(d); + tree.remove_entry(f); + tree.remove_entry(g); + + EXPECT_TRUE(tree.isEmpty()); + EXPECT_EQ(12, pool.getNumUsedBlocks()); } \ No newline at end of file From 6f02ef3e789c9492c1949b2b7e21ced6de957d06 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Wed, 13 Feb 2019 18:36:49 +0200 Subject: [PATCH 12/23] style and naming changes --- libuavcan/include/uavcan/transport/can_io.hpp | 29 ++-- libuavcan/include/uavcan/util/avl_tree.hpp | 140 +++++++++--------- libuavcan/src/transport/uc_can_io.cpp | 71 ++++----- 3 files changed, 121 insertions(+), 119 deletions(-) diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index d646b811f..b24d10d57 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -8,7 +8,6 @@ #define UAVCAN_TRANSPORT_CAN_IO_HPP_INCLUDED #include -#include #include #include #include @@ -49,10 +48,10 @@ struct CanTxQueueEntry // Not required to be packed - fits the block in any cas CanIOFlags flags; CanTxQueueEntry(const CanFrame& arg_frame, const MonotonicTime arg_deadline, Qos arg_qos, CanIOFlags arg_flags) - : deadline(std::move(arg_deadline)) - , frame(arg_frame) - , qos(uint8_t(arg_qos)) - , flags(arg_flags) + : deadline(arg_deadline) + , frame(arg_frame) + , qos(uint8_t(arg_qos)) + , flags(arg_flags) { UAVCAN_ASSERT((qos == Volatile) || (qos == Persistent)); IsDynamicallyAllocatable::check(); @@ -62,17 +61,17 @@ struct CanTxQueueEntry // Not required to be packed - fits the block in any cas bool isExpired(const MonotonicTime timestamp) const { return timestamp > deadline; } - bool operator<(const CanTxQueueEntry & other) const + bool operator<(const CanTxQueueEntry& other) const { return this->frame.priorityLowerThan(other.frame); } - bool operator>(const CanTxQueueEntry & other) const + bool operator>(const CanTxQueueEntry& other) const { return this->frame.priorityHigherThan(other.frame); } - bool operator==(const CanTxQueueEntry & other) const + bool operator==(const CanTxQueueEntry& other) const { return this->frame == other.frame; } @@ -88,9 +87,9 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree ISystemClock& sysclock_; uint32_t rejected_frames_cnt_; - bool linkedListContains(Node *head, const CanFrame &frame) const; + bool linkedListContains(Node* head, const CanFrame& frame) const; void safeIncrementRejectedFrames(); - AvlTree::Node *searchForNonExpiredMax(Node *n); + AvlTree::Node* searchForNonExpiredMax(Node* n); public: CanTxQueue(IPoolAllocator& allocator, ISystemClock& sysclock, std::size_t allocator_quota) @@ -103,17 +102,17 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree /* Avl Tree allocates the AvlTree::Node, while this(CanTxQueue) allocates the CanTxQueueEntry * Same logic for removal. */ - void push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags); - void remove(CanTxQueueEntry *entry); + void push(const CanFrame& frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags); + void remove(CanTxQueueEntry* entry); uint32_t getRejectedFrameCount() const { return rejected_frames_cnt_; } - bool contains(const CanFrame &frame) const; + bool contains(const CanFrame& frame) const; /* Tries to look up rightmost Node. If the frame is expired, removes it and continues traversing */ - CanTxQueueEntry *peek(); + CanTxQueueEntry* peek(); - bool topPriorityHigherOrEqual(const CanFrame &rhs_frame); + bool topPriorityHigherOrEqual(const CanFrame& rhs_frame); }; struct UAVCAN_EXPORT CanIfacePerfCounters diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index eecb1d705..3617317c5 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -16,33 +16,34 @@ #include #include -namespace uavcan { - +namespace uavcan +{ template -class UAVCAN_EXPORT AvlTree : Noncopyable { +class UAVCAN_EXPORT AvlTree : Noncopyable +{ protected: struct Node { - T *data; - int h = 1; // initially added as leaf - Node *left = UAVCAN_NULLPTR; - Node *right = UAVCAN_NULLPTR; - Node *equalKeys = UAVCAN_NULLPTR; + T* data; + uint16_t h = 1; // initially added as leaf + Node* left = UAVCAN_NULLPTR; + Node* right = UAVCAN_NULLPTR; + Node* equalKeys = UAVCAN_NULLPTR; }; - Node *root_; + Node* root_; private: size_t len_ ; - int heightOf(const Node *n) const{ - if(n == UAVCAN_NULLPTR){ + uint16_t heightOf(const Node* n) const { + if(n == UAVCAN_NULLPTR) { return 0; } return n->h; } - void postOrderTraverseRecursively(Node *n, std::function forEach) { + void postOrderTraverseRecursively(Node* n, std::function forEach) { if (n == UAVCAN_NULLPTR) { return; } @@ -52,22 +53,22 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { forEach(n->data); } - Node *makeNode(T *payload) { - void *praw = this->allocator_.allocate(sizeof(Node)); + Node* makeNode(T* payload) { + void* praw = this->allocator_.allocate(sizeof(Node)); if (praw == UAVCAN_NULLPTR) { UAVCAN_TRACE("AvlTree", " OOM -- Can't allocate Node"); return UAVCAN_NULLPTR; // Push rejected } - Node *node = new (praw) Node(); + Node* node = new (praw) Node(); UAVCAN_ASSERT(node); node->data = payload; return node; } - void deleteNode(Node *&n) { + void deleteNode(Node*& n) { if (n != UAVCAN_NULLPTR) { n->~Node(); allocator_.deallocate(n); @@ -75,7 +76,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } } - int balanceOf(Node *n) const { + uint16_t balanceOf(Node* n) const { if (n == UAVCAN_NULLPTR) { return 0; } @@ -83,9 +84,9 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return heightOf(n->left) - heightOf(n->right); } - Node *rotateRight(Node *y) const { - Node *x = y->left; - Node *T2 = x->right; + Node* rotateRight(Node* y) const { + Node* x = y->left; + Node* T2 = x->right; x->right = y; y->left = T2; @@ -96,9 +97,9 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return x; } - Node *rotateLeft(Node *x) { - Node *y = x->right; - Node *T2 = y->left; + Node* rotateLeft(Node* x) { + Node* y = x->right; + Node* T2 = y->left; y->left = x; x->right = T2; @@ -110,7 +111,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } // If UAVCAN_NULLPTR is returned, OOM happened. - Node *insert_helper(Node *node, Node *newNode) { + Node* insert_helper(Node* node, Node* newNode) { if (node == UAVCAN_NULLPTR) { len_++; return newNode; @@ -128,22 +129,22 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { node->h = std::max(heightOf(node->left), heightOf(node->right)) + 1; - int balance = balanceOf(node); + uint16_t balance = balanceOf(node); - if (balance > 1 && *newNode->data < *node->left->data) { + if (balance > 1 && (*newNode->data < *node->left->data) { return rotateRight(node); } - if (balance < -1 && *newNode->data > *node->right->data) { + if (balance < -1 && (*newNode->data > *node->right->data)) { return rotateLeft(node); } - if (balance > 1 && *newNode->data > *node->left->data) { + if (balance > 1 && (*newNode->data > *node->left->data)) { node->left = rotateLeft(node->left); return rotateRight(node); } - if (balance < -1 && *newNode->data < *node->right->data) { + if (balance < -1 && (*newNode->data < *node->right->data)) { node->right = rotateRight(node->right); return rotateLeft(node); } @@ -151,9 +152,9 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } - void appendToEndOf(Node *head, Node *newNode){ - Node *target = head; - while(target->equalKeys != UAVCAN_NULLPTR){ + void appendToEndOf(Node* head, Node* newNode) { + Node* target = head; + while(target->equalKeys != UAVCAN_NULLPTR) { target = head->equalKeys; } @@ -162,14 +163,14 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { /* Delete the element of the linked list (memory address comparison) * and return the new head */ - Node *deleteFromList(Node *root, T *data){ - auto current = root; - Node *prev = UAVCAN_NULLPTR; + Node* deleteFromList(Node* root, T* data) { + Node* current = root; + Node* prev = UAVCAN_NULLPTR; - while(current != UAVCAN_NULLPTR){ - if(current->data == data){ - if(current == root){ - auto ret = current->equalKeys; // From the remove method, this should never be null + while(current != UAVCAN_NULLPTR) { + if(current->data == data) { + if(current == root) { + Node* ret = current->equalKeys; // From the remove method, this should never be null /* Inherit subtrees */ ret->h = current->h; @@ -180,8 +181,8 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { deleteNode(current); return ret; /* Return one element forward */ - }else{ - auto next = current->equalKeys; + } else { + Node* next = current->equalKeys; prev->equalKeys = next; len_--; deleteNode(current); @@ -204,7 +205,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { * */ LimitedPoolAllocator allocator_; - void postOrderNodeTraverseRecursively(Node *n, std::function forEach) { + void postOrderNodeTraverseRecursively(Node* n, std::function forEach) { if (n == UAVCAN_NULLPTR) { return; } @@ -214,7 +215,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { forEach(n); } - Node *remove_helper(Node *node, T *data) { + Node* remove_helper(Node* node, T* data) { if (node == UAVCAN_NULLPTR) { return node; } @@ -224,7 +225,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } else if (*data > *node->data) { node->right = remove_helper(node->right, data); } else { - if(node->equalKeys == UAVCAN_NULLPTR){ + if(node->equalKeys == UAVCAN_NULLPTR) { if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { Node *temp = node->left ? node->left : node->right; @@ -240,15 +241,15 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } else { Node *minOfRight = node->right; - while (minOfRight->left != UAVCAN_NULLPTR){ + while (minOfRight->left != UAVCAN_NULLPTR) { minOfRight = minOfRight->left; } node->data = minOfRight->data; node->right = remove_helper(node->right, minOfRight->data); } - }else{ - auto newHead = deleteFromList(node, data); + } else { + Node* newHead = deleteFromList(node, data); return newHead; } } @@ -260,7 +261,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { node->h = std::max(heightOf(node->left), heightOf(node->right)) + 1; - int balance = balanceOf(node); + uint16_t balance = balanceOf(node); if (balance > 1 && balanceOf(node->left) >= 0) { return rotateRight(node); @@ -283,10 +284,10 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return node; } - bool linkedListContains(Node *head, const T *data) const{ - Node *next = head; - while(next != UAVCAN_NULLPTR){ - if(next->data == data){ /* Memory address comparison */ + bool linkedListContains(Node* head, const T* data) const { + Node* next = head; + while(next != UAVCAN_NULLPTR) { + if(next->data == data) { /* Memory address comparison */ return true; } next = next->equalKeys; @@ -295,25 +296,26 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } public: - AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota): - root_(UAVCAN_NULLPTR), - len_(0), - allocator_(allocator, allocator_quota){} + AvlTree(IPoolAllocator &allocator, std::size_t allocator_quota) + : root_(UAVCAN_NULLPTR) + , len_(0) + , allocator_(allocator, allocator_quota) + {} virtual ~AvlTree() { // delete leafs first - postOrderNodeTraverseRecursively(root_, [this](Node*& n){ + postOrderNodeTraverseRecursively(root_, [this](Node*& n) { this->deleteNode(n); }); } - void remove_entry(T *data){ + void remove_entry(T* data) { root_ = remove_helper(root_, data); } - bool insert(T *data) { - Node *newNode = makeNode(data); - if(newNode == UAVCAN_NULLPTR){ + bool insert(T* data) { + Node* newNode = makeNode(data); + if(newNode == UAVCAN_NULLPTR) { return false; } @@ -326,7 +328,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return root_ == UAVCAN_NULLPTR ? 0 : len_; } - void walkPostOrder(std::function forEach){ + void walkPostOrder(std::function forEach) { postOrderTraverseRecursively(root_, forEach); } @@ -335,15 +337,15 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { return getSize() == 0; } - T *max() const { - Node *n = root_; + T* max() const { + Node* n = root_; if (n == UAVCAN_NULLPTR) { return UAVCAN_NULLPTR; } for (;;) { - Node *next = n->right; + Node* next = n->right; if (next == UAVCAN_NULLPTR) { return n->data; } @@ -352,15 +354,15 @@ class UAVCAN_EXPORT AvlTree : Noncopyable { } } - bool contains(const T *data) const{ - Node *n = root_; + bool contains(const T* data) const { + Node* n = root_; while (n != UAVCAN_NULLPTR) { - if(*n->data < *data){ + if(*n->data < *data) { n = n->right; continue; } - if(*n->data > *data){ + if(*n->data > *data) { n = n->left; continue; } diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index a27c96153..f1bf23081 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -9,7 +9,8 @@ #include #include -namespace uavcan { +namespace uavcan +{ /* * CanRxFrame */ @@ -30,7 +31,7 @@ std::string CanRxFrame::toString(StringRepresentation mode) const { /* * CanTxQueue::Entry */ -void CanTxQueueEntry::destroy(CanTxQueueEntry *&obj, IPoolAllocator &allocator) { +void CanTxQueueEntry::destroy(CanTxQueueEntry*& obj, IPoolAllocator &allocator) { if (obj != UAVCAN_NULLPTR) { obj->~CanTxQueueEntry(); allocator.deallocate(obj); @@ -67,22 +68,22 @@ std::string CanTxQueueEntry::toString() const { */ CanTxQueue::~CanTxQueue() { // Remove all nodes & node contents of the tree without performing re-balancing steps - postOrderNodeTraverseRecursively(this->root_, [this](Node*& n){ + postOrderNodeTraverseRecursively(this->root_, [this](Node*& n) { CanTxQueueEntry::destroy(n->data, this->allocator_); }); // Step 2: AvlTree destructor is called to remove all the Node* (automatically after) } -bool CanTxQueue::contains(const CanFrame &frame) const{ - Node *n = this->root_; +bool CanTxQueue::contains(const CanFrame& frame) const{ + Node* n = this->root_; while (n != UAVCAN_NULLPTR) { - if(frame.priorityHigherThan(n->data->frame)){ + if(frame.priorityHigherThan(n->data->frame)) { n = n->right; continue; } - if(frame.priorityLowerThan(n->data->frame)){ + if(frame.priorityLowerThan(n->data->frame)) { n = n->left; continue; } @@ -92,10 +93,10 @@ bool CanTxQueue::contains(const CanFrame &frame) const{ return false; } -bool CanTxQueue::linkedListContains(Node *head, const CanFrame &frame) const{ - auto *next = head; - while(next != UAVCAN_NULLPTR){ - if(next->data->frame == frame){ +bool CanTxQueue::linkedListContains(Node* head, const CanFrame& frame) const{ + CanTxQueueEntry* next = head; + while(next != UAVCAN_NULLPTR) { + if(next->data->frame == frame) { return true; } @@ -119,16 +120,16 @@ void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, return; } - void *praw = this->allocator_.allocate(sizeof(CanTxQueueEntry)); + void* praw = this->allocator_.allocate(sizeof(CanTxQueueEntry)); if (praw == UAVCAN_NULLPTR) { UAVCAN_TRACE("CanTxQueue", "Push rejected: OOM (CanTxQueueEntry)"); safeIncrementRejectedFrames(); return; } - CanTxQueueEntry *entry = new(praw) CanTxQueueEntry(frame, tx_deadline, qos, flags); + CanTxQueueEntry* entry = new(praw) CanTxQueueEntry(frame, tx_deadline, qos, flags); UAVCAN_ASSERT(entry); - auto result = AvlTree::insert(entry); + bool result = AvlTree::insert(entry); if (!result) { /* AVL Tree could not allocate a new node */ @@ -138,7 +139,7 @@ void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, } } -void CanTxQueue::remove(CanTxQueueEntry *entry){ +void CanTxQueue::remove(CanTxQueueEntry* entry) { if (entry == UAVCAN_NULLPTR) { return; } @@ -149,43 +150,43 @@ void CanTxQueue::remove(CanTxQueueEntry *entry){ CanTxQueueEntry::destroy(entry, this->allocator_); } -CanTxQueueEntry *CanTxQueue::peek(){ - auto maxNode = searchForNonExpiredMax(this->root_); +CanTxQueueEntry* CanTxQueue::peek() { + Node* maxNode = searchForNonExpiredMax(this->root_); - if(maxNode == UAVCAN_NULLPTR){ + if(maxNode == UAVCAN_NULLPTR) { return UAVCAN_NULLPTR; } return maxNode->data; } -bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame &rhs_frame){ - auto peek_entry = peek(); +bool CanTxQueue::topPriorityHigherOrEqual(const CanFrame& rhs_frame) { + CanTxQueueEntry* peek_entry = peek(); if (peek_entry == UAVCAN_NULLPTR) { return false; } return !rhs_frame.priorityHigherThan(peek_entry->frame); } -uavcan::AvlTree::Node *CanTxQueue::searchForNonExpiredMax(Node *n) { +uavcan::AvlTree::Node* CanTxQueue::searchForNonExpiredMax(Node* n) { if (n == UAVCAN_NULLPTR) { return UAVCAN_NULLPTR; } - auto timestamp = sysclock_.getMonotonic(); + const MonotonicTime timestamp = sysclock_.getMonotonic(); - while(n->data->isExpired(timestamp)){ + while(n->data->isExpired(timestamp)) { this->remove(n->data); return searchForNonExpiredMax(this->root_); } - while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)){ - auto expiredEntry = n->data; - n->right = this->AvlTree::remove_helper(n, n->data); + while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)) { + CanTxQueueEntry* expiredEntry = n->data; + n->right = this->AvlTree::remove_node(n, n->data); CanTxQueueEntry::destroy(expiredEntry, this->allocator_); } - auto r = searchForNonExpiredMax(n->right); + Node* r = searchForNonExpiredMax(n->right); if (r != UAVCAN_NULLPTR) { return r; @@ -198,7 +199,7 @@ uavcan::AvlTree::Node *CanTxQueue::searchForNonExpiredM * CanIOManager */ int -CanIOManager::sendToIface(uint8_t iface_index, const CanFrame &frame, MonotonicTime tx_deadline, CanIOFlags flags) { +CanIOManager::sendToIface(uint8_t iface_index, const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags) { UAVCAN_ASSERT(iface_index < MaxCanIfaces); ICanIface *const iface = driver_.getIface(iface_index); if (iface == UAVCAN_NULLPTR) { @@ -218,7 +219,7 @@ CanIOManager::sendToIface(uint8_t iface_index, const CanFrame &frame, MonotonicT int CanIOManager::sendFromTxQueue(uint8_t iface_index) { UAVCAN_ASSERT(iface_index < MaxCanIfaces); - CanTxQueueEntry *entry = tx_queues_[iface_index]->peek(); + CanTxQueueEntry* entry = tx_queues_[iface_index]->peek(); if (entry == UAVCAN_NULLPTR) { return 0; } @@ -309,18 +310,18 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton // Building the list of next pending frames per iface. // The driver will give them a scrutinizing look before deciding whether he wants to accept them. // TODO: What does this mean? can we optimize further before passing them to the driver? - const CanFrame *pending_tx[MaxCanIfaces] = {}; + const CanFrame* pending_tx[MaxCanIfaces] = {}; for (int i = 0; i < num_ifaces; i++) { CanTxQueue &q = *tx_queues_[i]; - auto peek_entry = q.peek(); + CanTxQueueEntry* peek_entry = q.peek(); const CanFrame *peek_frame = peek_entry == UAVCAN_NULLPTR ? UAVCAN_NULLPTR : &peek_entry->frame; if (iface_mask & (1 << i)) // I hate myself so much right now. { - auto hasPriority = false; + bool hasPriority = false; // This may seem duplicate of topPriorityHigherOrEqual but we want to avoid traversing the queue again - if(peek_entry != UAVCAN_NULLPTR){ + if(peek_entry != UAVCAN_NULLPTR) { hasPriority = !frame.priorityHigherThan(*peek_frame); } @@ -387,10 +388,10 @@ int CanIOManager::receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline masks.write = makePendingTxMask(); masks.read = uint8_t((1 << num_ifaces) - 1); { - const CanFrame *pending_tx[MaxCanIfaces] = {}; + const CanFrame* pending_tx[MaxCanIfaces] = {}; for (int i = 0; i < num_ifaces; i++) // Dear compiler, kindly unroll this. Thanks. { - auto entry = tx_queues_[i]->peek(); + CanTxQueueEntry* entry = tx_queues_[i]->peek(); pending_tx[i] = (entry == UAVCAN_NULLPTR) ? UAVCAN_NULLPTR : &entry->frame; } From 36701bcba1e994c4c75a714b76774f35e2cfa996 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Wed, 20 Feb 2019 16:16:21 +0200 Subject: [PATCH 13/23] Remove heap allocs, adhere to suggested changes --- .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 602 ++++++++++++++++++ .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 602 ++++++++++++++++++ libuavcan/include/uavcan/transport/can_io.hpp | 3 + libuavcan/include/uavcan/util/avl_tree.hpp | 63 +- libuavcan/src/transport/uc_can_io.cpp | 16 +- 5 files changed, 1256 insertions(+), 30 deletions(-) create mode 100644 CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp create mode 100644 cmake-build-debug/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp diff --git a/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp b/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp new file mode 100644 index 000000000..b728b6329 --- /dev/null +++ b/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp @@ -0,0 +1,602 @@ +/* This source file must have a .cpp extension so that all C++ compilers + recognize the extension without flags. Borland does not know .cxx for + example. */ +#ifndef __cplusplus +# error "A C compiler has been selected for C++." +#endif + + +/* Version number components: V=Version, R=Revision, P=Patch + Version date components: YYYY=Year, MM=Month, DD=Day */ + +#if defined(__COMO__) +# define COMPILER_ID "Comeau" + /* __COMO_VERSION__ = VRR */ +# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) +# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) + +#elif defined(__INTEL_COMPILER) || defined(__ICC) +# define COMPILER_ID "Intel" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif + /* __INTEL_COMPILER = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) +# if defined(__INTEL_COMPILER_UPDATE) +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) +# else +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) +# endif +# if defined(__INTEL_COMPILER_BUILD_DATE) + /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ +# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) +# endif +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__PATHCC__) +# define COMPILER_ID "PathScale" +# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) +# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) +# if defined(__PATHCC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) +# endif + +#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) +# define COMPILER_ID "Embarcadero" +# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_CC) +# define COMPILER_ID "SunPro" +# if __SUNPRO_CC >= 0x5100 + /* __SUNPRO_CC = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# endif + +#elif defined(__HP_aCC) +# define COMPILER_ID "HP" + /* __HP_aCC = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) + +#elif defined(__DECCXX) +# define COMPILER_ID "Compaq" + /* __DECCXX_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) + +#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" +# if defined(__ibmxl__) +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) +# else + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) +# endif + + +#elif defined(__ibmxl__) || (defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800) +# define COMPILER_ID "XL" +# if defined(__ibmxl__) +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) +# else + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) +# endif + + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 +# define COMPILER_ID "VisualAge" +# if defined(__ibmxl__) +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) +# else + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) +# endif + + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version) +# define COMPILER_ID "Fujitsu" + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__GNUC__) || defined(__GNUG__) +# define COMPILER_ID "GNU" +# if defined(__GNUC__) +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# else +# define COMPILER_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" +#if defined(__VISUALDSPVERSION__) + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + +#elif defined(__ARMCC_VERSION) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION) +# define COMPILER_ID "MIPSpro" +# if defined(_SGI_COMPILER_VERSION) + /* _SGI_COMPILER_VERSION = VRP */ +# define COMPILER_VERSION_MAJOR DEC(_SGI_COMPILER_VERSION/100) +# define COMPILER_VERSION_MINOR DEC(_SGI_COMPILER_VERSION/10 % 10) +# define COMPILER_VERSION_PATCH DEC(_SGI_COMPILER_VERSION % 10) +# else + /* _COMPILER_VERSION = VRP */ +# define COMPILER_VERSION_MAJOR DEC(_COMPILER_VERSION/100) +# define COMPILER_VERSION_MINOR DEC(_COMPILER_VERSION/10 % 10) +# define COMPILER_VERSION_PATCH DEC(_COMPILER_VERSION % 10) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__sgi) +# define COMPILER_ID "MIPSpro" + +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(__CRAYXE) || defined(__CRAYXC) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__sgi) || defined(__sgi__) || defined(_SGI) +# define PLATFORM_ID "IRIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number components. */ +#ifdef COMPILER_VERSION_MAJOR +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + + +#if defined(_MSC_VER) && defined(_MSVC_LANG) +#define CXX_STD _MSVC_LANG +#else +#define CXX_STD __cplusplus +#endif + +const char* info_language_dialect_default = "INFO" ":" "dialect_default[" +#if CXX_STD > 201703L + "20" +#elif CXX_STD >= 201703L + "17" +#elif CXX_STD >= 201402L + "14" +#elif CXX_STD >= 201103L + "11" +#else + "98" +#endif +"]"; + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(__CRAYXE) || defined(__CRAYXC) + require += info_cray[argc]; +#endif + require += info_language_dialect_default[argc]; + (void)argv; + return require; +} diff --git a/cmake-build-debug/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp b/cmake-build-debug/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp new file mode 100644 index 000000000..b728b6329 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp @@ -0,0 +1,602 @@ +/* This source file must have a .cpp extension so that all C++ compilers + recognize the extension without flags. Borland does not know .cxx for + example. */ +#ifndef __cplusplus +# error "A C compiler has been selected for C++." +#endif + + +/* Version number components: V=Version, R=Revision, P=Patch + Version date components: YYYY=Year, MM=Month, DD=Day */ + +#if defined(__COMO__) +# define COMPILER_ID "Comeau" + /* __COMO_VERSION__ = VRR */ +# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) +# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) + +#elif defined(__INTEL_COMPILER) || defined(__ICC) +# define COMPILER_ID "Intel" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif + /* __INTEL_COMPILER = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) +# if defined(__INTEL_COMPILER_UPDATE) +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) +# else +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) +# endif +# if defined(__INTEL_COMPILER_BUILD_DATE) + /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ +# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) +# endif +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__PATHCC__) +# define COMPILER_ID "PathScale" +# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) +# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) +# if defined(__PATHCC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) +# endif + +#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) +# define COMPILER_ID "Embarcadero" +# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_CC) +# define COMPILER_ID "SunPro" +# if __SUNPRO_CC >= 0x5100 + /* __SUNPRO_CC = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# endif + +#elif defined(__HP_aCC) +# define COMPILER_ID "HP" + /* __HP_aCC = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) + +#elif defined(__DECCXX) +# define COMPILER_ID "Compaq" + /* __DECCXX_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) + +#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" +# if defined(__ibmxl__) +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) +# else + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) +# endif + + +#elif defined(__ibmxl__) || (defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800) +# define COMPILER_ID "XL" +# if defined(__ibmxl__) +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) +# else + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) +# endif + + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 +# define COMPILER_ID "VisualAge" +# if defined(__ibmxl__) +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) +# else + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) +# endif + + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version) +# define COMPILER_ID "Fujitsu" + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__GNUC__) || defined(__GNUG__) +# define COMPILER_ID "GNU" +# if defined(__GNUC__) +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# else +# define COMPILER_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" +#if defined(__VISUALDSPVERSION__) + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + +#elif defined(__ARMCC_VERSION) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION) +# define COMPILER_ID "MIPSpro" +# if defined(_SGI_COMPILER_VERSION) + /* _SGI_COMPILER_VERSION = VRP */ +# define COMPILER_VERSION_MAJOR DEC(_SGI_COMPILER_VERSION/100) +# define COMPILER_VERSION_MINOR DEC(_SGI_COMPILER_VERSION/10 % 10) +# define COMPILER_VERSION_PATCH DEC(_SGI_COMPILER_VERSION % 10) +# else + /* _COMPILER_VERSION = VRP */ +# define COMPILER_VERSION_MAJOR DEC(_COMPILER_VERSION/100) +# define COMPILER_VERSION_MINOR DEC(_COMPILER_VERSION/10 % 10) +# define COMPILER_VERSION_PATCH DEC(_COMPILER_VERSION % 10) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__sgi) +# define COMPILER_ID "MIPSpro" + +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(__CRAYXE) || defined(__CRAYXC) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__sgi) || defined(__sgi__) || defined(_SGI) +# define PLATFORM_ID "IRIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number components. */ +#ifdef COMPILER_VERSION_MAJOR +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + + +#if defined(_MSC_VER) && defined(_MSVC_LANG) +#define CXX_STD _MSVC_LANG +#else +#define CXX_STD __cplusplus +#endif + +const char* info_language_dialect_default = "INFO" ":" "dialect_default[" +#if CXX_STD > 201703L + "20" +#elif CXX_STD >= 201703L + "17" +#elif CXX_STD >= 201402L + "14" +#elif CXX_STD >= 201103L + "11" +#else + "98" +#endif +"]"; + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(__CRAYXE) || defined(__CRAYXC) + require += info_cray[argc]; +#endif + require += info_language_dialect_default[argc]; + (void)argv; + return require; +} diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index b24d10d57..8850646b8 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -83,6 +83,9 @@ struct CanTxQueueEntry // Not required to be packed - fits the block in any cas class UAVCAN_EXPORT CanTxQueue : public AvlTree { +private: + void postOrderTraverseEntryCleanup(Node* n); + protected: ISystemClock& sysclock_; uint32_t rejected_frames_cnt_; diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index 3617317c5..c1d5429cb 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -24,7 +24,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable protected: struct Node { T* data; - uint16_t h = 1; // initially added as leaf + int16_t h = 1; // initially added as leaf Node* left = UAVCAN_NULLPTR; Node* right = UAVCAN_NULLPTR; Node* equalKeys = UAVCAN_NULLPTR; @@ -35,7 +35,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable private: size_t len_ ; - uint16_t heightOf(const Node* n) const { + int16_t heightOf(const Node* n) const { if(n == UAVCAN_NULLPTR) { return 0; } @@ -76,12 +76,16 @@ class UAVCAN_EXPORT AvlTree : Noncopyable } } - uint16_t balanceOf(Node* n) const { + int16_t balanceOf(Node* n) const { if (n == UAVCAN_NULLPTR) { return 0; } - return heightOf(n->left) - heightOf(n->right); + return static_cast(heightOf(n->left) - heightOf(n->right)); + } + + int16_t maxOf(int16_t a, int16_t b) const { + return static_cast(a > b ? a : b); } Node* rotateRight(Node* y) const { @@ -91,8 +95,8 @@ class UAVCAN_EXPORT AvlTree : Noncopyable x->right = y; y->left = T2; - y->h = std::max(heightOf(y->left), heightOf(y->right)) + 1; - x->h = std::max(heightOf(x->left), heightOf(x->right)) + 1; + y->h = static_cast(maxOf(heightOf(y->left), heightOf(y->right)) + 1); + x->h = static_cast(maxOf(heightOf(x->left), heightOf(x->right)) + 1); return x; } @@ -104,34 +108,34 @@ class UAVCAN_EXPORT AvlTree : Noncopyable y->left = x; x->right = T2; - x->h = std::max(heightOf(x->left), heightOf(x->right)) + 1; - y->h = std::max(heightOf(y->left), heightOf(y->right)) + 1; + x->h = static_cast(maxOf(heightOf(x->left), heightOf(x->right)) + 1); + y->h = static_cast(maxOf(heightOf(y->left), heightOf(y->right)) + 1); return y; } // If UAVCAN_NULLPTR is returned, OOM happened. - Node* insert_helper(Node* node, Node* newNode) { + Node* insert_node(Node* node, Node* newNode) { if (node == UAVCAN_NULLPTR) { len_++; return newNode; } if (*newNode->data < *node->data) { - node->left = insert_helper(node->left, newNode); + node->left = insert_node(node->left, newNode); } else if (*newNode->data > *node->data) { - node->right = insert_helper(node->right, newNode); + node->right = insert_node(node->right, newNode); } else { len_++; appendToEndOf(node, newNode); return node; } - node->h = std::max(heightOf(node->left), heightOf(node->right)) + 1; + node->h = static_cast(maxOf(heightOf(node->left), heightOf(node->right)) + 1); - uint16_t balance = balanceOf(node); + int16_t balance = balanceOf(node); - if (balance > 1 && (*newNode->data < *node->left->data) { + if (balance > 1 && (*newNode->data < *node->left->data)) { return rotateRight(node); } @@ -197,6 +201,16 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return root; } + void postOrderTraverseNodeCleanup(Node* n) { + if (n == UAVCAN_NULLPTR) { + return; + } + + postOrderTraverseNodeCleanup(n->left); + postOrderTraverseNodeCleanup(n->right); + this->deleteNode(n); + } + protected: /* * Use this only to allocate the Node struct. @@ -215,15 +229,15 @@ class UAVCAN_EXPORT AvlTree : Noncopyable forEach(n); } - Node* remove_helper(Node* node, T* data) { + Node* remove_node(Node* node, T* data) { if (node == UAVCAN_NULLPTR) { return node; } if (*data < *node->data) { - node->left = remove_helper(node->left, data); + node->left = remove_node(node->left, data); } else if (*data > *node->data) { - node->right = remove_helper(node->right, data); + node->right = remove_node(node->right, data); } else { if(node->equalKeys == UAVCAN_NULLPTR) { if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { @@ -246,7 +260,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable } node->data = minOfRight->data; - node->right = remove_helper(node->right, minOfRight->data); + node->right = remove_node(node->right, minOfRight->data); } } else { Node* newHead = deleteFromList(node, data); @@ -258,10 +272,9 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return node; } - node->h = std::max(heightOf(node->left), - heightOf(node->right)) + 1; + node->h = static_cast(maxOf(heightOf(node->left), heightOf(node->right)) + 1); - uint16_t balance = balanceOf(node); + int16_t balance = balanceOf(node); if (balance > 1 && balanceOf(node->left) >= 0) { return rotateRight(node); @@ -304,13 +317,11 @@ class UAVCAN_EXPORT AvlTree : Noncopyable virtual ~AvlTree() { // delete leafs first - postOrderNodeTraverseRecursively(root_, [this](Node*& n) { - this->deleteNode(n); - }); + postOrderTraverseNodeCleanup(this->root_); } void remove_entry(T* data) { - root_ = remove_helper(root_, data); + root_ = remove_node(root_, data); } bool insert(T* data) { @@ -319,7 +330,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return false; } - root_ = insert_helper(root_, newNode); + root_ = insert_node(root_, newNode); return true; } diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index f1bf23081..07c6b7c1a 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -68,12 +68,20 @@ std::string CanTxQueueEntry::toString() const { */ CanTxQueue::~CanTxQueue() { // Remove all nodes & node contents of the tree without performing re-balancing steps - postOrderNodeTraverseRecursively(this->root_, [this](Node*& n) { - CanTxQueueEntry::destroy(n->data, this->allocator_); - }); + postOrderTraverseEntryCleanup(this->root_); // Step 2: AvlTree destructor is called to remove all the Node* (automatically after) } +void CanTxQueue::postOrderTraverseEntryCleanup(Node* n) { + if (n == UAVCAN_NULLPTR) { + return; + } + + postOrderTraverseEntryCleanup(n->left); + postOrderTraverseEntryCleanup(n->right); + CanTxQueueEntry::destroy(n->data, this->allocator_); +} + bool CanTxQueue::contains(const CanFrame& frame) const{ Node* n = this->root_; @@ -94,7 +102,7 @@ bool CanTxQueue::contains(const CanFrame& frame) const{ } bool CanTxQueue::linkedListContains(Node* head, const CanFrame& frame) const{ - CanTxQueueEntry* next = head; + Node* next = head; while(next != UAVCAN_NULLPTR) { if(next->data->frame == frame) { return true; From 1a0815513e9dd8120b8792d6e84c3eabdb0fe437 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Fri, 22 Feb 2019 15:10:13 +0200 Subject: [PATCH 14/23] Fix the unconditional for loop, styling & formatting --- .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 602 ------------------ .../CompilerIdCXX/CMakeCXXCompilerId.cpp | 602 ------------------ .../include/uavcan/node/generic_publisher.hpp | 1 - libuavcan/include/uavcan/transport/can_io.hpp | 1 - libuavcan/include/uavcan/util/avl_tree.hpp | 96 ++- libuavcan/src/transport/uc_can_io.cpp | 59 +- libuavcan/test/util/avl_tree.cpp | 39 +- 7 files changed, 95 insertions(+), 1305 deletions(-) delete mode 100644 CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp delete mode 100644 cmake-build-debug/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp diff --git a/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp b/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp deleted file mode 100644 index b728b6329..000000000 --- a/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +++ /dev/null @@ -1,602 +0,0 @@ -/* This source file must have a .cpp extension so that all C++ compilers - recognize the extension without flags. Borland does not know .cxx for - example. */ -#ifndef __cplusplus -# error "A C compiler has been selected for C++." -#endif - - -/* Version number components: V=Version, R=Revision, P=Patch - Version date components: YYYY=Year, MM=Month, DD=Day */ - -#if defined(__COMO__) -# define COMPILER_ID "Comeau" - /* __COMO_VERSION__ = VRR */ -# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) -# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) - -#elif defined(__INTEL_COMPILER) || defined(__ICC) -# define COMPILER_ID "Intel" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif - /* __INTEL_COMPILER = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) -# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) -# if defined(__INTEL_COMPILER_UPDATE) -# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) -# else -# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) -# endif -# if defined(__INTEL_COMPILER_BUILD_DATE) - /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ -# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) -# endif -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif - -#elif defined(__PATHCC__) -# define COMPILER_ID "PathScale" -# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) -# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) -# if defined(__PATHCC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) -# endif - -#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) -# define COMPILER_ID "Embarcadero" -# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) -# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) -# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) - -#elif defined(__BORLANDC__) -# define COMPILER_ID "Borland" - /* __BORLANDC__ = 0xVRR */ -# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) -# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) - -#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 -# define COMPILER_ID "Watcom" - /* __WATCOMC__ = VVRR */ -# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) -# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) -# if (__WATCOMC__ % 10) > 0 -# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) -# endif - -#elif defined(__WATCOMC__) -# define COMPILER_ID "OpenWatcom" - /* __WATCOMC__ = VVRP + 1100 */ -# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) -# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) -# if (__WATCOMC__ % 10) > 0 -# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) -# endif - -#elif defined(__SUNPRO_CC) -# define COMPILER_ID "SunPro" -# if __SUNPRO_CC >= 0x5100 - /* __SUNPRO_CC = 0xVRRP */ -# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) -# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) -# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) -# else - /* __SUNPRO_CC = 0xVRP */ -# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) -# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) -# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) -# endif - -#elif defined(__HP_aCC) -# define COMPILER_ID "HP" - /* __HP_aCC = VVRRPP */ -# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) -# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) -# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) - -#elif defined(__DECCXX) -# define COMPILER_ID "Compaq" - /* __DECCXX_VER = VVRRTPPPP */ -# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) -# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) -# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) - -#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) -# define COMPILER_ID "zOS" -# if defined(__ibmxl__) -# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) -# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) -# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) -# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) -# else - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) -# endif - - -#elif defined(__ibmxl__) || (defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800) -# define COMPILER_ID "XL" -# if defined(__ibmxl__) -# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) -# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) -# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) -# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) -# else - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) -# endif - - -#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 -# define COMPILER_ID "VisualAge" -# if defined(__ibmxl__) -# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) -# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) -# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) -# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) -# else - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) -# endif - - -#elif defined(__PGI) -# define COMPILER_ID "PGI" -# define COMPILER_VERSION_MAJOR DEC(__PGIC__) -# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) -# if defined(__PGIC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) -# endif - -#elif defined(_CRAYC) -# define COMPILER_ID "Cray" -# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) -# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) - -#elif defined(__TI_COMPILER_VERSION__) -# define COMPILER_ID "TI" - /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ -# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) -# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) -# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) - -#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version) -# define COMPILER_ID "Fujitsu" - -#elif defined(__SCO_VERSION__) -# define COMPILER_ID "SCO" - -#elif defined(__clang__) && defined(__apple_build_version__) -# define COMPILER_ID "AppleClang" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# define COMPILER_VERSION_MAJOR DEC(__clang_major__) -# define COMPILER_VERSION_MINOR DEC(__clang_minor__) -# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif -# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) - -#elif defined(__clang__) -# define COMPILER_ID "Clang" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# define COMPILER_VERSION_MAJOR DEC(__clang_major__) -# define COMPILER_VERSION_MINOR DEC(__clang_minor__) -# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif - -#elif defined(__GNUC__) || defined(__GNUG__) -# define COMPILER_ID "GNU" -# if defined(__GNUC__) -# define COMPILER_VERSION_MAJOR DEC(__GNUC__) -# else -# define COMPILER_VERSION_MAJOR DEC(__GNUG__) -# endif -# if defined(__GNUC_MINOR__) -# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) -# endif -# if defined(__GNUC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) -# endif - -#elif defined(_MSC_VER) -# define COMPILER_ID "MSVC" - /* _MSC_VER = VVRR */ -# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) -# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) -# if defined(_MSC_FULL_VER) -# if _MSC_VER >= 1400 - /* _MSC_FULL_VER = VVRRPPPPP */ -# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) -# else - /* _MSC_FULL_VER = VVRRPPPP */ -# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) -# endif -# endif -# if defined(_MSC_BUILD) -# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) -# endif - -#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) -# define COMPILER_ID "ADSP" -#if defined(__VISUALDSPVERSION__) - /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ -# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) -# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) -# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) -#endif - -#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) -# define COMPILER_ID "IAR" -# if defined(__VER__) -# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) -# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) -# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) -# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) -# endif - -#elif defined(__ARMCC_VERSION) -# define COMPILER_ID "ARMCC" -#if __ARMCC_VERSION >= 1000000 - /* __ARMCC_VERSION = VRRPPPP */ - # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) - # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) - # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) -#else - /* __ARMCC_VERSION = VRPPPP */ - # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) - # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) - # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) -#endif - - -#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION) -# define COMPILER_ID "MIPSpro" -# if defined(_SGI_COMPILER_VERSION) - /* _SGI_COMPILER_VERSION = VRP */ -# define COMPILER_VERSION_MAJOR DEC(_SGI_COMPILER_VERSION/100) -# define COMPILER_VERSION_MINOR DEC(_SGI_COMPILER_VERSION/10 % 10) -# define COMPILER_VERSION_PATCH DEC(_SGI_COMPILER_VERSION % 10) -# else - /* _COMPILER_VERSION = VRP */ -# define COMPILER_VERSION_MAJOR DEC(_COMPILER_VERSION/100) -# define COMPILER_VERSION_MINOR DEC(_COMPILER_VERSION/10 % 10) -# define COMPILER_VERSION_PATCH DEC(_COMPILER_VERSION % 10) -# endif - - -/* These compilers are either not known or too old to define an - identification macro. Try to identify the platform and guess that - it is the native compiler. */ -#elif defined(__sgi) -# define COMPILER_ID "MIPSpro" - -#elif defined(__hpux) || defined(__hpua) -# define COMPILER_ID "HP" - -#else /* unknown compiler */ -# define COMPILER_ID "" -#endif - -/* Construct the string literal in pieces to prevent the source from - getting matched. Store it in a pointer rather than an array - because some compilers will just produce instructions to fill the - array rather than assigning a pointer to a static array. */ -char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; -#ifdef SIMULATE_ID -char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; -#endif - -#ifdef __QNXNTO__ -char const* qnxnto = "INFO" ":" "qnxnto[]"; -#endif - -#if defined(__CRAYXE) || defined(__CRAYXC) -char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; -#endif - -#define STRINGIFY_HELPER(X) #X -#define STRINGIFY(X) STRINGIFY_HELPER(X) - -/* Identify known platforms by name. */ -#if defined(__linux) || defined(__linux__) || defined(linux) -# define PLATFORM_ID "Linux" - -#elif defined(__CYGWIN__) -# define PLATFORM_ID "Cygwin" - -#elif defined(__MINGW32__) -# define PLATFORM_ID "MinGW" - -#elif defined(__APPLE__) -# define PLATFORM_ID "Darwin" - -#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) -# define PLATFORM_ID "Windows" - -#elif defined(__FreeBSD__) || defined(__FreeBSD) -# define PLATFORM_ID "FreeBSD" - -#elif defined(__NetBSD__) || defined(__NetBSD) -# define PLATFORM_ID "NetBSD" - -#elif defined(__OpenBSD__) || defined(__OPENBSD) -# define PLATFORM_ID "OpenBSD" - -#elif defined(__sun) || defined(sun) -# define PLATFORM_ID "SunOS" - -#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) -# define PLATFORM_ID "AIX" - -#elif defined(__sgi) || defined(__sgi__) || defined(_SGI) -# define PLATFORM_ID "IRIX" - -#elif defined(__hpux) || defined(__hpux__) -# define PLATFORM_ID "HP-UX" - -#elif defined(__HAIKU__) -# define PLATFORM_ID "Haiku" - -#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) -# define PLATFORM_ID "BeOS" - -#elif defined(__QNX__) || defined(__QNXNTO__) -# define PLATFORM_ID "QNX" - -#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) -# define PLATFORM_ID "Tru64" - -#elif defined(__riscos) || defined(__riscos__) -# define PLATFORM_ID "RISCos" - -#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) -# define PLATFORM_ID "SINIX" - -#elif defined(__UNIX_SV__) -# define PLATFORM_ID "UNIX_SV" - -#elif defined(__bsdos__) -# define PLATFORM_ID "BSDOS" - -#elif defined(_MPRAS) || defined(MPRAS) -# define PLATFORM_ID "MP-RAS" - -#elif defined(__osf) || defined(__osf__) -# define PLATFORM_ID "OSF1" - -#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) -# define PLATFORM_ID "SCO_SV" - -#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) -# define PLATFORM_ID "ULTRIX" - -#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) -# define PLATFORM_ID "Xenix" - -#elif defined(__WATCOMC__) -# if defined(__LINUX__) -# define PLATFORM_ID "Linux" - -# elif defined(__DOS__) -# define PLATFORM_ID "DOS" - -# elif defined(__OS2__) -# define PLATFORM_ID "OS2" - -# elif defined(__WINDOWS__) -# define PLATFORM_ID "Windows3x" - -# else /* unknown platform */ -# define PLATFORM_ID -# endif - -#else /* unknown platform */ -# define PLATFORM_ID - -#endif - -/* For windows compilers MSVC and Intel we can determine - the architecture of the compiler being used. This is because - the compilers do not have flags that can change the architecture, - but rather depend on which compiler is being used -*/ -#if defined(_WIN32) && defined(_MSC_VER) -# if defined(_M_IA64) -# define ARCHITECTURE_ID "IA64" - -# elif defined(_M_X64) || defined(_M_AMD64) -# define ARCHITECTURE_ID "x64" - -# elif defined(_M_IX86) -# define ARCHITECTURE_ID "X86" - -# elif defined(_M_ARM64) -# define ARCHITECTURE_ID "ARM64" - -# elif defined(_M_ARM) -# if _M_ARM == 4 -# define ARCHITECTURE_ID "ARMV4I" -# elif _M_ARM == 5 -# define ARCHITECTURE_ID "ARMV5I" -# else -# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) -# endif - -# elif defined(_M_MIPS) -# define ARCHITECTURE_ID "MIPS" - -# elif defined(_M_SH) -# define ARCHITECTURE_ID "SHx" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__WATCOMC__) -# if defined(_M_I86) -# define ARCHITECTURE_ID "I86" - -# elif defined(_M_IX86) -# define ARCHITECTURE_ID "X86" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) -# if defined(__ICCARM__) -# define ARCHITECTURE_ID "ARM" - -# elif defined(__ICCAVR__) -# define ARCHITECTURE_ID "AVR" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif -#else -# define ARCHITECTURE_ID -#endif - -/* Convert integer to decimal digit literals. */ -#define DEC(n) \ - ('0' + (((n) / 10000000)%10)), \ - ('0' + (((n) / 1000000)%10)), \ - ('0' + (((n) / 100000)%10)), \ - ('0' + (((n) / 10000)%10)), \ - ('0' + (((n) / 1000)%10)), \ - ('0' + (((n) / 100)%10)), \ - ('0' + (((n) / 10)%10)), \ - ('0' + ((n) % 10)) - -/* Convert integer to hex digit literals. */ -#define HEX(n) \ - ('0' + ((n)>>28 & 0xF)), \ - ('0' + ((n)>>24 & 0xF)), \ - ('0' + ((n)>>20 & 0xF)), \ - ('0' + ((n)>>16 & 0xF)), \ - ('0' + ((n)>>12 & 0xF)), \ - ('0' + ((n)>>8 & 0xF)), \ - ('0' + ((n)>>4 & 0xF)), \ - ('0' + ((n) & 0xF)) - -/* Construct a string literal encoding the version number components. */ -#ifdef COMPILER_VERSION_MAJOR -char const info_version[] = { - 'I', 'N', 'F', 'O', ':', - 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', - COMPILER_VERSION_MAJOR, -# ifdef COMPILER_VERSION_MINOR - '.', COMPILER_VERSION_MINOR, -# ifdef COMPILER_VERSION_PATCH - '.', COMPILER_VERSION_PATCH, -# ifdef COMPILER_VERSION_TWEAK - '.', COMPILER_VERSION_TWEAK, -# endif -# endif -# endif - ']','\0'}; -#endif - -/* Construct a string literal encoding the internal version number. */ -#ifdef COMPILER_VERSION_INTERNAL -char const info_version_internal[] = { - 'I', 'N', 'F', 'O', ':', - 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', - 'i','n','t','e','r','n','a','l','[', - COMPILER_VERSION_INTERNAL,']','\0'}; -#endif - -/* Construct a string literal encoding the version number components. */ -#ifdef SIMULATE_VERSION_MAJOR -char const info_simulate_version[] = { - 'I', 'N', 'F', 'O', ':', - 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', - SIMULATE_VERSION_MAJOR, -# ifdef SIMULATE_VERSION_MINOR - '.', SIMULATE_VERSION_MINOR, -# ifdef SIMULATE_VERSION_PATCH - '.', SIMULATE_VERSION_PATCH, -# ifdef SIMULATE_VERSION_TWEAK - '.', SIMULATE_VERSION_TWEAK, -# endif -# endif -# endif - ']','\0'}; -#endif - -/* Construct the string literal in pieces to prevent the source from - getting matched. Store it in a pointer rather than an array - because some compilers will just produce instructions to fill the - array rather than assigning a pointer to a static array. */ -char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; -char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; - - - - -#if defined(_MSC_VER) && defined(_MSVC_LANG) -#define CXX_STD _MSVC_LANG -#else -#define CXX_STD __cplusplus -#endif - -const char* info_language_dialect_default = "INFO" ":" "dialect_default[" -#if CXX_STD > 201703L - "20" -#elif CXX_STD >= 201703L - "17" -#elif CXX_STD >= 201402L - "14" -#elif CXX_STD >= 201103L - "11" -#else - "98" -#endif -"]"; - -/*--------------------------------------------------------------------------*/ - -int main(int argc, char* argv[]) -{ - int require = 0; - require += info_compiler[argc]; - require += info_platform[argc]; -#ifdef COMPILER_VERSION_MAJOR - require += info_version[argc]; -#endif -#ifdef COMPILER_VERSION_INTERNAL - require += info_version_internal[argc]; -#endif -#ifdef SIMULATE_ID - require += info_simulate[argc]; -#endif -#ifdef SIMULATE_VERSION_MAJOR - require += info_simulate_version[argc]; -#endif -#if defined(__CRAYXE) || defined(__CRAYXC) - require += info_cray[argc]; -#endif - require += info_language_dialect_default[argc]; - (void)argv; - return require; -} diff --git a/cmake-build-debug/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp b/cmake-build-debug/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp deleted file mode 100644 index b728b6329..000000000 --- a/cmake-build-debug/CMakeFiles/3.13.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +++ /dev/null @@ -1,602 +0,0 @@ -/* This source file must have a .cpp extension so that all C++ compilers - recognize the extension without flags. Borland does not know .cxx for - example. */ -#ifndef __cplusplus -# error "A C compiler has been selected for C++." -#endif - - -/* Version number components: V=Version, R=Revision, P=Patch - Version date components: YYYY=Year, MM=Month, DD=Day */ - -#if defined(__COMO__) -# define COMPILER_ID "Comeau" - /* __COMO_VERSION__ = VRR */ -# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) -# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) - -#elif defined(__INTEL_COMPILER) || defined(__ICC) -# define COMPILER_ID "Intel" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif - /* __INTEL_COMPILER = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) -# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) -# if defined(__INTEL_COMPILER_UPDATE) -# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) -# else -# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) -# endif -# if defined(__INTEL_COMPILER_BUILD_DATE) - /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ -# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) -# endif -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif - -#elif defined(__PATHCC__) -# define COMPILER_ID "PathScale" -# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) -# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) -# if defined(__PATHCC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) -# endif - -#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) -# define COMPILER_ID "Embarcadero" -# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) -# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) -# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) - -#elif defined(__BORLANDC__) -# define COMPILER_ID "Borland" - /* __BORLANDC__ = 0xVRR */ -# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) -# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) - -#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 -# define COMPILER_ID "Watcom" - /* __WATCOMC__ = VVRR */ -# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) -# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) -# if (__WATCOMC__ % 10) > 0 -# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) -# endif - -#elif defined(__WATCOMC__) -# define COMPILER_ID "OpenWatcom" - /* __WATCOMC__ = VVRP + 1100 */ -# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) -# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) -# if (__WATCOMC__ % 10) > 0 -# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) -# endif - -#elif defined(__SUNPRO_CC) -# define COMPILER_ID "SunPro" -# if __SUNPRO_CC >= 0x5100 - /* __SUNPRO_CC = 0xVRRP */ -# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) -# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) -# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) -# else - /* __SUNPRO_CC = 0xVRP */ -# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) -# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) -# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) -# endif - -#elif defined(__HP_aCC) -# define COMPILER_ID "HP" - /* __HP_aCC = VVRRPP */ -# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) -# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) -# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) - -#elif defined(__DECCXX) -# define COMPILER_ID "Compaq" - /* __DECCXX_VER = VVRRTPPPP */ -# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) -# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) -# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) - -#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) -# define COMPILER_ID "zOS" -# if defined(__ibmxl__) -# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) -# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) -# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) -# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) -# else - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) -# endif - - -#elif defined(__ibmxl__) || (defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800) -# define COMPILER_ID "XL" -# if defined(__ibmxl__) -# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) -# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) -# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) -# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) -# else - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) -# endif - - -#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 -# define COMPILER_ID "VisualAge" -# if defined(__ibmxl__) -# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) -# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) -# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) -# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) -# else - /* __IBMCPP__ = VRP */ -# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) -# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) -# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) -# endif - - -#elif defined(__PGI) -# define COMPILER_ID "PGI" -# define COMPILER_VERSION_MAJOR DEC(__PGIC__) -# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) -# if defined(__PGIC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) -# endif - -#elif defined(_CRAYC) -# define COMPILER_ID "Cray" -# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) -# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) - -#elif defined(__TI_COMPILER_VERSION__) -# define COMPILER_ID "TI" - /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ -# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) -# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) -# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) - -#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version) -# define COMPILER_ID "Fujitsu" - -#elif defined(__SCO_VERSION__) -# define COMPILER_ID "SCO" - -#elif defined(__clang__) && defined(__apple_build_version__) -# define COMPILER_ID "AppleClang" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# define COMPILER_VERSION_MAJOR DEC(__clang_major__) -# define COMPILER_VERSION_MINOR DEC(__clang_minor__) -# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif -# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) - -#elif defined(__clang__) -# define COMPILER_ID "Clang" -# if defined(_MSC_VER) -# define SIMULATE_ID "MSVC" -# endif -# define COMPILER_VERSION_MAJOR DEC(__clang_major__) -# define COMPILER_VERSION_MINOR DEC(__clang_minor__) -# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) -# if defined(_MSC_VER) - /* _MSC_VER = VVRR */ -# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) -# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) -# endif - -#elif defined(__GNUC__) || defined(__GNUG__) -# define COMPILER_ID "GNU" -# if defined(__GNUC__) -# define COMPILER_VERSION_MAJOR DEC(__GNUC__) -# else -# define COMPILER_VERSION_MAJOR DEC(__GNUG__) -# endif -# if defined(__GNUC_MINOR__) -# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) -# endif -# if defined(__GNUC_PATCHLEVEL__) -# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) -# endif - -#elif defined(_MSC_VER) -# define COMPILER_ID "MSVC" - /* _MSC_VER = VVRR */ -# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) -# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) -# if defined(_MSC_FULL_VER) -# if _MSC_VER >= 1400 - /* _MSC_FULL_VER = VVRRPPPPP */ -# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) -# else - /* _MSC_FULL_VER = VVRRPPPP */ -# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) -# endif -# endif -# if defined(_MSC_BUILD) -# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) -# endif - -#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) -# define COMPILER_ID "ADSP" -#if defined(__VISUALDSPVERSION__) - /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ -# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) -# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) -# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) -#endif - -#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) -# define COMPILER_ID "IAR" -# if defined(__VER__) -# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) -# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) -# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) -# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) -# endif - -#elif defined(__ARMCC_VERSION) -# define COMPILER_ID "ARMCC" -#if __ARMCC_VERSION >= 1000000 - /* __ARMCC_VERSION = VRRPPPP */ - # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) - # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) - # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) -#else - /* __ARMCC_VERSION = VRPPPP */ - # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) - # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) - # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) -#endif - - -#elif defined(_SGI_COMPILER_VERSION) || defined(_COMPILER_VERSION) -# define COMPILER_ID "MIPSpro" -# if defined(_SGI_COMPILER_VERSION) - /* _SGI_COMPILER_VERSION = VRP */ -# define COMPILER_VERSION_MAJOR DEC(_SGI_COMPILER_VERSION/100) -# define COMPILER_VERSION_MINOR DEC(_SGI_COMPILER_VERSION/10 % 10) -# define COMPILER_VERSION_PATCH DEC(_SGI_COMPILER_VERSION % 10) -# else - /* _COMPILER_VERSION = VRP */ -# define COMPILER_VERSION_MAJOR DEC(_COMPILER_VERSION/100) -# define COMPILER_VERSION_MINOR DEC(_COMPILER_VERSION/10 % 10) -# define COMPILER_VERSION_PATCH DEC(_COMPILER_VERSION % 10) -# endif - - -/* These compilers are either not known or too old to define an - identification macro. Try to identify the platform and guess that - it is the native compiler. */ -#elif defined(__sgi) -# define COMPILER_ID "MIPSpro" - -#elif defined(__hpux) || defined(__hpua) -# define COMPILER_ID "HP" - -#else /* unknown compiler */ -# define COMPILER_ID "" -#endif - -/* Construct the string literal in pieces to prevent the source from - getting matched. Store it in a pointer rather than an array - because some compilers will just produce instructions to fill the - array rather than assigning a pointer to a static array. */ -char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; -#ifdef SIMULATE_ID -char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; -#endif - -#ifdef __QNXNTO__ -char const* qnxnto = "INFO" ":" "qnxnto[]"; -#endif - -#if defined(__CRAYXE) || defined(__CRAYXC) -char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; -#endif - -#define STRINGIFY_HELPER(X) #X -#define STRINGIFY(X) STRINGIFY_HELPER(X) - -/* Identify known platforms by name. */ -#if defined(__linux) || defined(__linux__) || defined(linux) -# define PLATFORM_ID "Linux" - -#elif defined(__CYGWIN__) -# define PLATFORM_ID "Cygwin" - -#elif defined(__MINGW32__) -# define PLATFORM_ID "MinGW" - -#elif defined(__APPLE__) -# define PLATFORM_ID "Darwin" - -#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) -# define PLATFORM_ID "Windows" - -#elif defined(__FreeBSD__) || defined(__FreeBSD) -# define PLATFORM_ID "FreeBSD" - -#elif defined(__NetBSD__) || defined(__NetBSD) -# define PLATFORM_ID "NetBSD" - -#elif defined(__OpenBSD__) || defined(__OPENBSD) -# define PLATFORM_ID "OpenBSD" - -#elif defined(__sun) || defined(sun) -# define PLATFORM_ID "SunOS" - -#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) -# define PLATFORM_ID "AIX" - -#elif defined(__sgi) || defined(__sgi__) || defined(_SGI) -# define PLATFORM_ID "IRIX" - -#elif defined(__hpux) || defined(__hpux__) -# define PLATFORM_ID "HP-UX" - -#elif defined(__HAIKU__) -# define PLATFORM_ID "Haiku" - -#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) -# define PLATFORM_ID "BeOS" - -#elif defined(__QNX__) || defined(__QNXNTO__) -# define PLATFORM_ID "QNX" - -#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) -# define PLATFORM_ID "Tru64" - -#elif defined(__riscos) || defined(__riscos__) -# define PLATFORM_ID "RISCos" - -#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) -# define PLATFORM_ID "SINIX" - -#elif defined(__UNIX_SV__) -# define PLATFORM_ID "UNIX_SV" - -#elif defined(__bsdos__) -# define PLATFORM_ID "BSDOS" - -#elif defined(_MPRAS) || defined(MPRAS) -# define PLATFORM_ID "MP-RAS" - -#elif defined(__osf) || defined(__osf__) -# define PLATFORM_ID "OSF1" - -#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) -# define PLATFORM_ID "SCO_SV" - -#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) -# define PLATFORM_ID "ULTRIX" - -#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) -# define PLATFORM_ID "Xenix" - -#elif defined(__WATCOMC__) -# if defined(__LINUX__) -# define PLATFORM_ID "Linux" - -# elif defined(__DOS__) -# define PLATFORM_ID "DOS" - -# elif defined(__OS2__) -# define PLATFORM_ID "OS2" - -# elif defined(__WINDOWS__) -# define PLATFORM_ID "Windows3x" - -# else /* unknown platform */ -# define PLATFORM_ID -# endif - -#else /* unknown platform */ -# define PLATFORM_ID - -#endif - -/* For windows compilers MSVC and Intel we can determine - the architecture of the compiler being used. This is because - the compilers do not have flags that can change the architecture, - but rather depend on which compiler is being used -*/ -#if defined(_WIN32) && defined(_MSC_VER) -# if defined(_M_IA64) -# define ARCHITECTURE_ID "IA64" - -# elif defined(_M_X64) || defined(_M_AMD64) -# define ARCHITECTURE_ID "x64" - -# elif defined(_M_IX86) -# define ARCHITECTURE_ID "X86" - -# elif defined(_M_ARM64) -# define ARCHITECTURE_ID "ARM64" - -# elif defined(_M_ARM) -# if _M_ARM == 4 -# define ARCHITECTURE_ID "ARMV4I" -# elif _M_ARM == 5 -# define ARCHITECTURE_ID "ARMV5I" -# else -# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) -# endif - -# elif defined(_M_MIPS) -# define ARCHITECTURE_ID "MIPS" - -# elif defined(_M_SH) -# define ARCHITECTURE_ID "SHx" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__WATCOMC__) -# if defined(_M_I86) -# define ARCHITECTURE_ID "I86" - -# elif defined(_M_IX86) -# define ARCHITECTURE_ID "X86" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif - -#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) -# if defined(__ICCARM__) -# define ARCHITECTURE_ID "ARM" - -# elif defined(__ICCAVR__) -# define ARCHITECTURE_ID "AVR" - -# else /* unknown architecture */ -# define ARCHITECTURE_ID "" -# endif -#else -# define ARCHITECTURE_ID -#endif - -/* Convert integer to decimal digit literals. */ -#define DEC(n) \ - ('0' + (((n) / 10000000)%10)), \ - ('0' + (((n) / 1000000)%10)), \ - ('0' + (((n) / 100000)%10)), \ - ('0' + (((n) / 10000)%10)), \ - ('0' + (((n) / 1000)%10)), \ - ('0' + (((n) / 100)%10)), \ - ('0' + (((n) / 10)%10)), \ - ('0' + ((n) % 10)) - -/* Convert integer to hex digit literals. */ -#define HEX(n) \ - ('0' + ((n)>>28 & 0xF)), \ - ('0' + ((n)>>24 & 0xF)), \ - ('0' + ((n)>>20 & 0xF)), \ - ('0' + ((n)>>16 & 0xF)), \ - ('0' + ((n)>>12 & 0xF)), \ - ('0' + ((n)>>8 & 0xF)), \ - ('0' + ((n)>>4 & 0xF)), \ - ('0' + ((n) & 0xF)) - -/* Construct a string literal encoding the version number components. */ -#ifdef COMPILER_VERSION_MAJOR -char const info_version[] = { - 'I', 'N', 'F', 'O', ':', - 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', - COMPILER_VERSION_MAJOR, -# ifdef COMPILER_VERSION_MINOR - '.', COMPILER_VERSION_MINOR, -# ifdef COMPILER_VERSION_PATCH - '.', COMPILER_VERSION_PATCH, -# ifdef COMPILER_VERSION_TWEAK - '.', COMPILER_VERSION_TWEAK, -# endif -# endif -# endif - ']','\0'}; -#endif - -/* Construct a string literal encoding the internal version number. */ -#ifdef COMPILER_VERSION_INTERNAL -char const info_version_internal[] = { - 'I', 'N', 'F', 'O', ':', - 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', - 'i','n','t','e','r','n','a','l','[', - COMPILER_VERSION_INTERNAL,']','\0'}; -#endif - -/* Construct a string literal encoding the version number components. */ -#ifdef SIMULATE_VERSION_MAJOR -char const info_simulate_version[] = { - 'I', 'N', 'F', 'O', ':', - 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', - SIMULATE_VERSION_MAJOR, -# ifdef SIMULATE_VERSION_MINOR - '.', SIMULATE_VERSION_MINOR, -# ifdef SIMULATE_VERSION_PATCH - '.', SIMULATE_VERSION_PATCH, -# ifdef SIMULATE_VERSION_TWEAK - '.', SIMULATE_VERSION_TWEAK, -# endif -# endif -# endif - ']','\0'}; -#endif - -/* Construct the string literal in pieces to prevent the source from - getting matched. Store it in a pointer rather than an array - because some compilers will just produce instructions to fill the - array rather than assigning a pointer to a static array. */ -char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; -char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; - - - - -#if defined(_MSC_VER) && defined(_MSVC_LANG) -#define CXX_STD _MSVC_LANG -#else -#define CXX_STD __cplusplus -#endif - -const char* info_language_dialect_default = "INFO" ":" "dialect_default[" -#if CXX_STD > 201703L - "20" -#elif CXX_STD >= 201703L - "17" -#elif CXX_STD >= 201402L - "14" -#elif CXX_STD >= 201103L - "11" -#else - "98" -#endif -"]"; - -/*--------------------------------------------------------------------------*/ - -int main(int argc, char* argv[]) -{ - int require = 0; - require += info_compiler[argc]; - require += info_platform[argc]; -#ifdef COMPILER_VERSION_MAJOR - require += info_version[argc]; -#endif -#ifdef COMPILER_VERSION_INTERNAL - require += info_version_internal[argc]; -#endif -#ifdef SIMULATE_ID - require += info_simulate[argc]; -#endif -#ifdef SIMULATE_VERSION_MAJOR - require += info_simulate_version[argc]; -#endif -#if defined(__CRAYXE) || defined(__CRAYXC) - require += info_cray[argc]; -#endif - require += info_language_dialect_default[argc]; - (void)argv; - return require; -} diff --git a/libuavcan/include/uavcan/node/generic_publisher.hpp b/libuavcan/include/uavcan/node/generic_publisher.hpp index 9a2175773..41744a102 100644 --- a/libuavcan/include/uavcan/node/generic_publisher.hpp +++ b/libuavcan/include/uavcan/node/generic_publisher.hpp @@ -93,7 +93,6 @@ class UAVCAN_EXPORT GenericPublisher : public GenericPublisherBase ZeroTransferBuffer, StaticTransferBuffer::Result> >::Result Buffer; - enum { ExtractQosFromDataKind = (DataTypeKind(DataSpec::DataTypeKind) == DataTypeKindMessage) ? diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index 8850646b8..6e0aae7c8 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -22,7 +22,6 @@ namespace uavcan { - struct UAVCAN_EXPORT CanRxFrame : public CanFrame { MonotonicTime ts_mono; diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index c1d5429cb..0eef4f5b6 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -1,7 +1,7 @@ /* -* AVL Tree implementation. -* Copyright (C) 2019 Theodoros Ntakouris -*/ + * AVL Tree implementation. + * Copyright (C) 2019 Theodoros Ntakouris + */ #ifndef UAVCAN_UTIL_AVL_TREE_HPP_INCLUDED #define UAVCAN_UTIL_AVL_TREE_HPP_INCLUDED @@ -18,16 +18,16 @@ namespace uavcan { -template +template class UAVCAN_EXPORT AvlTree : Noncopyable { protected: struct Node { - T* data; + T* data = UAVCAN_NULLPTR; int16_t h = 1; // initially added as leaf Node* left = UAVCAN_NULLPTR; Node* right = UAVCAN_NULLPTR; - Node* equalKeys = UAVCAN_NULLPTR; + Node* equal_keys = UAVCAN_NULLPTR; }; Node* root_; @@ -35,8 +35,8 @@ class UAVCAN_EXPORT AvlTree : Noncopyable private: size_t len_ ; - int16_t heightOf(const Node* n) const { - if(n == UAVCAN_NULLPTR) { + static int16_t heightOf(const Node* n) { + if (n == UAVCAN_NULLPTR) { return 0; } @@ -76,7 +76,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable } } - int16_t balanceOf(Node* n) const { + static int16_t balanceOf(Node* n) { if (n == UAVCAN_NULLPTR) { return 0; } @@ -84,11 +84,11 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return static_cast(heightOf(n->left) - heightOf(n->right)); } - int16_t maxOf(int16_t a, int16_t b) const { + static int16_t maxOf(int16_t a, int16_t b) { return static_cast(a > b ? a : b); } - Node* rotateRight(Node* y) const { + static Node* rotateRight(Node* y) { Node* x = y->left; Node* T2 = x->right; @@ -101,7 +101,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return x; } - Node* rotateLeft(Node* x) { + static Node* rotateLeft(Node* x) { Node* y = x->right; Node* T2 = y->left; @@ -115,16 +115,16 @@ class UAVCAN_EXPORT AvlTree : Noncopyable } // If UAVCAN_NULLPTR is returned, OOM happened. - Node* insert_node(Node* node, Node* newNode) { + Node* insertNode(Node* node, Node* newNode) { if (node == UAVCAN_NULLPTR) { len_++; return newNode; } if (*newNode->data < *node->data) { - node->left = insert_node(node->left, newNode); + node->left = insertNode(node->left, newNode); } else if (*newNode->data > *node->data) { - node->right = insert_node(node->right, newNode); + node->right = insertNode(node->right, newNode); } else { len_++; appendToEndOf(node, newNode); @@ -156,25 +156,26 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return node; } - void appendToEndOf(Node* head, Node* newNode) { + static void appendToEndOf(Node* head, Node* newNode) { Node* target = head; - while(target->equalKeys != UAVCAN_NULLPTR) { - target = head->equalKeys; + while(target->equal_keys != UAVCAN_NULLPTR) { + target = head->equal_keys; } - target->equalKeys = newNode; + target->equal_keys = newNode; } /* Delete the element of the linked list (memory address comparison) - * and return the new head */ + * and return the new head + */ Node* deleteFromList(Node* root, T* data) { Node* current = root; Node* prev = UAVCAN_NULLPTR; while(current != UAVCAN_NULLPTR) { - if(current->data == data) { - if(current == root) { - Node* ret = current->equalKeys; // From the remove method, this should never be null + if (current->data == data) { + if (current == root) { + Node* ret = current->equal_keys; // From the remove method, this should never be null /* Inherit subtrees */ ret->h = current->h; @@ -186,8 +187,8 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return ret; /* Return one element forward */ } else { - Node* next = current->equalKeys; - prev->equalKeys = next; + Node* next = current->equal_keys; + prev->equal_keys = next; len_--; deleteNode(current); return root; /* Unchanged root, non-head element was changed */ @@ -195,7 +196,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable } prev = current; - current = current->equalKeys; + current = current->equal_keys; } return root; @@ -216,7 +217,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable * Use this only to allocate the Node struct. * `T data` should be already allocated and * provided ready for usage from the outside world - * */ + */ LimitedPoolAllocator allocator_; void postOrderNodeTraverseRecursively(Node* n, std::function forEach) { @@ -229,17 +230,17 @@ class UAVCAN_EXPORT AvlTree : Noncopyable forEach(n); } - Node* remove_node(Node* node, T* data) { + Node* removeNode(Node* node, T* data) { if (node == UAVCAN_NULLPTR) { return node; } if (*data < *node->data) { - node->left = remove_node(node->left, data); + node->left = removeNode(node->left, data); } else if (*data > *node->data) { - node->right = remove_node(node->right, data); + node->right = removeNode(node->right, data); } else { - if(node->equalKeys == UAVCAN_NULLPTR) { + if (node->equal_keys == UAVCAN_NULLPTR) { if (node->left == UAVCAN_NULLPTR || node->right == UAVCAN_NULLPTR) { Node *temp = node->left ? node->left : node->right; @@ -260,7 +261,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable } node->data = minOfRight->data; - node->right = remove_node(node->right, minOfRight->data); + node->right = removeNode(node->right, minOfRight->data); } } else { Node* newHead = deleteFromList(node, data); @@ -297,13 +298,13 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return node; } - bool linkedListContains(Node* head, const T* data) const { + static bool linkedListContains(Node* head, const T* data) { Node* next = head; while(next != UAVCAN_NULLPTR) { - if(next->data == data) { /* Memory address comparison */ + if (next->data == data) { /* Memory address comparison */ return true; } - next = next->equalKeys; + next = next->equal_keys; } return false; } @@ -316,21 +317,21 @@ class UAVCAN_EXPORT AvlTree : Noncopyable {} virtual ~AvlTree() { - // delete leafs first + // Delete leafs first. postOrderTraverseNodeCleanup(this->root_); } - void remove_entry(T* data) { - root_ = remove_node(root_, data); + void removeEntry(T* data) { + root_ = removeNode(root_, data); } bool insert(T* data) { Node* newNode = makeNode(data); - if(newNode == UAVCAN_NULLPTR) { + if (newNode == UAVCAN_NULLPTR) { return false; } - root_ = insert_node(root_, newNode); + root_ = insertNode(root_, newNode); return true; } @@ -355,25 +356,22 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return UAVCAN_NULLPTR; } - for (;;) { - Node* next = n->right; - if (next == UAVCAN_NULLPTR) { - return n->data; - } - - n = next; + while (n->right != UAVCAN_NULLPTR) { + n = n->right; } + + return n->data; } bool contains(const T* data) const { Node* n = root_; while (n != UAVCAN_NULLPTR) { - if(*n->data < *data) { + if (*n->data < *data) { n = n->right; continue; } - if(*n->data > *data) { + if (*n->data > *data) { n = n->left; continue; } diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index 07c6b7c1a..6a4f73a7b 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -1,8 +1,8 @@ /* -* CAN bus IO logic. -* Copyright (C) 2014 Pavel Kirienko -* Copyright (C) 2019 Theodoros Ntakouris -*/ + * CAN bus IO logic. + * Copyright (C) 2014 Pavel Kirienko + * Copyright (C) 2019 Theodoros Ntakouris + */ #include #include @@ -12,8 +12,8 @@ namespace uavcan { /* -* CanRxFrame -*/ + * CanRxFrame + */ #if UAVCAN_TOSTRING std::string CanRxFrame::toString(StringRepresentation mode) const { @@ -29,8 +29,8 @@ std::string CanRxFrame::toString(StringRepresentation mode) const { #endif /* -* CanTxQueue::Entry -*/ + * CanTxQueue::Entry + */ void CanTxQueueEntry::destroy(CanTxQueueEntry*& obj, IPoolAllocator &allocator) { if (obj != UAVCAN_NULLPTR) { obj->~CanTxQueueEntry(); @@ -64,8 +64,8 @@ std::string CanTxQueueEntry::toString() const { #endif /* -* CanTxQueue -*/ + * CanTxQueue + */ CanTxQueue::~CanTxQueue() { // Remove all nodes & node contents of the tree without performing re-balancing steps postOrderTraverseEntryCleanup(this->root_); @@ -82,16 +82,16 @@ void CanTxQueue::postOrderTraverseEntryCleanup(Node* n) { CanTxQueueEntry::destroy(n->data, this->allocator_); } -bool CanTxQueue::contains(const CanFrame& frame) const{ +bool CanTxQueue::contains(const CanFrame& frame) const { Node* n = this->root_; while (n != UAVCAN_NULLPTR) { - if(frame.priorityHigherThan(n->data->frame)) { + if (frame.priorityHigherThan(n->data->frame)) { n = n->right; continue; } - if(frame.priorityLowerThan(n->data->frame)) { + if (frame.priorityLowerThan(n->data->frame)) { n = n->left; continue; } @@ -101,14 +101,14 @@ bool CanTxQueue::contains(const CanFrame& frame) const{ return false; } -bool CanTxQueue::linkedListContains(Node* head, const CanFrame& frame) const{ +bool CanTxQueue::linkedListContains(Node* head, const CanFrame& frame) const { Node* next = head; while(next != UAVCAN_NULLPTR) { - if(next->data->frame == frame) { + if (next->data->frame == frame) { return true; } - next = head->equalKeys; + next = head->equal_keys; } return false; } @@ -153,7 +153,7 @@ void CanTxQueue::remove(CanTxQueueEntry* entry) { } // Make the AvlTree remove the specific entry deleting it's Node * - this->AvlTree::remove_entry(entry); + this->AvlTree::removeEntry(entry); // Then let the entry destroy it's own contents CanTxQueueEntry::destroy(entry, this->allocator_); } @@ -161,7 +161,7 @@ void CanTxQueue::remove(CanTxQueueEntry* entry) { CanTxQueueEntry* CanTxQueue::peek() { Node* maxNode = searchForNonExpiredMax(this->root_); - if(maxNode == UAVCAN_NULLPTR) { + if (maxNode == UAVCAN_NULLPTR) { return UAVCAN_NULLPTR; } @@ -190,7 +190,7 @@ uavcan::AvlTree::Node* CanTxQueue::searchForNonExpiredM while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)) { CanTxQueueEntry* expiredEntry = n->data; - n->right = this->AvlTree::remove_node(n, n->data); + n->right = this->AvlTree::removeNode(n, n->data); CanTxQueueEntry::destroy(expiredEntry, this->allocator_); } @@ -204,8 +204,8 @@ uavcan::AvlTree::Node* CanTxQueue::searchForNonExpiredM } /* -* CanIOManager -*/ + * CanIOManager + */ int CanIOManager::sendToIface(uint8_t iface_index, const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags) { UAVCAN_ASSERT(iface_index < MaxCanIfaces); @@ -252,7 +252,7 @@ int CanIOManager::callSelect(CanSelectMasks &inout_masks, const CanFrame *(&pend return res; } -CanIOManager::CanIOManager(ICanDriver &driver, IPoolAllocator &allocator, ISystemClock &sysclock, +CanIOManager::CanIOManager(ICanDriver& driver, IPoolAllocator& allocator, ISystemClock& sysclock, std::size_t mem_blocks_per_iface) : driver_(driver), sysclock_(sysclock), num_ifaces_(driver.getNumIfaces()) { if (num_ifaces_ < 1 || num_ifaces_ > MaxCanIfaces) { @@ -316,8 +316,8 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton masks.write = iface_mask | makePendingTxMask(); { // Building the list of next pending frames per iface. - // The driver will give them a scrutinizing look before deciding whether he wants to accept them. - // TODO: What does this mean? can we optimize further before passing them to the driver? + // This is needed to avoid inner priority inversion in the TX queue. + // This is explained in the section 4.4.3.3 of the spec. const CanFrame* pending_tx[MaxCanIfaces] = {}; for (int i = 0; i < num_ifaces; i++) { CanTxQueue &q = *tx_queues_[i]; @@ -326,14 +326,14 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton if (iface_mask & (1 << i)) // I hate myself so much right now. { - bool hasPriority = false; + bool has_priority = false; // This may seem duplicate of topPriorityHigherOrEqual but we want to avoid traversing the queue again - if(peek_entry != UAVCAN_NULLPTR) { - hasPriority = !frame.priorityHigherThan(*peek_frame); + if (peek_entry != UAVCAN_NULLPTR) { + has_priority = !frame.priorityHigherThan(*peek_frame); } - pending_tx[i] = hasPriority ? peek_frame : &frame; + pending_tx[i] = has_priority ? peek_frame : &frame; } else { pending_tx[i] = peek_frame; } @@ -428,8 +428,7 @@ int CanIOManager::receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline const int res = iface->receive(out_frame, out_frame.ts_mono, out_frame.ts_utc, out_flags); if (res == 0) { - UAVCAN_ASSERT( - 0); // select() reported that iface has pending RX frames, but receive() returned none + UAVCAN_ASSERT(0); // select() reported that iface has pending RX frames, but receive() returned none continue; } out_frame.iface_index = i; diff --git a/libuavcan/test/util/avl_tree.cpp b/libuavcan/test/util/avl_tree.cpp index cf1dacfbf..a7ac29584 100644 --- a/libuavcan/test/util/avl_tree.cpp +++ b/libuavcan/test/util/avl_tree.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2019 Theodoros Ntakouris - * */ + */ #include #include @@ -9,31 +9,28 @@ using uavcan::AvlTree; -struct Entry{ +struct Entry { int key; int payload; - bool operator<(const Entry & other) const - { + bool operator<(const Entry& other) const { return this->key < other.key; } - bool operator>(const Entry & other) const - { + bool operator>(const Entry& other) const { return this->key > other.key; } - bool operator==(const Entry & other) const - { + bool operator==(const Entry& other) const { return this->key == other.key; } }; -/* OOM-Unsafe */ -inline Entry *makeEntry(uavcan::PoolAllocator<64 * 24, 64> *allocator, int key, int payload){ - void *praw = allocator->allocate(sizeof(Entry)); +// OOM-Unsafe +inline Entry* makeEntry(uavcan::PoolAllocator<64 * 24, 64>* allocator, int key, int payload) { + void* praw = allocator->allocate(sizeof(Entry)); - Entry *e = new (praw) Entry(); + Entry* e = new (praw) Entry(); UAVCAN_ASSERT(e); e->key = key; @@ -41,19 +38,21 @@ inline Entry *makeEntry(uavcan::PoolAllocator<64 * 24, 64> *allocator, int key, return e; } -inline bool matchPostOrder(Entry* expected[], AvlTree *tree){ +inline bool matchPostOrder(Entry* expected[], AvlTree* tree) { int count = 0; bool res = true; - tree->walkPostOrder([expected, &count, &res](Entry*& in){ + + tree->walkPostOrder([expected, &count, &res](Entry*& in) { auto res_ = in == expected[count]; res &= res_; count++; }); + return res; } /* Basic sanity checks */ -TEST(AvlTree, Sanity){ +TEST(AvlTree, Sanity) { uavcan::PoolAllocator<64 * 24, 64> pool; // 4 (x2) entries capacity AvlTree tree(pool, 99999); @@ -115,8 +114,8 @@ TEST(AvlTree, Sanity){ EXPECT_EQ(8, pool.getNumUsedBlocks()); /* - * Remove e2 - e4 - */ + * Remove e2 - e4 + */ tree.remove_entry(e2); EXPECT_TRUE(tree.contains(e1)); @@ -137,7 +136,7 @@ TEST(AvlTree, Sanity){ } /* Test multiple entries with same 'key' */ -TEST(AvlTree, MultipleEntriesPerKey){ +TEST(AvlTree, MultipleEntriesPerKey) { uavcan::PoolAllocator<64 * 24, 64> pool; // 4 (x2) entries capacity AvlTree tree(pool, 99999); @@ -150,7 +149,7 @@ TEST(AvlTree, MultipleEntriesPerKey){ /* * Insert 2 entries with same key - * */ + */ tree.insert(e1); tree.insert(e1_1); @@ -212,7 +211,7 @@ TEST(AvlTree, MultipleEntriesPerKey){ /* Check all possible rotation / balancing cases * Test cases from: https://stackoverflow.com/questions/3955680/how-to-check-if-my-avl-tree-implementation-is-correct * */ -TEST(AvlTree, AllRotations){ +TEST(AvlTree, AllRotations) { uavcan::PoolAllocator<64 * 24, 64> pool; // 4 (x2) entries capacity AvlTree tree(pool, 99999); From bd69b044deb90f0256f2a4657013134c02265253 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Fri, 22 Feb 2019 15:11:57 +0200 Subject: [PATCH 15/23] Remove auto in avl_tree.cpp --- libuavcan/test/util/avl_tree.cpp | 42 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/libuavcan/test/util/avl_tree.cpp b/libuavcan/test/util/avl_tree.cpp index a7ac29584..b0b8e7e27 100644 --- a/libuavcan/test/util/avl_tree.cpp +++ b/libuavcan/test/util/avl_tree.cpp @@ -43,7 +43,7 @@ inline bool matchPostOrder(Entry* expected[], AvlTree* tree) { bool res = true; tree->walkPostOrder([expected, &count, &res](Entry*& in) { - auto res_ = in == expected[count]; + bool res_ = in == expected[count]; res &= res_; count++; }); @@ -59,10 +59,10 @@ TEST(AvlTree, Sanity) { EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(0, pool.getNumUsedBlocks()); - auto e1 = makeEntry(&pool, 1, 1); - auto e2 = makeEntry(&pool, 2, 2); - auto e3 = makeEntry(&pool, 3, 3); - auto e4 = makeEntry(&pool, 4, 4); + Entry* e1 = makeEntry(&pool, 1, 1); + Entry* e2 = makeEntry(&pool, 2, 2); + Entry* e3 = makeEntry(&pool, 3, 3); + Entry* e4 = makeEntry(&pool, 4, 4); EXPECT_EQ(4, pool.getNumUsedBlocks()); @@ -141,11 +141,11 @@ TEST(AvlTree, MultipleEntriesPerKey) { AvlTree tree(pool, 99999); - auto e1 = makeEntry(&pool, 1, 1); - auto e1_1 = makeEntry(&pool, 1, 11); - auto e1_11 = makeEntry(&pool, 1, 111); + Entry* e1 = makeEntry(&pool, 1, 1); + Entry* e1_1 = makeEntry(&pool, 1, 11); + Entry* e1_11 = makeEntry(&pool, 1, 111); - auto e2 = makeEntry(&pool, 2, 2); + Entry* e2 = makeEntry(&pool, 2, 2); /* * Insert 2 entries with same key @@ -218,18 +218,18 @@ TEST(AvlTree, AllRotations) { EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(0, pool.getNumUsedBlocks()); - auto a = makeEntry(&pool, 1, 1); - auto b = makeEntry(&pool, 2, 2); - auto c = makeEntry(&pool, 3, 3); - auto d = makeEntry(&pool, 4, 4); - auto e = makeEntry(&pool, 5, 5); - auto f = makeEntry(&pool, 6, 6); - auto g = makeEntry(&pool, 7, 7); - auto h = makeEntry(&pool, 8, 8); - auto i = makeEntry(&pool, 9, 9); - auto j = makeEntry(&pool, 10, 10); - auto k = makeEntry(&pool, 11, 11); - auto l = makeEntry(&pool, 12, 12); + Entry* a = makeEntry(&pool, 1, 1); + Entry* b = makeEntry(&pool, 2, 2); + Entry* c = makeEntry(&pool, 3, 3); + Entry* d = makeEntry(&pool, 4, 4); + Entry* e = makeEntry(&pool, 5, 5); + Entry* f = makeEntry(&pool, 6, 6); + Entry* g = makeEntry(&pool, 7, 7); + Entry* h = makeEntry(&pool, 8, 8); + Entry* i = makeEntry(&pool, 9, 9); + Entry* j = makeEntry(&pool, 10, 10); + Entry* k = makeEntry(&pool, 11, 11); + Entry* l = makeEntry(&pool, 12, 12); /* * Simple test cases for insert From 2c12d208cdb7e05dcad1c70836951e445c0b9e0c Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Fri, 22 Feb 2019 15:13:56 +0200 Subject: [PATCH 16/23] Fix tx_queue.cpp tests --- libuavcan/test/transport/can/tx_queue.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libuavcan/test/transport/can/tx_queue.cpp b/libuavcan/test/transport/can/tx_queue.cpp index cc1cae694..f09b1e9d3 100644 --- a/libuavcan/test/transport/can/tx_queue.cpp +++ b/libuavcan/test/transport/can/tx_queue.cpp @@ -80,7 +80,7 @@ TEST(CanTxQueue, TxQueue) * Removing */ - CanTxQueueEntry *entry = queue.peek(); + CanTxQueueEntry* entry = queue.peek(); EXPECT_TRUE(entry); queue.remove(entry); @@ -95,7 +95,7 @@ TEST(CanTxQueue, TxQueue) EXPECT_FALSE(queue.contains(f5)); EXPECT_FALSE(queue.contains(f6)); - while(queue.peek() != UAVCAN_NULLPTR){ + while (queue.peek() != UAVCAN_NULLPTR) { queue.remove(queue.peek()); } @@ -119,7 +119,7 @@ TEST(CanTxQueue, TxQueue) EXPECT_TRUE(queue.contains(f0)); EXPECT_TRUE(queue.contains(f4)); // f0 is higher priority, so will get traversed first -- f4 not yet removed - auto peek = queue.peek(); + CanTxQueueEntry* peek = queue.peek(); EXPECT_EQ(f0, peek->frame); queue.remove(peek); @@ -170,7 +170,7 @@ TEST(CanTxQueue, TxQueue) * Remove all - cleanup */ - while(queue.peek() != UAVCAN_NULLPTR){ + while (queue.peek() != UAVCAN_NULLPTR) { queue.remove(queue.peek()); } From 41d92b652b9e69b7e3ab897d10405b2976c3710b Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Fri, 22 Feb 2019 15:37:38 +0200 Subject: [PATCH 17/23] naming --- libuavcan/test/util/avl_tree.cpp | 150 +++++++++++++++---------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/libuavcan/test/util/avl_tree.cpp b/libuavcan/test/util/avl_tree.cpp index b0b8e7e27..11059cb20 100644 --- a/libuavcan/test/util/avl_tree.cpp +++ b/libuavcan/test/util/avl_tree.cpp @@ -72,14 +72,14 @@ TEST(AvlTree, Sanity) { EXPECT_EQ(1, tree.getSize()); EXPECT_EQ(5, pool.getNumUsedBlocks()); - tree.remove_entry(e1); + tree.removeEntry(e1); EXPECT_FALSE(tree.contains(e1)); EXPECT_EQ(UAVCAN_NULLPTR, tree.max()); EXPECT_EQ(0, tree.getSize()); EXPECT_EQ(4, pool.getNumUsedBlocks()); // Won't break if asked to remove data that do not exist - tree.remove_entry(e1); + tree.removeEntry(e1); EXPECT_FALSE(tree.contains(e1)); EXPECT_EQ(UAVCAN_NULLPTR, tree.max()); EXPECT_EQ(0, tree.getSize()); @@ -117,7 +117,7 @@ TEST(AvlTree, Sanity) { * Remove e2 - e4 */ - tree.remove_entry(e2); + tree.removeEntry(e2); EXPECT_TRUE(tree.contains(e1)); EXPECT_FALSE(tree.contains(e2)); EXPECT_TRUE(tree.contains(e3)); @@ -126,7 +126,7 @@ TEST(AvlTree, Sanity) { EXPECT_EQ(3, tree.getSize()); EXPECT_EQ(7, pool.getNumUsedBlocks()); - tree.remove_entry(e4); + tree.removeEntry(e4); EXPECT_TRUE(tree.contains(e1)); EXPECT_TRUE(tree.contains(e3)); EXPECT_FALSE(tree.contains(e4)); @@ -160,7 +160,7 @@ TEST(AvlTree, MultipleEntriesPerKey) { EXPECT_EQ(6, pool.getNumUsedBlocks()); - tree.remove_entry(e1); + tree.removeEntry(e1); EXPECT_FALSE(tree.contains(e1)); EXPECT_TRUE(tree.contains(e1_1)); @@ -168,7 +168,7 @@ TEST(AvlTree, MultipleEntriesPerKey) { EXPECT_EQ(1, tree.getSize()); EXPECT_EQ(5, pool.getNumUsedBlocks()); - tree.remove_entry(e1); + tree.removeEntry(e1); /* * Insert another with higher priority and @@ -189,8 +189,8 @@ TEST(AvlTree, MultipleEntriesPerKey) { EXPECT_EQ(4, tree.getSize()); EXPECT_EQ(8, pool.getNumUsedBlocks()); - tree.remove_entry(e2); - tree.remove_entry(e1_1); // middle one in node with key == 1 + tree.removeEntry(e2); + tree.removeEntry(e1_1); // middle one in node with key == 1 EXPECT_FALSE(tree.contains(e2)); EXPECT_TRUE(tree.contains(e1)); EXPECT_FALSE(tree.contains(e1_1)); @@ -200,7 +200,7 @@ TEST(AvlTree, MultipleEntriesPerKey) { EXPECT_EQ(2, tree.getSize()); EXPECT_EQ(6, pool.getNumUsedBlocks()); - tree.remove_entry(e1_11); // last one in queue + tree.removeEntry(e1_11); // last one in queue EXPECT_EQ(e1, tree.max()); EXPECT_FALSE(tree.contains(e1_11)); @@ -251,9 +251,9 @@ TEST(AvlTree, AllRotations) { Entry* match_1l[] = {a, c, b}; EXPECT_TRUE(matchPostOrder(match_1l , &tree)); - tree.remove_entry(a); - tree.remove_entry(b); - tree.remove_entry(c); + tree.removeEntry(a); + tree.removeEntry(b); + tree.removeEntry(c); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -272,9 +272,9 @@ TEST(AvlTree, AllRotations) { Entry* match_1r[] = {a,c,b}; EXPECT_TRUE(matchPostOrder(match_1r , &tree)); - tree.remove_entry(c); - tree.remove_entry(b); - tree.remove_entry(a); + tree.removeEntry(c); + tree.removeEntry(b); + tree.removeEntry(a); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -293,9 +293,9 @@ TEST(AvlTree, AllRotations) { Entry* match_2l[] = {a,c,b}; EXPECT_TRUE(matchPostOrder(match_2l , &tree)); - tree.remove_entry(a); - tree.remove_entry(c); - tree.remove_entry(b); + tree.removeEntry(a); + tree.removeEntry(c); + tree.removeEntry(b); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -315,9 +315,9 @@ TEST(AvlTree, AllRotations) { Entry* match_2r[] = {a,c,b}; EXPECT_TRUE(matchPostOrder(match_2r , &tree)); - tree.remove_entry(c); - tree.remove_entry(a); - tree.remove_entry(b); + tree.removeEntry(c); + tree.removeEntry(a); + tree.removeEntry(b); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -342,14 +342,14 @@ TEST(AvlTree, AllRotations) { Entry* match_pre_del_1l[] = {a,d,c,b}; EXPECT_TRUE(matchPostOrder(match_pre_del_1l , &tree)); - tree.remove_entry(a); + tree.removeEntry(a); Entry* match_post_del_1l[] = {b,d,c}; EXPECT_TRUE(matchPostOrder(match_post_del_1l , &tree)); - tree.remove_entry(b); - tree.remove_entry(c); - tree.remove_entry(d); + tree.removeEntry(b); + tree.removeEntry(c); + tree.removeEntry(d); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -370,14 +370,14 @@ TEST(AvlTree, AllRotations) { Entry* match_pre_del_1r[] = {a,b,d,c}; EXPECT_TRUE(matchPostOrder(match_pre_del_1r , &tree)); - tree.remove_entry(d); + tree.removeEntry(d); Entry* match_post_del_1r[] = {a,c,b}; EXPECT_TRUE(matchPostOrder(match_post_del_1r , &tree)); - tree.remove_entry(c); - tree.remove_entry(b); - tree.remove_entry(a); + tree.removeEntry(c); + tree.removeEntry(b); + tree.removeEntry(a); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -396,14 +396,14 @@ TEST(AvlTree, AllRotations) { Entry* match_pre_del_2l[] = {a,c,d,b}; EXPECT_TRUE(matchPostOrder(match_pre_del_2l , &tree)); - tree.remove_entry(a); + tree.removeEntry(a); Entry* match_post_del_2l[] = {b,d,c}; EXPECT_TRUE(matchPostOrder(match_post_del_2l , &tree)); - tree.remove_entry(b); - tree.remove_entry(d); - tree.remove_entry(c); + tree.removeEntry(b); + tree.removeEntry(d); + tree.removeEntry(c); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -423,14 +423,14 @@ TEST(AvlTree, AllRotations) { Entry* match_pre_del_2r[] = {b,a,d,c}; EXPECT_TRUE(matchPostOrder(match_pre_del_2r , &tree)); - tree.remove_entry(d); + tree.removeEntry(d); Entry* match_post_del_2r[] = {a,c,b}; EXPECT_TRUE(matchPostOrder(match_post_del_2r , &tree)); - tree.remove_entry(c); - tree.remove_entry(a); - tree.remove_entry(b); + tree.removeEntry(c); + tree.removeEntry(a); + tree.removeEntry(b); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -460,17 +460,17 @@ TEST(AvlTree, AllRotations) { Entry* match_c_pre_del_1r[] = {a,b,d,g,f,e,c}; EXPECT_TRUE(matchPostOrder(match_c_pre_del_1r , &tree)); - tree.remove_entry(a); + tree.removeEntry(a); Entry* match_c_post_del_1r[] = {b,d,c,g,f,e}; EXPECT_TRUE(matchPostOrder(match_c_post_del_1r , &tree)); - tree.remove_entry(c); - tree.remove_entry(b); - tree.remove_entry(e); - tree.remove_entry(d); - tree.remove_entry(f); - tree.remove_entry(g); + tree.removeEntry(c); + tree.removeEntry(b); + tree.removeEntry(e); + tree.removeEntry(d); + tree.removeEntry(f); + tree.removeEntry(g); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -497,17 +497,17 @@ TEST(AvlTree, AllRotations) { Entry* match_c2_pre_del_1r[] = {a,b,d,c,g,f,e}; EXPECT_TRUE(matchPostOrder(match_c2_pre_del_1r , &tree)); - tree.remove_entry(g); + tree.removeEntry(g); Entry* match_c2_post_del_1r[] = {a,b,d,f,e,c}; EXPECT_TRUE(matchPostOrder(match_c2_post_del_1r , &tree)); - tree.remove_entry(e); - tree.remove_entry(c); - tree.remove_entry(f); - tree.remove_entry(b); - tree.remove_entry(d); - tree.remove_entry(a); + tree.removeEntry(e); + tree.removeEntry(c); + tree.removeEntry(f); + tree.removeEntry(b); + tree.removeEntry(d); + tree.removeEntry(a); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -541,22 +541,22 @@ TEST(AvlTree, AllRotations) { Entry* match_c_pre_del_2l[] = {b,a,d,c,f,g,i,h,l,k,j,e}; EXPECT_TRUE(matchPostOrder(match_c_pre_del_2l , &tree)); - tree.remove_entry(b); + tree.removeEntry(b); Entry* match_c_post_del_2l[] = {a,d,c,f,g,e,i,l,k,j,h}; EXPECT_TRUE(matchPostOrder(match_c_post_del_2l , &tree)); - tree.remove_entry(e); - tree.remove_entry(c); - tree.remove_entry(j); - tree.remove_entry(a); - tree.remove_entry(d); - tree.remove_entry(h); - tree.remove_entry(k); - tree.remove_entry(g); - tree.remove_entry(i); - tree.remove_entry(l); - tree.remove_entry(f); + tree.removeEntry(e); + tree.removeEntry(c); + tree.removeEntry(j); + tree.removeEntry(a); + tree.removeEntry(d); + tree.removeEntry(h); + tree.removeEntry(k); + tree.removeEntry(g); + tree.removeEntry(i); + tree.removeEntry(l); + tree.removeEntry(f); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); @@ -588,22 +588,22 @@ TEST(AvlTree, AllRotations) { Entry* match_c_pre_del_2r[] = {a,b,d,g,f,e,c,j,i,l,k,h}; EXPECT_TRUE(matchPostOrder(match_c_pre_del_2r , &tree)); - tree.remove_entry(j); + tree.removeEntry(j); Entry* match_c_post_del_2r[] = {a,b,d,c,g,f,i,l,k,h,e}; EXPECT_TRUE(matchPostOrder(match_c_post_del_2r , &tree)); - tree.remove_entry(h); - tree.remove_entry(c); - tree.remove_entry(k); - tree.remove_entry(b); - tree.remove_entry(e); - tree.remove_entry(i); - tree.remove_entry(l); - tree.remove_entry(a); - tree.remove_entry(d); - tree.remove_entry(f); - tree.remove_entry(g); + tree.removeEntry(h); + tree.removeEntry(c); + tree.removeEntry(k); + tree.removeEntry(b); + tree.removeEntry(e); + tree.removeEntry(i); + tree.removeEntry(l); + tree.removeEntry(a); + tree.removeEntry(d); + tree.removeEntry(f); + tree.removeEntry(g); EXPECT_TRUE(tree.isEmpty()); EXPECT_EQ(12, pool.getNumUsedBlocks()); From 6ebda4a8e4c8e4d93a71bd8b7418120e886e0a4d Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Fri, 22 Feb 2019 16:25:38 +0200 Subject: [PATCH 18/23] Drop QoS completely --- .../include/uavcan/node/abstract_node.hpp | 5 +- .../include/uavcan/node/generic_publisher.hpp | 10 +--- libuavcan/include/uavcan/transport/can_io.hpp | 13 ++--- .../include/uavcan/transport/dispatcher.hpp | 2 +- .../uavcan/transport/transfer_sender.hpp | 9 ++-- libuavcan/src/node/uc_generic_publisher.cpp | 4 +- libuavcan/src/transport/uc_can_io.cpp | 48 ++++++------------- libuavcan/src/transport/uc_dispatcher.cpp | 4 +- .../src/transport/uc_transfer_sender.cpp | 7 ++- libuavcan/test/transport/can/io.cpp | 32 ++++++------- libuavcan/test/transport/can/tx_queue.cpp | 25 +++++----- libuavcan/test/transport/dispatcher.cpp | 4 +- libuavcan/test/transport/transfer_sender.cpp | 9 ++-- .../linux/apps/test_multithreading.cpp | 5 +- 14 files changed, 68 insertions(+), 109 deletions(-) diff --git a/libuavcan/include/uavcan/node/abstract_node.hpp b/libuavcan/include/uavcan/node/abstract_node.hpp index 9e1e20a9c..dd68e5153 100644 --- a/libuavcan/include/uavcan/node/abstract_node.hpp +++ b/libuavcan/include/uavcan/node/abstract_node.hpp @@ -104,15 +104,12 @@ class UAVCAN_EXPORT INode * * Optional parameters: * - * @param qos Quality of service. Please refer to the CAN IO manager for details. - * * @param flags CAN IO flags. Please refer to the CAN driver API for details. */ int injectTxFrame(const CanFrame& frame, MonotonicTime tx_deadline, uint8_t iface_mask, - Qos qos = Qos::Volatile, CanIOFlags flags = 0) { - return getDispatcher().getCanIOManager().send(frame, tx_deadline, MonotonicTime(), iface_mask, qos, flags); + return getDispatcher().getCanIOManager().send(frame, tx_deadline, MonotonicTime(), iface_mask, flags); } #if !UAVCAN_TINY diff --git a/libuavcan/include/uavcan/node/generic_publisher.hpp b/libuavcan/include/uavcan/node/generic_publisher.hpp index 41744a102..b70268b05 100644 --- a/libuavcan/include/uavcan/node/generic_publisher.hpp +++ b/libuavcan/include/uavcan/node/generic_publisher.hpp @@ -41,7 +41,7 @@ class GenericPublisherBase : Noncopyable bool isInited() const; - int doInit(DataTypeKind dtkind, const char* dtname, Qos qos); + int doInit(DataTypeKind dtkind, const char* dtname); MonotonicTime getTxDeadline() const; @@ -93,12 +93,6 @@ class UAVCAN_EXPORT GenericPublisher : public GenericPublisherBase ZeroTransferBuffer, StaticTransferBuffer::Result> >::Result Buffer; - enum - { - ExtractQosFromDataKind = (DataTypeKind(DataSpec::DataTypeKind) == DataTypeKindMessage) ? - Qos::Volatile : Qos::Persistent - }; - int checkInit(); int doEncode(const DataStruct& message, ITransferBuffer& buffer) const; @@ -158,7 +152,7 @@ int GenericPublisher::checkInit() return 0; } - return doInit(DataTypeKind(DataSpec::DataTypeKind), DataSpec::getDataTypeFullName(), Qos(ExtractQosFromDataKind)); + return doInit(DataTypeKind(DataSpec::DataTypeKind), DataSpec::getDataTypeFullName()); } template diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index 6e0aae7c8..5a7deb6cd 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -37,22 +37,17 @@ struct UAVCAN_EXPORT CanRxFrame : public CanFrame #endif }; -enum Qos { Volatile, Persistent }; - struct CanTxQueueEntry // Not required to be packed - fits the block in any case { MonotonicTime deadline; const CanFrame frame; - uint8_t qos; CanIOFlags flags; - CanTxQueueEntry(const CanFrame& arg_frame, const MonotonicTime arg_deadline, Qos arg_qos, CanIOFlags arg_flags) + CanTxQueueEntry(const CanFrame& arg_frame, const MonotonicTime arg_deadline, CanIOFlags arg_flags) : deadline(arg_deadline) , frame(arg_frame) - , qos(uint8_t(arg_qos)) , flags(arg_flags) { - UAVCAN_ASSERT((qos == Volatile) || (qos == Persistent)); IsDynamicallyAllocatable::check(); } @@ -76,7 +71,7 @@ struct CanTxQueueEntry // Not required to be packed - fits the block in any cas } #if UAVCAN_TOSTRING - std::string toString() const; + std::string toString() const; #endif }; @@ -104,7 +99,7 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree /* Avl Tree allocates the AvlTree::Node, while this(CanTxQueue) allocates the CanTxQueueEntry * Same logic for removal. */ - void push(const CanFrame& frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags); + void push(const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags); void remove(CanTxQueueEntry* entry); uint32_t getRejectedFrameCount() const { return rejected_frames_cnt_; } @@ -176,7 +171,7 @@ class UAVCAN_EXPORT CanIOManager : Noncopyable * negative - failure */ int send(const CanFrame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, - uint8_t iface_mask, Qos qos, CanIOFlags flags); + uint8_t iface_mask, CanIOFlags flags); int receive(CanRxFrame& out_frame, MonotonicTime blocking_deadline, CanIOFlags& out_flags); }; diff --git a/libuavcan/include/uavcan/transport/dispatcher.hpp b/libuavcan/include/uavcan/transport/dispatcher.hpp index a1e750bb2..a8fbc236a 100644 --- a/libuavcan/include/uavcan/transport/dispatcher.hpp +++ b/libuavcan/include/uavcan/transport/dispatcher.hpp @@ -157,7 +157,7 @@ class UAVCAN_EXPORT Dispatcher : Noncopyable /** * Refer to CanIOManager::send() for the parameter description */ - int send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, Qos qos, + int send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, CanIOFlags flags, uint8_t iface_mask); void cleanup(MonotonicTime ts); diff --git a/libuavcan/include/uavcan/transport/transfer_sender.hpp b/libuavcan/include/uavcan/transport/transfer_sender.hpp index f45d81f2c..8a12def12 100644 --- a/libuavcan/include/uavcan/transport/transfer_sender.hpp +++ b/libuavcan/include/uavcan/transport/transfer_sender.hpp @@ -24,7 +24,6 @@ class UAVCAN_EXPORT TransferSender Dispatcher& dispatcher_; TransferPriority priority_; - Qos qos_; TransferCRC crc_base_; DataTypeID data_type_id_; CanIOFlags flags_; @@ -41,30 +40,28 @@ class UAVCAN_EXPORT TransferSender return MonotonicDuration::fromMSec(60 * 1000); } - TransferSender(Dispatcher& dispatcher, const DataTypeDescriptor& data_type, Qos qos, + TransferSender(Dispatcher& dispatcher, const DataTypeDescriptor& data_type, MonotonicDuration max_transfer_interval = getDefaultMaxTransferInterval()) : max_transfer_interval_(max_transfer_interval) , dispatcher_(dispatcher) , priority_(TransferPriority::Default) - , qos_(Qos()) , flags_(CanIOFlags(0)) , iface_mask_(AllIfacesMask) , allow_anonymous_transfers_(false) { - init(data_type, qos); + init(data_type); } TransferSender(Dispatcher& dispatcher, MonotonicDuration max_transfer_interval = getDefaultMaxTransferInterval()) : max_transfer_interval_(max_transfer_interval) , dispatcher_(dispatcher) , priority_(TransferPriority::Default) - , qos_(Qos()) , flags_(CanIOFlags(0)) , iface_mask_(AllIfacesMask) , allow_anonymous_transfers_(false) { } - void init(const DataTypeDescriptor& dtid, Qos qos); + void init(const DataTypeDescriptor& dtid); bool isInitialized() const { return data_type_id_ != DataTypeID(); } diff --git a/libuavcan/src/node/uc_generic_publisher.cpp b/libuavcan/src/node/uc_generic_publisher.cpp index be5e4ddc9..c8a458bc7 100644 --- a/libuavcan/src/node/uc_generic_publisher.cpp +++ b/libuavcan/src/node/uc_generic_publisher.cpp @@ -12,7 +12,7 @@ bool GenericPublisherBase::isInited() const return sender_.isInitialized(); } -int GenericPublisherBase::doInit(DataTypeKind dtkind, const char* dtname, Qos qos) +int GenericPublisherBase::doInit(DataTypeKind dtkind, const char* dtname) { if (isInited()) { @@ -28,7 +28,7 @@ int GenericPublisherBase::doInit(DataTypeKind dtkind, const char* dtname, Qos qo return -ErrUnknownDataType; } - sender_.init(*descr, qos); + sender_.init(*descr); return 0; } diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index 6a4f73a7b..ab9e20ec0 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -15,22 +15,28 @@ namespace uavcan * CanRxFrame */ #if UAVCAN_TOSTRING - -std::string CanRxFrame::toString(StringRepresentation mode) const { +std::string CanRxFrame::toString(StringRepresentation mode) const +{ std::string out = CanFrame::toString(mode); out.reserve(128); - out += " ts_m=" + ts_mono.toString(); + out += " ts_m=" + ts_mono.toString(); out += " ts_utc=" + ts_utc.toString(); out += " iface="; out += char('0' + iface_index); return out; } - #endif /* - * CanTxQueue::Entry + * CanTxQueueEntry */ + #if UAVCAN_TOSTRING +std::string CanTxQueueEntry::toString() const +{ + return frame.toString(); +} +#endif + void CanTxQueueEntry::destroy(CanTxQueueEntry*& obj, IPoolAllocator &allocator) { if (obj != UAVCAN_NULLPTR) { obj->~CanTxQueueEntry(); @@ -39,30 +45,6 @@ void CanTxQueueEntry::destroy(CanTxQueueEntry*& obj, IPoolAllocator &allocator) } } -#if UAVCAN_TOSTRING - -std::string CanTxQueueEntry::toString() const { - std::string str_qos; - switch (qos) { - case Volatile: { - str_qos = " "; - break; - } - case Persistent: { - str_qos = " "; - break; - } - default: { - UAVCAN_ASSERT(0); - str_qos = " "; - break; - } - } - return str_qos + frame.toString(); -} - -#endif - /* * CanTxQueue */ @@ -119,7 +101,7 @@ void CanTxQueue::safeIncrementRejectedFrames() { } } -void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, CanIOFlags flags) { +void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, CanIOFlags flags) { const MonotonicTime timestamp = sysclock_.getMonotonic(); if (timestamp >= tx_deadline) { @@ -135,7 +117,7 @@ void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, Qos qos, return; } - CanTxQueueEntry* entry = new(praw) CanTxQueueEntry(frame, tx_deadline, qos, flags); + CanTxQueueEntry* entry = new(praw) CanTxQueueEntry(frame, tx_deadline, flags); UAVCAN_ASSERT(entry); bool result = AvlTree::insert(entry); @@ -295,7 +277,7 @@ CanIfacePerfCounters CanIOManager::getIfacePerfCounters(uint8_t iface_index) con } int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, - uint8_t iface_mask, Qos qos, CanIOFlags flags) { + uint8_t iface_mask, CanIOFlags flags) { const uint8_t num_ifaces = getNumIfaces(); const uint8_t all_ifaces_mask = uint8_t((1U << num_ifaces) - 1); iface_mask &= all_ifaces_mask; @@ -379,7 +361,7 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton } for (uint8_t i = 0; i < num_ifaces; i++) { if (iface_mask & (1 << i)) { - tx_queues_[i]->push(frame, tx_deadline, qos, flags); + tx_queues_[i]->push(frame, tx_deadline, flags); } } break; diff --git a/libuavcan/src/transport/uc_dispatcher.cpp b/libuavcan/src/transport/uc_dispatcher.cpp index efc66e7fa..d44c647da 100644 --- a/libuavcan/src/transport/uc_dispatcher.cpp +++ b/libuavcan/src/transport/uc_dispatcher.cpp @@ -285,7 +285,7 @@ int Dispatcher::spinOnce() } int Dispatcher::send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, - Qos qos, CanIOFlags flags, uint8_t iface_mask) + CanIOFlags flags, uint8_t iface_mask) { if (frame.getSrcNodeID() != getNodeID()) { @@ -300,7 +300,7 @@ int Dispatcher::send(const Frame& frame, MonotonicTime tx_deadline, MonotonicTim UAVCAN_ASSERT(0); return -ErrLogic; } - return canio_.send(can_frame, tx_deadline, blocking_deadline, iface_mask, qos, flags); + return canio_.send(can_frame, tx_deadline, blocking_deadline, iface_mask, flags); } void Dispatcher::cleanup(MonotonicTime ts) diff --git a/libuavcan/src/transport/uc_transfer_sender.cpp b/libuavcan/src/transport/uc_transfer_sender.cpp index b06a2e6d6..5a9a42a14 100644 --- a/libuavcan/src/transport/uc_transfer_sender.cpp +++ b/libuavcan/src/transport/uc_transfer_sender.cpp @@ -15,11 +15,10 @@ void TransferSender::registerError() const dispatcher_.getTransferPerfCounter().addError(); } -void TransferSender::init(const DataTypeDescriptor& dtid, Qos qos) +void TransferSender::init(const DataTypeDescriptor& dtid) { UAVCAN_ASSERT(!isInitialized()); - qos_ = qos; data_type_id_ = dtid.getID(); crc_base_ = dtid.getSignature().toTransferCRC(); } @@ -71,7 +70,7 @@ int TransferSender::send(const uint8_t* payload, unsigned payload_len, Monotonic const CanIOFlags flags = frame.getSrcNodeID().isUnicast() ? flags_ : (flags_ | CanIOFlagAbortOnError); - return dispatcher_.send(frame, tx_deadline, blocking_deadline, qos_, flags, iface_mask_); + return dispatcher_.send(frame, tx_deadline, blocking_deadline, flags, iface_mask_); } else // Multi Frame Transfer { @@ -105,7 +104,7 @@ int TransferSender::send(const uint8_t* payload, unsigned payload_len, Monotonic while (true) { - const int send_res = dispatcher_.send(frame, tx_deadline, blocking_deadline, qos_, flags_, iface_mask_); + const int send_res = dispatcher_.send(frame, tx_deadline, blocking_deadline, flags_, iface_mask_); if (send_res < 0) { registerError(); diff --git a/libuavcan/test/transport/can/io.cpp b/libuavcan/test/transport/can/io.cpp index 513b42cf9..45abc7d53 100644 --- a/libuavcan/test/transport/can/io.cpp +++ b/libuavcan/test/transport/can/io.cpp @@ -117,7 +117,6 @@ TEST(CanIOManager, Transmission) using uavcan::CanIOManager; using uavcan::CanTxQueue; using uavcan::CanTxQueueEntry; - using uavcan::Qos; // Memory uavcan::PoolAllocator<40 * 64, 64> pool; @@ -141,13 +140,13 @@ TEST(CanIOManager, Transmission) /* * Simple transmission */ - EXPECT_EQ(2, iomgr.send(frames[0], tsMono(100), tsMono(0), ALL_IFACES_MASK, Qos::Volatile, flags)); + EXPECT_EQ(2, iomgr.send(frames[0], tsMono(100), tsMono(0), ALL_IFACES_MASK, flags)); EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[0], 100)); EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 100)); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); - EXPECT_EQ(1, iomgr.send(frames[1], tsMono(200), tsMono(100), 2, Qos::Persistent, flags)); // To #1 only + EXPECT_EQ(1, iomgr.send(frames[1], tsMono(200), tsMono(100), 2, flags)); // To #1 only EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[1], 200)); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(uavcan::CanFrame())); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); @@ -166,7 +165,7 @@ TEST(CanIOManager, Transmission) // Sending to both, #0 blocked driver.ifaces.at(0).writeable = false; - EXPECT_LT(0, iomgr.send(frames[0], tsMono(201), tsMono(200), ALL_IFACES_MASK, Qos::Persistent, flags)); + EXPECT_LT(0, iomgr.send(frames[0], tsMono(201), tsMono(200), ALL_IFACES_MASK, flags)); EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 201)); EXPECT_EQ(200, clockmock.monotonic); EXPECT_EQ(200, clockmock.utc); @@ -178,13 +177,13 @@ TEST(CanIOManager, Transmission) // Sending to both, both blocked driver.ifaces.at(1).writeable = false; - EXPECT_EQ(0, iomgr.send(frames[1], tsMono(777), tsMono(300), ALL_IFACES_MASK, Qos::Volatile, flags)); + EXPECT_EQ(0, iomgr.send(frames[1], tsMono(777), tsMono(300), ALL_IFACES_MASK, flags)); EXPECT_EQ(6, pool.getNumUsedBlocks()); // Total 3 frames in TX queue now EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); // Still 0 EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); // 1!! // Sending to #0, both blocked - EXPECT_EQ(0, iomgr.send(frames[2], tsMono(888), tsMono(400), 1, Qos::Persistent, flags)); + EXPECT_EQ(0, iomgr.send(frames[2], tsMono(888), tsMono(400), 1, flags)); EXPECT_EQ(400, clockmock.monotonic); EXPECT_EQ(400, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); @@ -201,7 +200,7 @@ TEST(CanIOManager, Transmission) driver.ifaces.at(0).writeable = true; driver.ifaces.at(1).writeable = true; // One frame per each iface will be sent: - EXPECT_LT(0, iomgr.send(frames[0], tsMono(999), tsMono(500), 2, Qos::Persistent, flags)); + EXPECT_LT(0, iomgr.send(frames[0], tsMono(999), tsMono(500), 2, flags)); EXPECT_TRUE(driver.ifaces.at(0).matchAndPopTx(frames[1], 777)); // Note that frame[0] on iface #0 has expired EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 999)); // In different order due to prioritization EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); @@ -232,10 +231,10 @@ TEST(CanIOManager, Transmission) driver.ifaces.at(1).writeable = false; // Sending 5 frames, one will be rejected - EXPECT_EQ(0, iomgr.send(frames[2], tsMono(2222), tsMono(1000), ALL_IFACES_MASK, Qos::Persistent, flags)); - EXPECT_EQ(0, iomgr.send(frames[0], tsMono(3333), tsMono(1100), 2, Qos::Persistent, flags)); + EXPECT_EQ(0, iomgr.send(frames[2], tsMono(2222), tsMono(1000), ALL_IFACES_MASK, flags)); + EXPECT_EQ(0, iomgr.send(frames[0], tsMono(3333), tsMono(1100), 2, flags)); // One frame kicked here: - EXPECT_EQ(0, iomgr.send(frames[1], tsMono(4444), tsMono(1200), ALL_IFACES_MASK, Qos::Volatile, flags)); + EXPECT_EQ(0, iomgr.send(frames[1], tsMono(4444), tsMono(1200), ALL_IFACES_MASK, flags)); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[1])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); @@ -273,7 +272,7 @@ TEST(CanIOManager, Transmission) EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[1])); // State checks - EXPECT_EQ(2, pool.getNumUsedBlocks()); // TX queue is not empty now, contains the pending frames[2] because of QoS changes stated aboce + EXPECT_EQ(2, pool.getNumUsedBlocks()); // TX queue is not empty now, contains the pending frames[2] because of QoS changes stated above EXPECT_EQ(1200, clockmock.monotonic); EXPECT_EQ(1200, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); @@ -288,7 +287,7 @@ TEST(CanIOManager, Transmission) driver.select_failure = true; EXPECT_EQ(-uavcan::ErrDriver, iomgr.receive(rx_frame, tsMono(2000), flags)); EXPECT_EQ(-uavcan::ErrDriver, - iomgr.send(frames[0], tsMono(2100), tsMono(2000), ALL_IFACES_MASK, Qos::Volatile, flags)); + iomgr.send(frames[0], tsMono(2100), tsMono(2000), ALL_IFACES_MASK, flags)); EXPECT_EQ(1200, clockmock.monotonic); EXPECT_EQ(1200, clockmock.utc); ASSERT_EQ(0, flags); @@ -302,7 +301,7 @@ TEST(CanIOManager, Transmission) driver.ifaces.at(0).tx_failure = true; driver.ifaces.at(1).tx_failure = true; // Non-blocking - return < 0 - EXPECT_GE(0, iomgr.send(frames[0], tsMono(2200), tsMono(0), ALL_IFACES_MASK, Qos::Persistent, flags)); + EXPECT_GE(0, iomgr.send(frames[0], tsMono(2200), tsMono(0), ALL_IFACES_MASK, flags)); EXPECT_TRUE(driver.ifaces.at(0).matchPendingTx(frames[0])); EXPECT_TRUE(driver.ifaces.at(1).matchPendingTx(frames[0])); @@ -334,7 +333,6 @@ TEST(CanIOManager, Loopback) using uavcan::CanIOManager; using uavcan::CanTxQueue; using uavcan::CanTxQueueEntry; - using uavcan::Qos; using uavcan::CanFrame; using uavcan::CanRxFrame; @@ -359,14 +357,14 @@ TEST(CanIOManager, Loopback) CanRxFrame rfr2; uavcan::CanIOFlags flags = 0; - ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, Qos::Volatile, uavcan::CanIOFlagLoopback)); + ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, uavcan::CanIOFlagLoopback)); ASSERT_LE(0, iomgr.receive(rfr1, tsMono(100), flags)); ASSERT_EQ(uavcan::CanIOFlagLoopback, flags); ASSERT_TRUE(rfr1 == fr1); flags = 0; - ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, Qos::Volatile, uavcan::CanIOFlagLoopback)); - ASSERT_EQ(1, iomgr.send(fr2, tsMono(1000), tsMono(0), 1, Qos::Persistent, uavcan::CanIOFlagLoopback)); + ASSERT_EQ(1, iomgr.send(fr1, tsMono(1000), tsMono(0), 1, uavcan::CanIOFlagLoopback)); + ASSERT_EQ(1, iomgr.send(fr2, tsMono(1000), tsMono(0), 1, uavcan::CanIOFlagLoopback)); ASSERT_LE(0, iomgr.receive(rfr1, tsMono(100), flags)); ASSERT_EQ(uavcan::CanIOFlagLoopback, flags); ASSERT_LE(0, iomgr.receive(rfr2, tsMono(100), flags)); diff --git a/libuavcan/test/transport/can/tx_queue.cpp b/libuavcan/test/transport/can/tx_queue.cpp index f09b1e9d3..944e0f92e 100644 --- a/libuavcan/test/transport/can/tx_queue.cpp +++ b/libuavcan/test/transport/can/tx_queue.cpp @@ -12,7 +12,6 @@ TEST(CanTxQueue, TxQueue) using uavcan::CanTxQueue; using uavcan::CanTxQueueEntry; using uavcan::CanFrame; - using uavcan::Qos; ASSERT_GE(40, sizeof(CanTxQueueEntry)); // should be true for any platforms, though not required @@ -38,7 +37,7 @@ TEST(CanTxQueue, TxQueue) /* * Basic priority insertion */ - queue.push(f4, tsMono(100), Qos::Persistent, flags); + queue.push(f4, tsMono(100), flags); EXPECT_FALSE(queue.isEmpty()); EXPECT_TRUE(queue.contains(f4)); EXPECT_EQ(1, queue.getSize()); @@ -49,17 +48,17 @@ TEST(CanTxQueue, TxQueue) EXPECT_TRUE(queue.topPriorityHigherOrEqual(f4)); // Equal EXPECT_FALSE(queue.topPriorityHigherOrEqual(f3)); - queue.push(f3, tsMono(200), Qos::Persistent, flags); + queue.push(f3, tsMono(200), flags); EXPECT_EQ(f3, queue.peek()->frame); EXPECT_EQ(2, queue.getSize()); - queue.push(f0, tsMono(300), Qos::Volatile, flags); + queue.push(f0, tsMono(300), flags); EXPECT_EQ(f0, queue.peek()->frame); EXPECT_EQ(3, queue.getSize()); - queue.push(f1, tsMono(400), Qos::Volatile, flags); + queue.push(f1, tsMono(400), flags); EXPECT_EQ(f0, queue.peek()->frame); // Still f0, since it is highest EXPECT_TRUE(queue.topPriorityHigherOrEqual(f0)); // Equal EXPECT_TRUE(queue.topPriorityHigherOrEqual(f1)); @@ -112,8 +111,8 @@ TEST(CanTxQueue, TxQueue) * Expiration Auto Remove on Peek */ - queue.push(f0, tsMono(999), Qos::Persistent, flags); - queue.push(f4, tsMono(101), Qos::Persistent, flags); + queue.push(f0, tsMono(999), flags); + queue.push(f4, tsMono(101), flags); clockmock.monotonic = 102; // make f4 expire EXPECT_TRUE(queue.contains(f0)); @@ -133,7 +132,7 @@ TEST(CanTxQueue, TxQueue) EXPECT_EQ(0, queue.getSize()); EXPECT_EQ(0, pool.getNumUsedBlocks()); - queue.push(f4, tsMono(98), Qos::Persistent, flags); // already expired + queue.push(f4, tsMono(98), flags); // already expired EXPECT_FALSE(queue.peek()); EXPECT_EQ(1, queue.getRejectedFrameCount()); @@ -144,20 +143,20 @@ TEST(CanTxQueue, TxQueue) * Add multiple so that we reach OOM */ - queue.push(f0, tsMono(900), Qos::Persistent, flags); + queue.push(f0, tsMono(900), flags); EXPECT_EQ(2, pool.getNumUsedBlocks()); - queue.push(f1, tsMono(1000), Qos::Persistent, flags); + queue.push(f1, tsMono(1000), flags); EXPECT_EQ(4, pool.getNumUsedBlocks()); - queue.push(f2, tsMono(1100), Qos::Persistent, flags); + queue.push(f2, tsMono(1100), flags); EXPECT_EQ(6, pool.getNumUsedBlocks()); - queue.push(f3, tsMono(1200), Qos::Persistent, flags); + queue.push(f3, tsMono(1200), flags); EXPECT_EQ(8, pool.getNumUsedBlocks()); EXPECT_TRUE(queue.contains(f3)); - queue.push(f4, tsMono(1300), Qos::Persistent, flags); + queue.push(f4, tsMono(1300), flags); EXPECT_EQ(8, pool.getNumUsedBlocks()); EXPECT_FALSE(queue.contains(f4)); diff --git a/libuavcan/test/transport/dispatcher.cpp b/libuavcan/test/transport/dispatcher.cpp index 00c0ac49c..29883228d 100644 --- a/libuavcan/test/transport/dispatcher.cpp +++ b/libuavcan/test/transport/dispatcher.cpp @@ -281,7 +281,7 @@ TEST(Dispatcher, Transmission) ASSERT_TRUE(dispatcher.hasPublisher(123)); ASSERT_FALSE(dispatcher.hasPublisher(456)); - ASSERT_EQ(2, dispatcher.send(frame, TX_DEADLINE, tsMono(0), uavcan::Qos::Volatile, 0, 0xFF)); + ASSERT_EQ(2, dispatcher.send(frame, TX_DEADLINE, tsMono(0), 0, 0xFF)); /* * Validation @@ -376,7 +376,7 @@ TEST(Dispatcher, Loopback) ASSERT_TRUE(listener.last_frame == uavcan::RxFrame()); - ASSERT_LE(0, dispatcher.send(frame, tsMono(1000), tsMono(0), uavcan::Qos::Persistent, + ASSERT_LE(0, dispatcher.send(frame, tsMono(1000), tsMono(0), uavcan::CanIOFlagLoopback, 0xFF)); ASSERT_EQ(0, dispatcher.spin(tsMono(1000))); diff --git a/libuavcan/test/transport/transfer_sender.cpp b/libuavcan/test/transport/transfer_sender.cpp index 56eafa971..6761857ca 100644 --- a/libuavcan/test/transport/transfer_sender.cpp +++ b/libuavcan/test/transport/transfer_sender.cpp @@ -52,8 +52,8 @@ TEST(TransferSender, Basic) uavcan::TransferSender senders[2] = { - uavcan::TransferSender(dispatcher_tx, TYPES[0], uavcan::Qos ::Volatile), - uavcan::TransferSender(dispatcher_tx, TYPES[1], uavcan::Qos ::Persistent) + uavcan::TransferSender(dispatcher_tx, TYPES[0]), + uavcan::TransferSender(dispatcher_tx, TYPES[1]) }; static const std::string DATA[4] = @@ -199,7 +199,7 @@ TEST(TransferSender, Loopback) uavcan::DataTypeDescriptor desc = makeDataType(uavcan::DataTypeKindMessage, 1, "Foobar"); - uavcan::TransferSender sender(dispatcher, desc, uavcan::Qos ::Volatile); + uavcan::TransferSender sender(dispatcher, desc); sender.setCanIOFlags(uavcan::CanIOFlagLoopback); ASSERT_EQ(uavcan::CanIOFlagLoopback, sender.getCanIOFlags()); @@ -234,8 +234,7 @@ TEST(TransferSender, PassiveMode) uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock); - uavcan::TransferSender sender(dispatcher, makeDataType(uavcan::DataTypeKindMessage, 123), - uavcan::Qos ::Volatile); + uavcan::TransferSender sender(dispatcher, makeDataType(uavcan::DataTypeKindMessage, 123)); static const uint8_t Payload[] = {1, 2, 3, 4, 5}; diff --git a/libuavcan_drivers/linux/apps/test_multithreading.cpp b/libuavcan_drivers/linux/apps/test_multithreading.cpp index 9f1228365..27f5bdc70 100644 --- a/libuavcan_drivers/linux/apps/test_multithreading.cpp +++ b/libuavcan_drivers/linux/apps/test_multithreading.cpp @@ -159,7 +159,7 @@ class VirtualCanIface : public uavcan::ICanIface, int16_t send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags) override { std::lock_guard lock(mutex_); - prioritized_tx_queue_.push(frame, tx_deadline, uavcan::Qos::Volatile, flags); + prioritized_tx_queue_.push(frame, tx_deadline, flags); return 1; } @@ -226,8 +226,7 @@ class VirtualCanIface : public uavcan::ICanIface, UAVCAN_TRACE("VirtualCanIface", "TX injection [iface=0x%02x]: %s", unsigned(iface_mask), e->toString().c_str()); - const int res = main_node.injectTxFrame(e->frame, e->deadline, iface_mask, - uavcan::Qos(e->qos), e->flags); + const int res = main_node.injectTxFrame(e->frame, e->deadline, iface_mask, e->flags); prioritized_tx_queue_.remove(e); if (res <= 0) { From 5b207dad534e0a3f23f7e0a58fe51bfa7d9675f6 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Sun, 24 Feb 2019 00:28:11 +0200 Subject: [PATCH 19/23] Fix explicit this --- libuavcan/include/uavcan/transport/can_io.hpp | 8 ++++---- libuavcan/src/transport/uc_can_io.cpp | 20 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index 5a7deb6cd..eed012a11 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -89,10 +89,10 @@ class UAVCAN_EXPORT CanTxQueue : public AvlTree AvlTree::Node* searchForNonExpiredMax(Node* n); public: - CanTxQueue(IPoolAllocator& allocator, ISystemClock& sysclock, std::size_t allocator_quota) - : AvlTree(allocator, allocator_quota) - , sysclock_(sysclock) - , rejected_frames_cnt_(0) + CanTxQueue(IPoolAllocator& allocator, ISystemClock& sysclock, std::size_t allocator_quota) : + AvlTree(allocator, allocator_quota), + sysclock_(sysclock), + rejected_frames_cnt_(0) {} ~CanTxQueue() override; diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index ab9e20ec0..9e604b82e 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -50,7 +50,7 @@ void CanTxQueueEntry::destroy(CanTxQueueEntry*& obj, IPoolAllocator &allocator) */ CanTxQueue::~CanTxQueue() { // Remove all nodes & node contents of the tree without performing re-balancing steps - postOrderTraverseEntryCleanup(this->root_); + postOrderTraverseEntryCleanup(root_); // Step 2: AvlTree destructor is called to remove all the Node* (automatically after) } @@ -61,11 +61,11 @@ void CanTxQueue::postOrderTraverseEntryCleanup(Node* n) { postOrderTraverseEntryCleanup(n->left); postOrderTraverseEntryCleanup(n->right); - CanTxQueueEntry::destroy(n->data, this->allocator_); + CanTxQueueEntry::destroy(n->data, allocator_); } bool CanTxQueue::contains(const CanFrame& frame) const { - Node* n = this->root_; + Node* n = root_; while (n != UAVCAN_NULLPTR) { if (frame.priorityHigherThan(n->data->frame)) { @@ -110,7 +110,7 @@ void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, CanIOFla return; } - void* praw = this->allocator_.allocate(sizeof(CanTxQueueEntry)); + void* praw = allocator_.allocate(sizeof(CanTxQueueEntry)); if (praw == UAVCAN_NULLPTR) { UAVCAN_TRACE("CanTxQueue", "Push rejected: OOM (CanTxQueueEntry)"); safeIncrementRejectedFrames(); @@ -125,7 +125,7 @@ void CanTxQueue::push(const CanFrame &frame, MonotonicTime tx_deadline, CanIOFla /* AVL Tree could not allocate a new node */ UAVCAN_TRACE("CanTxQueue", "Push rejected: OOM (AvlTree::Node)"); safeIncrementRejectedFrames(); - CanTxQueueEntry::destroy(entry, this->allocator_); + CanTxQueueEntry::destroy(entry, allocator_); } } @@ -137,11 +137,11 @@ void CanTxQueue::remove(CanTxQueueEntry* entry) { // Make the AvlTree remove the specific entry deleting it's Node * this->AvlTree::removeEntry(entry); // Then let the entry destroy it's own contents - CanTxQueueEntry::destroy(entry, this->allocator_); + CanTxQueueEntry::destroy(entry, allocator_); } CanTxQueueEntry* CanTxQueue::peek() { - Node* maxNode = searchForNonExpiredMax(this->root_); + Node* maxNode = searchForNonExpiredMax(root_); if (maxNode == UAVCAN_NULLPTR) { return UAVCAN_NULLPTR; @@ -166,14 +166,14 @@ uavcan::AvlTree::Node* CanTxQueue::searchForNonExpiredM const MonotonicTime timestamp = sysclock_.getMonotonic(); while(n->data->isExpired(timestamp)) { - this->remove(n->data); - return searchForNonExpiredMax(this->root_); + remove(n->data); + return searchForNonExpiredMax(root_); } while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)) { CanTxQueueEntry* expiredEntry = n->data; n->right = this->AvlTree::removeNode(n, n->data); - CanTxQueueEntry::destroy(expiredEntry, this->allocator_); + CanTxQueueEntry::destroy(expiredEntry, allocator_); } Node* r = searchForNonExpiredMax(n->right); From d5a21fe626f98cf6730196e3dd5244d8032d61ef Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Thu, 28 Feb 2019 14:37:27 +0200 Subject: [PATCH 20/23] Remove one reduntant static cast, add suggested change on balanceOf --- libuavcan/include/uavcan/transport/can_io.hpp | 2 +- libuavcan/include/uavcan/util/avl_tree.hpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index eed012a11..83d33e2c4 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -37,7 +37,7 @@ struct UAVCAN_EXPORT CanRxFrame : public CanFrame #endif }; -struct CanTxQueueEntry // Not required to be packed - fits the block in any case +struct UAVCAN_EXPORT CanTxQueueEntry // Not required to be packed - fits the block in any case { MonotonicTime deadline; const CanFrame frame; diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index 0eef4f5b6..6e2452854 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -81,11 +81,12 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return 0; } - return static_cast(heightOf(n->left) - heightOf(n->right)); + const int32_t diff = heightOf(n->left) - heightOf(n->right); + return static_cast(std::max(-2, std::min(2, diff))); } static int16_t maxOf(int16_t a, int16_t b) { - return static_cast(a > b ? a : b); + return a > b ? a : b; } static Node* rotateRight(Node* y) { From 5df8572aef7cab51e8227026a44db1a4be8c8ed7 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Fri, 1 Mar 2019 12:17:58 +0200 Subject: [PATCH 21/23] Braces revert for canio manager The autoformatter has to be fixed asap --- libuavcan/src/transport/uc_can_io.cpp | 146 +++++++++++++++++--------- 1 file changed, 98 insertions(+), 48 deletions(-) diff --git a/libuavcan/src/transport/uc_can_io.cpp b/libuavcan/src/transport/uc_can_io.cpp index 9e604b82e..4f4123373 100644 --- a/libuavcan/src/transport/uc_can_io.cpp +++ b/libuavcan/src/transport/uc_can_io.cpp @@ -189,43 +189,52 @@ uavcan::AvlTree::Node* CanTxQueue::searchForNonExpiredM * CanIOManager */ int -CanIOManager::sendToIface(uint8_t iface_index, const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags) { +CanIOManager::sendToIface(uint8_t iface_index, const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags) +{ UAVCAN_ASSERT(iface_index < MaxCanIfaces); ICanIface *const iface = driver_.getIface(iface_index); - if (iface == UAVCAN_NULLPTR) { + if (iface == UAVCAN_NULLPTR) + { UAVCAN_ASSERT(0); // Nonexistent interface return -ErrLogic; } const int res = iface->send(frame, tx_deadline, flags); - if (res != 1) { + if (res != 1) + { UAVCAN_TRACE("CanIOManager", "Send failed: code %i, iface %i, frame %s", res, iface_index, frame.toString().c_str()); } - if (res > 0) { + if (res > 0) + { counters_[iface_index].frames_tx += unsigned(res); } return res; } -int CanIOManager::sendFromTxQueue(uint8_t iface_index) { +int CanIOManager::sendFromTxQueue(uint8_t iface_index) +{ UAVCAN_ASSERT(iface_index < MaxCanIfaces); CanTxQueueEntry* entry = tx_queues_[iface_index]->peek(); - if (entry == UAVCAN_NULLPTR) { + if (entry == UAVCAN_NULLPTR) + { return 0; } const int res = sendToIface(iface_index, entry->frame, entry->deadline, entry->flags); - if (res > 0) { + if (res > 0) + { tx_queues_[iface_index]->remove(entry); } return res; } int CanIOManager::callSelect(CanSelectMasks &inout_masks, const CanFrame *(&pending_tx)[MaxCanIfaces], - MonotonicTime blocking_deadline) { + MonotonicTime blocking_deadline) +{ const CanSelectMasks in_masks = inout_masks; const int res = driver_.select(inout_masks, pending_tx, blocking_deadline); - if (res < 0) { + if (res < 0) + { return -ErrDriver; } @@ -236,36 +245,45 @@ int CanIOManager::callSelect(CanSelectMasks &inout_masks, const CanFrame *(&pend CanIOManager::CanIOManager(ICanDriver& driver, IPoolAllocator& allocator, ISystemClock& sysclock, std::size_t mem_blocks_per_iface) - : driver_(driver), sysclock_(sysclock), num_ifaces_(driver.getNumIfaces()) { - if (num_ifaces_ < 1 || num_ifaces_ > MaxCanIfaces) { + : driver_(driver), sysclock_(sysclock), num_ifaces_(driver.getNumIfaces()) +{ + if (num_ifaces_ < 1 || num_ifaces_ > MaxCanIfaces) + { handleFatalError("Num ifaces"); } - if (mem_blocks_per_iface == 0) { + if (mem_blocks_per_iface == 0) + { mem_blocks_per_iface = allocator.getBlockCapacity() / (num_ifaces_ + 1U) + 1U; } UAVCAN_TRACE("CanIOManager", "Memory blocks per iface: %u, total: %u", unsigned(mem_blocks_per_iface), unsigned(allocator.getBlockCapacity())); - for (int i = 0; i < num_ifaces_; i++) { + for (int i = 0; i < num_ifaces_; i++) + { tx_queues_[i].construct (allocator, sysclock, mem_blocks_per_iface); } } -uint8_t CanIOManager::makePendingTxMask() const { +uint8_t CanIOManager::makePendingTxMask() const +{ uint8_t write_mask = 0; - for (uint8_t i = 0; i < getNumIfaces(); i++) { - if (!tx_queues_[i]->isEmpty()) { + for (uint8_t i = 0; i < getNumIfaces(); i++) + { + if (!tx_queues_[i]->isEmpty()) + { write_mask = uint8_t(write_mask | (1 << i)); } } return write_mask; } -CanIfacePerfCounters CanIOManager::getIfacePerfCounters(uint8_t iface_index) const { +CanIfacePerfCounters CanIOManager::getIfacePerfCounters(uint8_t iface_index) const +{ ICanIface *const iface = driver_.getIface(iface_index); - if (iface == UAVCAN_NULLPTR || iface_index >= MaxCanIfaces) { + if (iface == UAVCAN_NULLPTR || iface_index >= MaxCanIfaces) + { UAVCAN_ASSERT(0); return CanIfacePerfCounters(); } @@ -277,12 +295,14 @@ CanIfacePerfCounters CanIOManager::getIfacePerfCounters(uint8_t iface_index) con } int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, - uint8_t iface_mask, CanIOFlags flags) { + uint8_t iface_mask, CanIOFlags flags) +{ const uint8_t num_ifaces = getNumIfaces(); const uint8_t all_ifaces_mask = uint8_t((1U << num_ifaces) - 1); iface_mask &= all_ifaces_mask; - if (blocking_deadline > tx_deadline) { + if (blocking_deadline > tx_deadline) + { blocking_deadline = tx_deadline; } @@ -290,7 +310,8 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton while (true) // Somebody please refactor this. { - if (iface_mask == 0) { + if (iface_mask == 0) + { break; } @@ -301,7 +322,8 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton // This is needed to avoid inner priority inversion in the TX queue. // This is explained in the section 4.4.3.3 of the spec. const CanFrame* pending_tx[MaxCanIfaces] = {}; - for (int i = 0; i < num_ifaces; i++) { + for (int i = 0; i < num_ifaces; i++) + { CanTxQueue &q = *tx_queues_[i]; CanTxQueueEntry* peek_entry = q.peek(); const CanFrame *peek_frame = peek_entry == UAVCAN_NULLPTR ? UAVCAN_NULLPTR : &peek_entry->frame; @@ -311,42 +333,55 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton bool has_priority = false; // This may seem duplicate of topPriorityHigherOrEqual but we want to avoid traversing the queue again - if (peek_entry != UAVCAN_NULLPTR) { + if (peek_entry != UAVCAN_NULLPTR) + { has_priority = !frame.priorityHigherThan(*peek_frame); } pending_tx[i] = has_priority ? peek_frame : &frame; - } else { + } + else + { pending_tx[i] = peek_frame; } } const int select_res = callSelect(masks, pending_tx, blocking_deadline); - if (select_res < 0) { + if (select_res < 0) + { return -ErrDriver; } UAVCAN_ASSERT(masks.read == 0); } // Transmission - for (uint8_t i = 0; i < num_ifaces; i++) { - if (masks.write & (1 << i)) { + for (uint8_t i = 0; i < num_ifaces; i++) + { + if (masks.write & (1 << i)) + { int res = 0; - if (iface_mask & (1 << i)) { - if (tx_queues_[i]->topPriorityHigherOrEqual(frame)) { + if (iface_mask & (1 << i)) + { + if (tx_queues_[i]->topPriorityHigherOrEqual(frame)) + { res = sendFromTxQueue( i); // May return 0 if nothing to transmit (e.g. expired) } - if (res <= 0) { + if (res <= 0) + { res = sendToIface(i, frame, tx_deadline, flags); - if (res > 0) { + if (res > 0) + { iface_mask &= uint8_t(~(1 << i)); // Mark transmitted } } - } else { + } + else + { res = sendFromTxQueue(i); } - if (res > 0) { + if (res > 0) + { retval++; } } @@ -354,13 +389,17 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton // Timeout. Enqueue the frame if wasn't transmitted and leave. const bool timed_out = sysclock_.getMonotonic() >= blocking_deadline; - if (masks.write == 0 || timed_out) { - if (!timed_out) { + if (masks.write == 0 || timed_out) + { + if (!timed_out) + { UAVCAN_TRACE("CanIOManager", "Send: Premature timeout in select(), will try again"); continue; } - for (uint8_t i = 0; i < num_ifaces; i++) { - if (iface_mask & (1 << i)) { + for (uint8_t i = 0; i < num_ifaces; i++) + { + if (iface_mask & (1 << i)) + { tx_queues_[i]->push(frame, tx_deadline, flags); } } @@ -370,10 +409,12 @@ int CanIOManager::send(const CanFrame &frame, MonotonicTime tx_deadline, Monoton return retval; } -int CanIOManager::receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline, CanIOFlags &out_flags) { +int CanIOManager::receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline, CanIOFlags &out_flags) +{ const uint8_t num_ifaces = getNumIfaces(); - while (true) { + while (true) + { CanSelectMasks masks; masks.write = makePendingTxMask(); masks.read = uint8_t((1 << num_ifaces) - 1); @@ -386,36 +427,44 @@ int CanIOManager::receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline } const int select_res = callSelect(masks, pending_tx, blocking_deadline); - if (select_res < 0) { + if (select_res < 0) + { return -ErrDriver; } } // Write - if buffers are not empty, one frame will be sent for each iface per one receive() call - for (uint8_t i = 0; i < num_ifaces; i++) { - if (masks.write & (1 << i)) { + for (uint8_t i = 0; i < num_ifaces; i++) + { + if (masks.write & (1 << i)) + { (void) sendFromTxQueue( i); // It may fail, we don't care. Requested operation was receive, not send. } } // Read - for (uint8_t i = 0; i < num_ifaces; i++) { - if (masks.read & (1 << i)) { + for (uint8_t i = 0; i < num_ifaces; i++) + { + if (masks.read & (1 << i)) + { ICanIface *const iface = driver_.getIface(i); - if (iface == UAVCAN_NULLPTR) { + if (iface == UAVCAN_NULLPTR) + { UAVCAN_ASSERT(0); // Nonexistent interface continue; } const int res = iface->receive(out_frame, out_frame.ts_mono, out_frame.ts_utc, out_flags); - if (res == 0) { + if (res == 0) + { UAVCAN_ASSERT(0); // select() reported that iface has pending RX frames, but receive() returned none continue; } out_frame.iface_index = i; - if ((res > 0) && !(out_flags & CanIOFlagLoopback)) { + if ((res > 0) && !(out_flags & CanIOFlagLoopback)) + { counters_[i].frames_rx += 1; } return (res < 0) ? -ErrDriver : res; @@ -423,7 +472,8 @@ int CanIOManager::receive(CanRxFrame &out_frame, MonotonicTime blocking_deadline } // Timeout checked in the last order - this way we can operate with expired deadline: - if (sysclock_.getMonotonic() >= blocking_deadline) { + if (sysclock_.getMonotonic() >= blocking_deadline) + { break; } } From e61e964c6f6bbade327dbab7e783825c2dedb32a Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Fri, 1 Mar 2019 13:01:28 +0200 Subject: [PATCH 22/23] Add OOM test for AvlTree node allocation --- libuavcan/test/util/avl_tree.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/libuavcan/test/util/avl_tree.cpp b/libuavcan/test/util/avl_tree.cpp index 11059cb20..eb0e0b38e 100644 --- a/libuavcan/test/util/avl_tree.cpp +++ b/libuavcan/test/util/avl_tree.cpp @@ -208,11 +208,34 @@ TEST(AvlTree, MultipleEntriesPerKey) { EXPECT_EQ(5, pool.getNumUsedBlocks()); } +TEST(AvlTree, FailToAllocateNode) { + uavcan::PoolAllocator<64 * 3, 64> pool; // 2 entries + 1 node + + AvlTree tree(pool, 9999); + + void* praw = pool.allocate(sizeof(Entry)); + + Entry* e1 = new (praw) Entry(); + e1->key = 1; + e1->payload = 1; + + praw = pool.allocate(sizeof(Entry)); + Entry* e2 = new (praw) Entry(); + e2->key = 2; + e2->payload = 2; + + EXPECT_TRUE(tree.insert(e1)); + EXPECT_EQ(1, tree.getSize()); + + EXPECT_FALSE(tree.insert(e2)); // OOM -- Will print something like 'UAVCAN: AvlTree: OOM -- Can't allocate Node' + EXPECT_EQ(1, tree.getSize()); +} + /* Check all possible rotation / balancing cases * Test cases from: https://stackoverflow.com/questions/3955680/how-to-check-if-my-avl-tree-implementation-is-correct * */ TEST(AvlTree, AllRotations) { - uavcan::PoolAllocator<64 * 24, 64> pool; // 4 (x2) entries capacity + uavcan::PoolAllocator<64 * 24, 64> pool; AvlTree tree(pool, 99999); EXPECT_TRUE(tree.isEmpty()); From 49861565042b8ee3ff097c6480fee1ba1251a633 Mon Sep 17 00:00:00 2001 From: Theodoros Zarkopafilis Ntakouris Date: Sat, 2 Mar 2019 00:27:43 +0200 Subject: [PATCH 23/23] Remove null check on getSize, revert min-height Of --- libuavcan/include/uavcan/util/avl_tree.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libuavcan/include/uavcan/util/avl_tree.hpp b/libuavcan/include/uavcan/util/avl_tree.hpp index 6e2452854..753a28fc8 100644 --- a/libuavcan/include/uavcan/util/avl_tree.hpp +++ b/libuavcan/include/uavcan/util/avl_tree.hpp @@ -33,7 +33,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable Node* root_; private: - size_t len_ ; + size_t len_ = 0; static int16_t heightOf(const Node* n) { if (n == UAVCAN_NULLPTR) { @@ -81,8 +81,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable return 0; } - const int32_t diff = heightOf(n->left) - heightOf(n->right); - return static_cast(std::max(-2, std::min(2, diff))); + return static_cast(heightOf(n->left) - heightOf(n->right)); } static int16_t maxOf(int16_t a, int16_t b) { @@ -338,7 +337,7 @@ class UAVCAN_EXPORT AvlTree : Noncopyable } size_t getSize() const { - return root_ == UAVCAN_NULLPTR ? 0 : len_; + return len_; } void walkPostOrder(std::function forEach) {