mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-11-01 02:21:35 +08:00
First stab at global refactoring of memory management - the library builds, but unit tests are failing horribly
This commit is contained in:
@@ -239,24 +239,6 @@ static const unsigned MaxCanAcceptanceFilters = UAVCAN_MAX_CAN_ACCEPTANCE_FILTER
|
|||||||
static const unsigned MaxCanAcceptanceFilters = 32;
|
static const unsigned MaxCanAcceptanceFilters = 32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* This constant defines how many receiver objects will be statically pre-allocated by classes that listen to messages
|
|
||||||
* of type uavcan.protocol.NodeStatus from other nodes. If the number of publishers exceeds this value, extra
|
|
||||||
* listeners will be allocated in the dynamic memory (one block per listener).
|
|
||||||
*
|
|
||||||
* The default value is safe to use in any application (since extra memory can always be retrieved from the pool).
|
|
||||||
* Applications that are extremely memory sensitive and are not expected to operate in large networks can override
|
|
||||||
* the default with a lower value.
|
|
||||||
*
|
|
||||||
* Note that nodes that aren't using classes that monitor the network (e.g. NodeStatusMonitor, dynamic node ID
|
|
||||||
* allocation servers) do not depend on this configuration parameter in any way.
|
|
||||||
*/
|
|
||||||
#ifdef UAVCAN_MAX_NETWORK_SIZE_HINT
|
|
||||||
static const unsigned MaxNetworkSizeHint = UAVCAN_MAX_NETWORK_SIZE_HINT;
|
|
||||||
#else
|
|
||||||
static const unsigned MaxNetworkSizeHint = 64; ///< Rest will go into the dynamic memory
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // UAVCAN_BUILD_CONFIG_HPP_INCLUDED
|
#endif // UAVCAN_BUILD_CONFIG_HPP_INCLUDED
|
||||||
|
|||||||
@@ -119,25 +119,16 @@ public:
|
|||||||
* This helper class does some compile-time magic on the transport layer machinery. For authorized personnel only.
|
* This helper class does some compile-time magic on the transport layer machinery. For authorized personnel only.
|
||||||
*/
|
*/
|
||||||
template <typename DataStruct_,
|
template <typename DataStruct_,
|
||||||
unsigned NumStaticReceivers_,
|
template<unsigned> class TransferListenerTemplate = TransferListener
|
||||||
unsigned NumStaticBufs_,
|
|
||||||
template<unsigned, unsigned, unsigned> class TransferListenerTemplate = TransferListener
|
|
||||||
>
|
>
|
||||||
class UAVCAN_EXPORT TransferListenerInstantiationHelper
|
class UAVCAN_EXPORT TransferListenerInstantiationHelper
|
||||||
{
|
{
|
||||||
enum { DataTypeMaxByteLen = BitLenToByteLen<DataStruct_::MaxBitLen>::Result };
|
enum { DataTypeMaxByteLen = BitLenToByteLen<DataStruct_::MaxBitLen>::Result };
|
||||||
enum { NeedsBuffer = int(DataTypeMaxByteLen) > int(GuaranteedPayloadLenPerFrame) };
|
enum { NeedsBuffer = int(DataTypeMaxByteLen) > int(GuaranteedPayloadLenPerFrame) };
|
||||||
enum { BufferSize = NeedsBuffer ? DataTypeMaxByteLen : 0 };
|
enum { BufferSize = NeedsBuffer ? DataTypeMaxByteLen : 0 };
|
||||||
#if UAVCAN_TINY
|
|
||||||
enum { NumStaticBufs = 0 };
|
|
||||||
enum { NumStaticReceivers = 0 };
|
|
||||||
#else
|
|
||||||
enum { NumStaticBufs = NeedsBuffer ? NumStaticBufs_: 0 };
|
|
||||||
enum { NumStaticReceivers = NumStaticReceivers_ };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef TransferListenerTemplate<BufferSize, NumStaticBufs, NumStaticReceivers> Type;
|
typedef TransferListenerTemplate<BufferSize> Type;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -35,22 +35,8 @@ namespace uavcan
|
|||||||
* For simple nodes this number can be reduced.
|
* For simple nodes this number can be reduced.
|
||||||
* For high-traffic nodes the recommended minimum is
|
* For high-traffic nodes the recommended minimum is
|
||||||
* like 16K * (number of CAN ifaces + 1).
|
* like 16K * (number of CAN ifaces + 1).
|
||||||
*
|
|
||||||
* @tparam OutgoingTransferRegistryStaticEntries Number of statically allocated objects
|
|
||||||
* to track Transfer ID for outgoing transfers.
|
|
||||||
* Normally it should be equal to expected number of
|
|
||||||
* publishers and service callers, but it's not necessary.
|
|
||||||
* Additional objects for Transfer ID tracking will
|
|
||||||
* be allocated in the memory pool if needed.
|
|
||||||
* Default value is acceptable for any use case.
|
|
||||||
*/
|
*/
|
||||||
template <std::size_t MemPoolSize_,
|
template <std::size_t MemPoolSize_>
|
||||||
#if UAVCAN_TINY
|
|
||||||
unsigned OutgoingTransferRegistryStaticEntries = 0
|
|
||||||
#else
|
|
||||||
unsigned OutgoingTransferRegistryStaticEntries = 10
|
|
||||||
#endif
|
|
||||||
>
|
|
||||||
class UAVCAN_EXPORT Node : public INode
|
class UAVCAN_EXPORT Node : public INode
|
||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
@@ -61,7 +47,7 @@ class UAVCAN_EXPORT Node : public INode
|
|||||||
typedef PoolAllocator<MemPoolSize, MemPoolBlockSize> Allocator;
|
typedef PoolAllocator<MemPoolSize, MemPoolBlockSize> Allocator;
|
||||||
|
|
||||||
Allocator pool_allocator_;
|
Allocator pool_allocator_;
|
||||||
OutgoingTransferRegistry<OutgoingTransferRegistryStaticEntries> outgoing_trans_reg_;
|
OutgoingTransferRegistry outgoing_trans_reg_;
|
||||||
Scheduler scheduler_;
|
Scheduler scheduler_;
|
||||||
|
|
||||||
NodeStatusProvider proto_nsp_;
|
NodeStatusProvider proto_nsp_;
|
||||||
@@ -260,9 +246,8 @@ public:
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
template <std::size_t MemPoolSize_, unsigned OutgoingTransferRegistryStaticEntries>
|
template <std::size_t MemPoolSize_>
|
||||||
int Node<MemPoolSize_, OutgoingTransferRegistryStaticEntries>::start(
|
int Node<MemPoolSize_>::start(const TransferPriority priority)
|
||||||
const TransferPriority priority)
|
|
||||||
{
|
{
|
||||||
if (started_)
|
if (started_)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,13 +21,11 @@
|
|||||||
namespace uavcan
|
namespace uavcan
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename ServiceDataType, unsigned NumStaticReceiversAndBuffers>
|
template <typename ServiceDataType>
|
||||||
class UAVCAN_EXPORT ServiceResponseTransferListenerInstantiationHelper
|
class UAVCAN_EXPORT ServiceResponseTransferListenerInstantiationHelper
|
||||||
{
|
{
|
||||||
public: // so much templating it hurts
|
public:
|
||||||
typedef typename TransferListenerInstantiationHelper<typename ServiceDataType::Response,
|
typedef typename TransferListenerInstantiationHelper<typename ServiceDataType::Response,
|
||||||
NumStaticReceiversAndBuffers,
|
|
||||||
NumStaticReceiversAndBuffers,
|
|
||||||
TransferListenerWithFilter>::Type Type;
|
TransferListenerWithFilter>::Type Type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -217,24 +215,18 @@ public:
|
|||||||
* In C++11 mode this type defaults to std::function<>.
|
* In C++11 mode this type defaults to std::function<>.
|
||||||
* In C++03 mode this type defaults to a plain function pointer; use binder to
|
* In C++03 mode this type defaults to a plain function pointer; use binder to
|
||||||
* call member functions as callbacks.
|
* call member functions as callbacks.
|
||||||
*
|
|
||||||
* @tparam NumStaticCalls_ Number of concurrent calls that the class will be able to handle without using the
|
|
||||||
* memory pool. Note that this is NOT the maximum possible number of concurrent calls,
|
|
||||||
* there's no such limit. Defaults to one.
|
|
||||||
*/
|
*/
|
||||||
template <typename DataType_,
|
template <typename DataType_,
|
||||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||||
typename Callback_ = std::function<void (const ServiceCallResult<DataType_>&)>,
|
typename Callback_ = std::function<void (const ServiceCallResult<DataType_>&)>
|
||||||
#else
|
#else
|
||||||
typename Callback_ = void (*)(const ServiceCallResult<DataType_>&),
|
typename Callback_ = void (*)(const ServiceCallResult<DataType_>&)
|
||||||
#endif
|
#endif
|
||||||
unsigned NumStaticCalls_ = 1
|
|
||||||
>
|
>
|
||||||
class UAVCAN_EXPORT ServiceClient
|
class UAVCAN_EXPORT ServiceClient
|
||||||
: public GenericSubscriber<DataType_,
|
: public GenericSubscriber<DataType_,
|
||||||
typename DataType_::Response,
|
typename DataType_::Response,
|
||||||
typename ServiceResponseTransferListenerInstantiationHelper<DataType_,
|
typename ServiceResponseTransferListenerInstantiationHelper<DataType_>::Type>
|
||||||
NumStaticCalls_>::Type>
|
|
||||||
, public ServiceClientBase
|
, public ServiceClientBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -244,16 +236,13 @@ public:
|
|||||||
typedef ServiceCallResult<DataType> ServiceCallResultType;
|
typedef ServiceCallResult<DataType> ServiceCallResultType;
|
||||||
typedef Callback_ Callback;
|
typedef Callback_ Callback;
|
||||||
|
|
||||||
enum { NumStaticCalls = NumStaticCalls_ };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef ServiceClient<DataType, Callback> SelfType;
|
typedef ServiceClient<DataType, Callback> SelfType;
|
||||||
typedef GenericPublisher<DataType, RequestType> PublisherType;
|
typedef GenericPublisher<DataType, RequestType> PublisherType;
|
||||||
typedef typename ServiceResponseTransferListenerInstantiationHelper<DataType, NumStaticCalls>::Type
|
typedef typename ServiceResponseTransferListenerInstantiationHelper<DataType>::Type TransferListenerType;
|
||||||
TransferListenerType;
|
|
||||||
typedef GenericSubscriber<DataType, ResponseType, TransferListenerType> SubscriberType;
|
typedef GenericSubscriber<DataType, ResponseType, TransferListenerType> SubscriberType;
|
||||||
|
|
||||||
typedef Multiset<CallState, NumStaticCalls> CallRegistry;
|
typedef Multiset<CallState> CallRegistry;
|
||||||
|
|
||||||
struct TimeoutCallbackCaller
|
struct TimeoutCallbackCaller
|
||||||
{
|
{
|
||||||
@@ -424,8 +413,8 @@ public:
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::invokeCallback(ServiceCallResultType& result)
|
void ServiceClient<DataType_, Callback_>::invokeCallback(ServiceCallResultType& result)
|
||||||
{
|
{
|
||||||
if (coerceOrFallback<bool>(callback_, true))
|
if (coerceOrFallback<bool>(callback_, true))
|
||||||
{
|
{
|
||||||
@@ -437,8 +426,8 @@ void ServiceClient<DataType_, Callback_, NumStaticCalls_>::invokeCallback(Servic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
bool ServiceClient<DataType_, Callback_, NumStaticCalls_>::shouldAcceptFrame(const RxFrame& frame) const
|
bool ServiceClient<DataType_, Callback_>::shouldAcceptFrame(const RxFrame& frame) const
|
||||||
{
|
{
|
||||||
UAVCAN_ASSERT(frame.getTransferType() == TransferTypeServiceResponse); // Other types filtered out by dispatcher
|
UAVCAN_ASSERT(frame.getTransferType() == TransferTypeServiceResponse); // Other types filtered out by dispatcher
|
||||||
|
|
||||||
@@ -447,9 +436,8 @@ bool ServiceClient<DataType_, Callback_, NumStaticCalls_>::shouldAcceptFrame(con
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::
|
void ServiceClient<DataType_, Callback_>::handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response)
|
||||||
handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response)
|
|
||||||
{
|
{
|
||||||
UAVCAN_ASSERT(response.getTransferType() == TransferTypeServiceResponse);
|
UAVCAN_ASSERT(response.getTransferType() == TransferTypeServiceResponse);
|
||||||
|
|
||||||
@@ -460,8 +448,8 @@ handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::handleDeadline(MonotonicTime)
|
void ServiceClient<DataType_, Callback_>::handleDeadline(MonotonicTime)
|
||||||
{
|
{
|
||||||
UAVCAN_TRACE("ServiceClient", "Shared deadline event received");
|
UAVCAN_TRACE("ServiceClient", "Shared deadline event received");
|
||||||
/*
|
/*
|
||||||
@@ -484,8 +472,8 @@ void ServiceClient<DataType_, Callback_, NumStaticCalls_>::handleDeadline(Monoto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
int ServiceClient<DataType_, Callback_, NumStaticCalls_>::addCallState(ServiceCallID call_id)
|
int ServiceClient<DataType_, Callback_>::addCallState(ServiceCallID call_id)
|
||||||
{
|
{
|
||||||
if (call_registry_.isEmpty())
|
if (call_registry_.isEmpty())
|
||||||
{
|
{
|
||||||
@@ -507,16 +495,16 @@ int ServiceClient<DataType_, Callback_, NumStaticCalls_>::addCallState(ServiceCa
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
int ServiceClient<DataType_, Callback_, NumStaticCalls_>::call(NodeID server_node_id, const RequestType& request)
|
int ServiceClient<DataType_, Callback_>::call(NodeID server_node_id, const RequestType& request)
|
||||||
{
|
{
|
||||||
ServiceCallID dummy;
|
ServiceCallID dummy;
|
||||||
return call(server_node_id, request, dummy);
|
return call(server_node_id, request, dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
int ServiceClient<DataType_, Callback_, NumStaticCalls_>::call(NodeID server_node_id, const RequestType& request,
|
int ServiceClient<DataType_, Callback_>::call(NodeID server_node_id, const RequestType& request,
|
||||||
ServiceCallID& out_call_id)
|
ServiceCallID& out_call_id)
|
||||||
{
|
{
|
||||||
if (!coerceOrFallback<bool>(callback_, true))
|
if (!coerceOrFallback<bool>(callback_, true))
|
||||||
{
|
{
|
||||||
@@ -573,8 +561,8 @@ int ServiceClient<DataType_, Callback_, NumStaticCalls_>::call(NodeID server_nod
|
|||||||
return publisher_res;
|
return publisher_res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::cancelCall(ServiceCallID call_id)
|
void ServiceClient<DataType_, Callback_>::cancelCall(ServiceCallID call_id)
|
||||||
{
|
{
|
||||||
call_registry_.removeFirstWhere(CallStateMatchingPredicate(call_id));
|
call_registry_.removeFirstWhere(CallStateMatchingPredicate(call_id));
|
||||||
if (call_registry_.isEmpty())
|
if (call_registry_.isEmpty())
|
||||||
@@ -583,21 +571,21 @@ void ServiceClient<DataType_, Callback_, NumStaticCalls_>::cancelCall(ServiceCal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::cancelAllCalls()
|
void ServiceClient<DataType_, Callback_>::cancelAllCalls()
|
||||||
{
|
{
|
||||||
call_registry_.clear();
|
call_registry_.clear();
|
||||||
SubscriberType::stop();
|
SubscriberType::stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
bool ServiceClient<DataType_, Callback_, NumStaticCalls_>::hasPendingCallToServer(NodeID server_node_id) const
|
bool ServiceClient<DataType_, Callback_>::hasPendingCallToServer(NodeID server_node_id) const
|
||||||
{
|
{
|
||||||
return NULL != call_registry_.find(ServerSearchPredicate(server_node_id));
|
return NULL != call_registry_.find(ServerSearchPredicate(server_node_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
template <typename DataType_, typename Callback_>
|
||||||
ServiceCallID ServiceClient<DataType_, Callback_, NumStaticCalls_>::getCallIDByIndex(unsigned index) const
|
ServiceCallID ServiceClient<DataType_, Callback_>::getCallIDByIndex(unsigned index) const
|
||||||
{
|
{
|
||||||
const CallState* const id = call_registry_.getByIndex(index);
|
const CallState* const id = call_registry_.getByIndex(index);
|
||||||
return (id == NULL) ? ServiceCallID() : id->getCallID();
|
return (id == NULL) ? ServiceCallID() : id->getCallID();
|
||||||
|
|||||||
@@ -77,33 +77,19 @@ public:
|
|||||||
* In C++11 mode this type defaults to std::function<>.
|
* In C++11 mode this type defaults to std::function<>.
|
||||||
* In C++03 mode this type defaults to a plain function pointer; use binder to
|
* In C++03 mode this type defaults to a plain function pointer; use binder to
|
||||||
* call member functions as callbacks.
|
* call member functions as callbacks.
|
||||||
*
|
|
||||||
* @tparam NumStaticReceivers Number of statically allocated receiver objects. If there's more service
|
|
||||||
* clients for this service, extra receivers will be allocated in the memory pool.
|
|
||||||
*
|
|
||||||
* @tparam NumStaticBufs Number of statically allocated receiver buffers. If there's more concurrent
|
|
||||||
* incoming transfers, extra buffers will be allocated in the memory pool.
|
|
||||||
*/
|
*/
|
||||||
template <typename DataType_,
|
template <typename DataType_,
|
||||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||||
typename Callback_ = std::function<void (const ReceivedDataStructure<typename DataType_::Request>&,
|
typename Callback_ = std::function<void (const ReceivedDataStructure<typename DataType_::Request>&,
|
||||||
ServiceResponseDataStructure<typename DataType_::Response>&)>,
|
ServiceResponseDataStructure<typename DataType_::Response>&)>
|
||||||
#else
|
#else
|
||||||
typename Callback_ = void (*)(const ReceivedDataStructure<typename DataType_::Request>&,
|
typename Callback_ = void (*)(const ReceivedDataStructure<typename DataType_::Request>&,
|
||||||
ServiceResponseDataStructure<typename DataType_::Response>&),
|
ServiceResponseDataStructure<typename DataType_::Response>&)
|
||||||
#endif
|
|
||||||
#if UAVCAN_TINY
|
|
||||||
unsigned NumStaticReceivers = 0,
|
|
||||||
unsigned NumStaticBufs = 0
|
|
||||||
#else
|
|
||||||
unsigned NumStaticReceivers = 2,
|
|
||||||
unsigned NumStaticBufs = 1
|
|
||||||
#endif
|
#endif
|
||||||
>
|
>
|
||||||
class UAVCAN_EXPORT ServiceServer
|
class UAVCAN_EXPORT ServiceServer
|
||||||
: public GenericSubscriber<DataType_, typename DataType_::Request,
|
: public GenericSubscriber<DataType_, typename DataType_::Request,
|
||||||
typename TransferListenerInstantiationHelper<typename DataType_::Request,
|
typename TransferListenerInstantiationHelper<typename DataType_::Request>::Type>
|
||||||
NumStaticReceivers, NumStaticBufs>::Type>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef DataType_ DataType;
|
typedef DataType_ DataType;
|
||||||
@@ -112,8 +98,7 @@ public:
|
|||||||
typedef Callback_ Callback;
|
typedef Callback_ Callback;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef typename TransferListenerInstantiationHelper<RequestType, NumStaticReceivers, NumStaticBufs>::Type
|
typedef typename TransferListenerInstantiationHelper<RequestType>::Type TransferListenerType;
|
||||||
TransferListenerType;
|
|
||||||
typedef GenericSubscriber<DataType, RequestType, TransferListenerType> SubscriberType;
|
typedef GenericSubscriber<DataType, RequestType, TransferListenerType> SubscriberType;
|
||||||
typedef GenericPublisher<DataType, ResponseType> PublisherType;
|
typedef GenericPublisher<DataType, ResponseType> PublisherType;
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ namespace uavcan
|
|||||||
* Please refer to the @ref Node<> for documentation concerning the template arguments; refer to the tutorials
|
* Please refer to the @ref Node<> for documentation concerning the template arguments; refer to the tutorials
|
||||||
* to lean how to use libuavcan in multiprocess applications.
|
* to lean how to use libuavcan in multiprocess applications.
|
||||||
*/
|
*/
|
||||||
template <std::size_t MemPoolSize_,
|
template <std::size_t MemPoolSize_>
|
||||||
unsigned OutgoingTransferRegistryStaticEntries = 10
|
|
||||||
>
|
|
||||||
class UAVCAN_EXPORT SubNode : public INode
|
class UAVCAN_EXPORT SubNode : public INode
|
||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
@@ -33,7 +31,7 @@ class UAVCAN_EXPORT SubNode : public INode
|
|||||||
typedef PoolAllocator<MemPoolSize, MemPoolBlockSize> Allocator;
|
typedef PoolAllocator<MemPoolSize, MemPoolBlockSize> Allocator;
|
||||||
|
|
||||||
Allocator pool_allocator_;
|
Allocator pool_allocator_;
|
||||||
OutgoingTransferRegistry<OutgoingTransferRegistryStaticEntries> outgoing_trans_reg_;
|
OutgoingTransferRegistry outgoing_trans_reg_;
|
||||||
Scheduler scheduler_;
|
Scheduler scheduler_;
|
||||||
|
|
||||||
uint64_t internal_failure_cnt_;
|
uint64_t internal_failure_cnt_;
|
||||||
|
|||||||
@@ -34,38 +34,23 @@ namespace uavcan
|
|||||||
* In C++11 mode this type defaults to std::function<>.
|
* In C++11 mode this type defaults to std::function<>.
|
||||||
* In C++03 mode this type defaults to a plain function pointer; use binder to
|
* In C++03 mode this type defaults to a plain function pointer; use binder to
|
||||||
* call member functions as callbacks.
|
* call member functions as callbacks.
|
||||||
*
|
|
||||||
* @tparam NumStaticReceivers Number of statically allocated receiver objects. If there's more publishers
|
|
||||||
* of this message, extra receivers will be allocated in the memory pool.
|
|
||||||
*
|
|
||||||
* @tparam NumStaticBufs Number of statically allocated receiver buffers. If there's more concurrent
|
|
||||||
* incoming transfers, extra buffers will be allocated in the memory pool.
|
|
||||||
*/
|
*/
|
||||||
template <typename DataType_,
|
template <typename DataType_,
|
||||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||||
typename Callback_ = std::function<void (const ReceivedDataStructure<DataType_>&)>,
|
typename Callback_ = std::function<void (const ReceivedDataStructure<DataType_>&)>
|
||||||
#else
|
#else
|
||||||
typename Callback_ = void (*)(const ReceivedDataStructure<DataType_>&),
|
typename Callback_ = void (*)(const ReceivedDataStructure<DataType_>&)
|
||||||
#endif
|
|
||||||
#if UAVCAN_TINY
|
|
||||||
unsigned NumStaticReceivers = 0,
|
|
||||||
unsigned NumStaticBufs = 0
|
|
||||||
#else
|
|
||||||
unsigned NumStaticReceivers = 2,
|
|
||||||
unsigned NumStaticBufs = 1
|
|
||||||
#endif
|
#endif
|
||||||
>
|
>
|
||||||
class UAVCAN_EXPORT Subscriber
|
class UAVCAN_EXPORT Subscriber
|
||||||
: public GenericSubscriber<DataType_, DataType_,
|
: public GenericSubscriber<DataType_, DataType_,
|
||||||
typename TransferListenerInstantiationHelper<DataType_, NumStaticReceivers,
|
typename TransferListenerInstantiationHelper<DataType_>::Type>
|
||||||
NumStaticBufs>::Type>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef Callback_ Callback;
|
typedef Callback_ Callback;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef typename TransferListenerInstantiationHelper<DataType_, NumStaticReceivers, NumStaticBufs>::Type
|
typedef typename TransferListenerInstantiationHelper<DataType_>::Type TransferListenerType;
|
||||||
TransferListenerType;
|
|
||||||
typedef GenericSubscriber<DataType_, DataType_, TransferListenerType> BaseType;
|
typedef GenericSubscriber<DataType_, DataType_, TransferListenerType> BaseType;
|
||||||
|
|
||||||
Callback callback_;
|
Callback callback_;
|
||||||
|
|||||||
@@ -126,8 +126,8 @@ private:
|
|||||||
*/
|
*/
|
||||||
ServiceServer<AppendEntries, AppendEntriesCallback> append_entries_srv_;
|
ServiceServer<AppendEntries, AppendEntriesCallback> append_entries_srv_;
|
||||||
ServiceClient<AppendEntries, AppendEntriesResponseCallback> append_entries_client_;
|
ServiceClient<AppendEntries, AppendEntriesResponseCallback> append_entries_client_;
|
||||||
ServiceServer<RequestVote, RequestVoteCallback> request_vote_srv_;
|
ServiceServer<RequestVote, RequestVoteCallback> request_vote_srv_;
|
||||||
ServiceClient<RequestVote, RequestVoteResponseCallback, MaxNumFollowers> request_vote_client_;
|
ServiceClient<RequestVote, RequestVoteResponseCallback> request_vote_client_;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Methods
|
* Methods
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class NodeDiscoverer : TimerBase
|
|||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Map<NodeID, NodeData, 10> NodeMap;
|
typedef Map<NodeID, NodeData> NodeMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When this number of attempts has been made, the discoverer will give up and assume that the node
|
* When this number of attempts has been made, the discoverer will give up and assume that the node
|
||||||
@@ -101,10 +101,10 @@ class NodeDiscoverer : TimerBase
|
|||||||
IEventTracer& tracer_;
|
IEventTracer& tracer_;
|
||||||
|
|
||||||
BitSet<NodeID::Max + 1> committed_node_mask_; ///< Nodes that are marked will not be queried
|
BitSet<NodeID::Max + 1> committed_node_mask_; ///< Nodes that are marked will not be queried
|
||||||
NodeMap node_map_; ///< Will not work in UAVCAN_TINY
|
NodeMap node_map_;
|
||||||
|
|
||||||
ServiceClient<protocol::GetNodeInfo, GetNodeInfoResponseCallback> get_node_info_client_;
|
ServiceClient<protocol::GetNodeInfo, GetNodeInfoResponseCallback> get_node_info_client_;
|
||||||
Subscriber<protocol::NodeStatus, NodeStatusCallback, MaxNetworkSizeHint, 0> node_status_sub_;
|
Subscriber<protocol::NodeStatus, NodeStatusCallback> node_status_sub_;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Methods
|
* Methods
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ class UAVCAN_EXPORT GlobalTimeSyncSlave : Noncopyable
|
|||||||
void (GlobalTimeSyncSlave::*)(const ReceivedDataStructure<protocol::GlobalTimeSync>&)>
|
void (GlobalTimeSyncSlave::*)(const ReceivedDataStructure<protocol::GlobalTimeSync>&)>
|
||||||
GlobalTimeSyncCallback;
|
GlobalTimeSyncCallback;
|
||||||
|
|
||||||
// Static buffers are explicitly disabled because time should never be unicasted.
|
Subscriber<protocol::GlobalTimeSync, GlobalTimeSyncCallback> sub_;
|
||||||
Subscriber<protocol::GlobalTimeSync, GlobalTimeSyncCallback, 2, 0> sub_;
|
|
||||||
|
|
||||||
UtcTime prev_ts_utc_;
|
UtcTime prev_ts_utc_;
|
||||||
MonotonicTime prev_ts_mono_;
|
MonotonicTime prev_ts_mono_;
|
||||||
|
|||||||
@@ -156,7 +156,6 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { NumStaticCalls = 2 };
|
|
||||||
enum { DefaultNumRequestAttempts = 16 };
|
enum { DefaultNumRequestAttempts = 16 };
|
||||||
enum { DefaultTimerIntervalMSec = 40 }; ///< Read explanation in the class documentation
|
enum { DefaultTimerIntervalMSec = 40 }; ///< Read explanation in the class documentation
|
||||||
|
|
||||||
@@ -165,9 +164,9 @@ private:
|
|||||||
*/
|
*/
|
||||||
Entry entries_[NodeID::Max]; // [1, NodeID::Max]
|
Entry entries_[NodeID::Max]; // [1, NodeID::Max]
|
||||||
|
|
||||||
Multiset<INodeInfoListener*, 2> listeners_;
|
Multiset<INodeInfoListener*> listeners_;
|
||||||
|
|
||||||
ServiceClient<protocol::GetNodeInfo, GetNodeInfoResponseCallback, NumStaticCalls> get_node_info_client_;
|
ServiceClient<protocol::GetNodeInfo, GetNodeInfoResponseCallback> get_node_info_client_;
|
||||||
|
|
||||||
MonotonicDuration request_interval_;
|
MonotonicDuration request_interval_;
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ private:
|
|||||||
|
|
||||||
typedef MethodBinder<NodeStatusMonitor*, void (NodeStatusMonitor::*)(const TimerEvent&)> TimerCallback;
|
typedef MethodBinder<NodeStatusMonitor*, void (NodeStatusMonitor::*)(const TimerEvent&)> TimerCallback;
|
||||||
|
|
||||||
Subscriber<protocol::NodeStatus, NodeStatusCallback, MaxNetworkSizeHint, 0> sub_;
|
Subscriber<protocol::NodeStatus, NodeStatusCallback> sub_;
|
||||||
|
|
||||||
TimerEventForwarder<TimerCallback> timer_;
|
TimerEventForwarder<TimerCallback> timer_;
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ private:
|
|||||||
static const unsigned DefaultAnonMsgMask = 0xFF;
|
static const unsigned DefaultAnonMsgMask = 0xFF;
|
||||||
static const unsigned DefaultAnonMsgID = 0x0;
|
static const unsigned DefaultAnonMsgID = 0x0;
|
||||||
|
|
||||||
typedef uavcan::Multiset<CanFilterConfig, 1> MultisetConfigContainer;
|
typedef uavcan::Multiset<CanFilterConfig> MultisetConfigContainer;
|
||||||
|
|
||||||
static CanFilterConfig mergeFilters(CanFilterConfig &a_, CanFilterConfig &b_);
|
static CanFilterConfig mergeFilters(CanFilterConfig &a_, CanFilterConfig &b_);
|
||||||
static uint8_t countBits(uint32_t n_);
|
static uint8_t countBits(uint32_t n_);
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ public:
|
|||||||
* Outgoing transfer registry keeps track of Transfer ID values for all currently existing local transfer senders.
|
* Outgoing transfer registry keeps track of Transfer ID values for all currently existing local transfer senders.
|
||||||
* If a local transfer sender was inactive for a sufficiently long time, the outgoing transfer registry will
|
* If a local transfer sender was inactive for a sufficiently long time, the outgoing transfer registry will
|
||||||
* remove the respective Transfer ID tracking object.
|
* remove the respective Transfer ID tracking object.
|
||||||
|
*
|
||||||
|
* TODO: Deinterface this.
|
||||||
*/
|
*/
|
||||||
class UAVCAN_EXPORT IOutgoingTransferRegistry
|
class UAVCAN_EXPORT IOutgoingTransferRegistry
|
||||||
{
|
{
|
||||||
@@ -74,7 +76,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <int NumStaticEntries>
|
|
||||||
class UAVCAN_EXPORT OutgoingTransferRegistry : public IOutgoingTransferRegistry, Noncopyable
|
class UAVCAN_EXPORT OutgoingTransferRegistry : public IOutgoingTransferRegistry, Noncopyable
|
||||||
{
|
{
|
||||||
struct Value
|
struct Value
|
||||||
@@ -123,7 +124,7 @@ class UAVCAN_EXPORT OutgoingTransferRegistry : public IOutgoingTransferRegistry,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<OutgoingTransferRegistryKey, Value, NumStaticEntries> map_;
|
Map<OutgoingTransferRegistryKey, Value> map_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OutgoingTransferRegistry(IPoolAllocator& allocator)
|
explicit OutgoingTransferRegistry(IPoolAllocator& allocator)
|
||||||
@@ -140,11 +141,12 @@ public:
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OutgoingTransferRegistry<>
|
* OutgoingTransferRegistry
|
||||||
|
* TODO: deinterface and move to .cpp
|
||||||
*/
|
*/
|
||||||
template <int NumStaticEntries>
|
inline
|
||||||
TransferID* OutgoingTransferRegistry<NumStaticEntries>::accessOrCreate(const OutgoingTransferRegistryKey& key,
|
TransferID* OutgoingTransferRegistry::accessOrCreate(const OutgoingTransferRegistryKey& key,
|
||||||
MonotonicTime new_deadline)
|
MonotonicTime new_deadline)
|
||||||
{
|
{
|
||||||
UAVCAN_ASSERT(!new_deadline.isZero());
|
UAVCAN_ASSERT(!new_deadline.isZero());
|
||||||
Value* p = map_.access(key);
|
Value* p = map_.access(key);
|
||||||
@@ -161,14 +163,14 @@ TransferID* OutgoingTransferRegistry<NumStaticEntries>::accessOrCreate(const Out
|
|||||||
return &p->tid;
|
return &p->tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int NumStaticEntries>
|
inline
|
||||||
bool OutgoingTransferRegistry<NumStaticEntries>::exists(DataTypeID dtid, TransferType tt) const
|
bool OutgoingTransferRegistry::exists(DataTypeID dtid, TransferType tt) const
|
||||||
{
|
{
|
||||||
return NULL != map_.find(ExistenceCheckingPredicate(dtid, tt));
|
return NULL != map_.find(ExistenceCheckingPredicate(dtid, tt));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int NumStaticEntries>
|
inline
|
||||||
void OutgoingTransferRegistry<NumStaticEntries>::cleanup(MonotonicTime ts)
|
void OutgoingTransferRegistry::cleanup(MonotonicTime ts)
|
||||||
{
|
{
|
||||||
map_.removeAllWhere(DeadlineExpiredPredicate(ts));
|
map_.removeAllWhere(DeadlineExpiredPredicate(ts));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,8 +194,6 @@ public:
|
|||||||
|
|
||||||
virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
|
virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
|
||||||
virtual int write(unsigned offset, const uint8_t* data, unsigned len);
|
virtual int write(unsigned offset, const uint8_t* data, unsigned len);
|
||||||
|
|
||||||
bool migrateFrom(const TransferBufferManagerEntry* tbme);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <uint16_t Size>
|
template <uint16_t Size>
|
||||||
@@ -250,11 +248,7 @@ class TransferBufferManagerImpl : public ITransferBufferManager, Noncopyable
|
|||||||
IPoolAllocator& allocator_;
|
IPoolAllocator& allocator_;
|
||||||
const uint16_t max_buf_size_;
|
const uint16_t max_buf_size_;
|
||||||
|
|
||||||
virtual StaticTransferBufferManagerEntryImpl* getStaticByIndex(uint16_t index) const = 0;
|
|
||||||
|
|
||||||
StaticTransferBufferManagerEntryImpl* findFirstStatic(const TransferBufferManagerKey& key);
|
|
||||||
DynamicTransferBufferManagerEntry* findFirstDynamic(const TransferBufferManagerKey& key);
|
DynamicTransferBufferManagerEntry* findFirstDynamic(const TransferBufferManagerKey& key);
|
||||||
void optimizeStorage();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TransferBufferManagerImpl(uint16_t max_buf_size, IPoolAllocator& allocator)
|
TransferBufferManagerImpl(uint16_t max_buf_size, IPoolAllocator& allocator)
|
||||||
@@ -269,49 +263,20 @@ public:
|
|||||||
virtual void remove(const TransferBufferManagerKey& key);
|
virtual void remove(const TransferBufferManagerKey& key);
|
||||||
virtual bool isEmpty() const;
|
virtual bool isEmpty() const;
|
||||||
|
|
||||||
unsigned getNumDynamicBuffers() const;
|
unsigned getNumBuffers() const;
|
||||||
unsigned getNumStaticBuffers() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <uint16_t MaxBufSize, uint8_t NumStaticBufs>
|
|
||||||
class UAVCAN_EXPORT TransferBufferManager : public TransferBufferManagerImpl
|
|
||||||
{
|
|
||||||
mutable StaticTransferBufferManagerEntry<MaxBufSize> static_buffers_[NumStaticBufs];
|
|
||||||
|
|
||||||
virtual StaticTransferBufferManagerEntry<MaxBufSize>* getStaticByIndex(uint16_t index) const
|
|
||||||
{
|
|
||||||
return (index < NumStaticBufs) ? &static_buffers_[index] : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit TransferBufferManager(IPoolAllocator& allocator)
|
|
||||||
: TransferBufferManagerImpl(MaxBufSize, allocator)
|
|
||||||
{
|
|
||||||
#if UAVCAN_TINY
|
|
||||||
StaticAssert<(NumStaticBufs == 0)>::check(); // Static buffers in UAVCAN_TINY mode are not allowed
|
|
||||||
#endif
|
|
||||||
StaticAssert<(MaxBufSize > 0)>::check();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <uint16_t MaxBufSize>
|
template <uint16_t MaxBufSize>
|
||||||
class UAVCAN_EXPORT TransferBufferManager<MaxBufSize, 0> : public TransferBufferManagerImpl
|
class UAVCAN_EXPORT TransferBufferManager : public TransferBufferManagerImpl
|
||||||
{
|
{
|
||||||
virtual StaticTransferBufferManagerEntry<MaxBufSize>* getStaticByIndex(uint16_t) const
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TransferBufferManager(IPoolAllocator& allocator)
|
explicit TransferBufferManager(IPoolAllocator& allocator) :
|
||||||
: TransferBufferManagerImpl(MaxBufSize, allocator)
|
TransferBufferManagerImpl(MaxBufSize, allocator)
|
||||||
{
|
{ }
|
||||||
StaticAssert<(MaxBufSize > 0)>::check();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class UAVCAN_EXPORT TransferBufferManager<0, 0> : public ITransferBufferManager
|
class UAVCAN_EXPORT TransferBufferManager<0> : public ITransferBufferManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TransferBufferManager() { }
|
TransferBufferManager() { }
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public:
|
|||||||
class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListenerBase>, Noncopyable
|
class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListenerBase>, Noncopyable
|
||||||
{
|
{
|
||||||
const DataTypeDescriptor& data_type_;
|
const DataTypeDescriptor& data_type_;
|
||||||
MapBase<TransferBufferManagerKey, TransferReceiver>& receivers_;
|
Map<TransferBufferManagerKey, TransferReceiver>& receivers_;
|
||||||
ITransferBufferManager& bufmgr_;
|
ITransferBufferManager& bufmgr_;
|
||||||
TransferPerfCounter& perf_;
|
TransferPerfCounter& perf_;
|
||||||
const TransferCRC crc_base_; ///< Pre-initialized with data type hash, thus constant
|
const TransferCRC crc_base_; ///< Pre-initialized with data type hash, thus constant
|
||||||
@@ -123,7 +123,7 @@ class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListene
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
TransferListenerBase(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
TransferListenerBase(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
||||||
MapBase<TransferBufferManagerKey, TransferReceiver>& receivers,
|
Map<TransferBufferManagerKey, TransferReceiver>& receivers,
|
||||||
ITransferBufferManager& bufmgr)
|
ITransferBufferManager& bufmgr)
|
||||||
: data_type_(data_type)
|
: data_type_(data_type)
|
||||||
, receivers_(receivers)
|
, receivers_(receivers)
|
||||||
@@ -157,24 +157,18 @@ public:
|
|||||||
/**
|
/**
|
||||||
* This class should be derived by transfer receivers (subscribers, servers).
|
* This class should be derived by transfer receivers (subscribers, servers).
|
||||||
*/
|
*/
|
||||||
template <unsigned MaxBufSize, unsigned NumStaticBufs, unsigned NumStaticReceivers>
|
template <unsigned MaxBufSize>
|
||||||
class UAVCAN_EXPORT TransferListener : public TransferListenerBase
|
class UAVCAN_EXPORT TransferListener : public TransferListenerBase
|
||||||
{
|
{
|
||||||
TransferBufferManager<MaxBufSize, NumStaticBufs> bufmgr_;
|
TransferBufferManager<MaxBufSize> bufmgr_;
|
||||||
Map<TransferBufferManagerKey, TransferReceiver, NumStaticReceivers> receivers_;
|
Map<TransferBufferManagerKey, TransferReceiver> receivers_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TransferListener(TransferPerfCounter& perf, const DataTypeDescriptor& data_type, IPoolAllocator& allocator)
|
TransferListener(TransferPerfCounter& perf, const DataTypeDescriptor& data_type, IPoolAllocator& allocator)
|
||||||
: TransferListenerBase(perf, data_type, receivers_, bufmgr_)
|
: TransferListenerBase(perf, data_type, receivers_, bufmgr_)
|
||||||
, bufmgr_(allocator)
|
, bufmgr_(allocator)
|
||||||
, receivers_(allocator)
|
, receivers_(allocator)
|
||||||
{
|
{ }
|
||||||
#if UAVCAN_TINY
|
|
||||||
StaticAssert<NumStaticBufs == 0>::check();
|
|
||||||
StaticAssert<NumStaticReceivers == 0>::check();
|
|
||||||
#endif
|
|
||||||
StaticAssert<(NumStaticReceivers >= NumStaticBufs)>::check(); // Otherwise it would be meaningless
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~TransferListener()
|
virtual ~TransferListener()
|
||||||
{
|
{
|
||||||
@@ -200,15 +194,15 @@ public:
|
|||||||
/**
|
/**
|
||||||
* This class should be derived by callers.
|
* This class should be derived by callers.
|
||||||
*/
|
*/
|
||||||
template <unsigned MaxBufSize, unsigned NumStaticBufs, unsigned NumStaticReceivers>
|
template <unsigned MaxBufSize>
|
||||||
class UAVCAN_EXPORT TransferListenerWithFilter : public TransferListener<MaxBufSize, NumStaticBufs, NumStaticReceivers>
|
class UAVCAN_EXPORT TransferListenerWithFilter : public TransferListener<MaxBufSize>
|
||||||
{
|
{
|
||||||
const ITransferAcceptanceFilter* filter_;
|
const ITransferAcceptanceFilter* filter_;
|
||||||
|
|
||||||
virtual void handleFrame(const RxFrame& frame);
|
virtual void handleFrame(const RxFrame& frame);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef TransferListener<MaxBufSize, NumStaticBufs, NumStaticReceivers> BaseType;
|
typedef TransferListener<MaxBufSize> BaseType;
|
||||||
|
|
||||||
TransferListenerWithFilter(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
TransferListenerWithFilter(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
||||||
IPoolAllocator& allocator)
|
IPoolAllocator& allocator)
|
||||||
@@ -227,8 +221,8 @@ public:
|
|||||||
/*
|
/*
|
||||||
* TransferListenerWithFilter<>
|
* TransferListenerWithFilter<>
|
||||||
*/
|
*/
|
||||||
template <unsigned MaxBufSize, unsigned NumStaticBufs, unsigned NumStaticReceivers>
|
template <unsigned MaxBufSize>
|
||||||
void TransferListenerWithFilter<MaxBufSize, NumStaticBufs, NumStaticReceivers>::handleFrame(const RxFrame& frame)
|
void TransferListenerWithFilter<MaxBufSize>::handleFrame(const RxFrame& frame)
|
||||||
{
|
{
|
||||||
if (filter_ != NULL)
|
if (filter_ != NULL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ namespace uavcan
|
|||||||
/**
|
/**
|
||||||
* Slow but memory efficient KV container.
|
* Slow but memory efficient KV container.
|
||||||
*
|
*
|
||||||
* KV pairs can be allocated in a static buffer or in the node's memory pool if the static buffer is exhausted.
|
* KV pairs will be allocated in the node's memory pool.
|
||||||
* When a KV pair is deleted from the static buffer, one pair from the memory pool will be moved in the free
|
|
||||||
* slot of the static buffer, so the use of the memory pool is minimized.
|
|
||||||
*
|
*
|
||||||
* Please be aware that this container does not perform any speed optimizations to minimize memory footprint,
|
* Please be aware that this container does not perform any speed optimizations to minimize memory footprint,
|
||||||
* so the complexity of most operations is O(N).
|
* so the complexity of most operations is O(N).
|
||||||
@@ -32,10 +30,8 @@ namespace uavcan
|
|||||||
* Size of Key + Value + padding must not exceed MemPoolBlockSize.
|
* Size of Key + Value + padding must not exceed MemPoolBlockSize.
|
||||||
*/
|
*/
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
class UAVCAN_EXPORT MapBase : Noncopyable
|
class UAVCAN_EXPORT Map : Noncopyable
|
||||||
{
|
{
|
||||||
template <typename, typename, unsigned> friend class Map;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct KVPair
|
struct KVPair
|
||||||
{
|
{
|
||||||
@@ -102,16 +98,9 @@ private:
|
|||||||
|
|
||||||
LinkedListRoot<KVGroup> list_;
|
LinkedListRoot<KVGroup> list_;
|
||||||
IPoolAllocator& allocator_;
|
IPoolAllocator& allocator_;
|
||||||
#if !UAVCAN_TINY
|
|
||||||
KVPair* const static_;
|
|
||||||
const unsigned num_static_entries_;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
KVPair* findKey(const Key& key);
|
KVPair* findKey(const Key& key);
|
||||||
|
|
||||||
#if !UAVCAN_TINY
|
|
||||||
void optimizeStorage();
|
|
||||||
#endif
|
|
||||||
void compact();
|
void compact();
|
||||||
|
|
||||||
struct YesPredicate
|
struct YesPredicate
|
||||||
@@ -119,30 +108,18 @@ private:
|
|||||||
bool operator()(const Key&, const Value&) const { return true; }
|
bool operator()(const Key&, const Value&) const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
|
||||||
#if UAVCAN_TINY
|
|
||||||
MapBase(IPoolAllocator& allocator)
|
|
||||||
: allocator_(allocator)
|
|
||||||
{
|
|
||||||
UAVCAN_ASSERT(Key() == Key());
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
MapBase(KVPair* static_buf, unsigned num_static_entries, IPoolAllocator& allocator)
|
|
||||||
: allocator_(allocator)
|
|
||||||
, static_(static_buf)
|
|
||||||
, num_static_entries_(num_static_entries)
|
|
||||||
{
|
|
||||||
UAVCAN_ASSERT(Key() == Key());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// Derived class destructor must call clear();
|
|
||||||
~MapBase()
|
|
||||||
{
|
|
||||||
UAVCAN_ASSERT(getSize() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Map(IPoolAllocator& allocator) :
|
||||||
|
allocator_(allocator)
|
||||||
|
{
|
||||||
|
UAVCAN_ASSERT(Key() == Key());
|
||||||
|
}
|
||||||
|
|
||||||
|
~Map()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns null pointer if there's no such entry.
|
* Returns null pointer if there's no such entry.
|
||||||
*/
|
*/
|
||||||
@@ -192,69 +169,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool isEmpty() const { return find(YesPredicate()) == NULL; }
|
bool isEmpty() const { return find(YesPredicate()) == NULL; }
|
||||||
|
|
||||||
unsigned getSize() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For testing, do not use directly.
|
* Complexity is O(N).
|
||||||
*/
|
*/
|
||||||
unsigned getNumStaticPairs() const;
|
unsigned getSize() const;
|
||||||
unsigned getNumDynamicPairs() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename Key, typename Value, unsigned NumStaticEntries = 0>
|
|
||||||
class UAVCAN_EXPORT Map : public MapBase<Key, Value>
|
|
||||||
{
|
|
||||||
typename MapBase<Key, Value>::KVPair static_[NumStaticEntries];
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
#if !UAVCAN_TINY
|
|
||||||
|
|
||||||
// This instantiation will not be valid in UAVCAN_TINY mode
|
|
||||||
explicit Map(IPoolAllocator& allocator)
|
|
||||||
: MapBase<Key, Value>(static_, NumStaticEntries, allocator)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~Map() { this->clear(); }
|
|
||||||
|
|
||||||
#endif // !UAVCAN_TINY
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
|
||||||
class UAVCAN_EXPORT Map<Key, Value, 0> : public MapBase<Key, Value>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Map(IPoolAllocator& allocator)
|
|
||||||
#if UAVCAN_TINY
|
|
||||||
: MapBase<Key, Value>(allocator)
|
|
||||||
#else
|
|
||||||
: MapBase<Key, Value>(NULL, 0, allocator)
|
|
||||||
#endif
|
|
||||||
{ }
|
|
||||||
|
|
||||||
~Map() { this->clear(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MapBase<>
|
* Map<>
|
||||||
*/
|
*/
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::findKey(const Key& key)
|
typename Map<Key, Value>::KVPair* Map<Key, Value>::findKey(const Key& key)
|
||||||
{
|
{
|
||||||
#if !UAVCAN_TINY
|
|
||||||
for (unsigned i = 0; i < num_static_entries_; i++)
|
|
||||||
{
|
|
||||||
if (static_[i].match(key))
|
|
||||||
{
|
|
||||||
return static_ + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
KVGroup* p = list_.get();
|
KVGroup* p = list_.get();
|
||||||
while (p)
|
while (p)
|
||||||
{
|
{
|
||||||
@@ -268,64 +196,8 @@ typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::findKey(const Key& ke
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !UAVCAN_TINY
|
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
void MapBase<Key, Value>::optimizeStorage()
|
void Map<Key, Value>::compact()
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
// Looking for first EMPTY static entry
|
|
||||||
KVPair* stat = NULL;
|
|
||||||
for (unsigned i = 0; i < num_static_entries_; i++)
|
|
||||||
{
|
|
||||||
if (static_[i].match(Key()))
|
|
||||||
{
|
|
||||||
stat = static_ + i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (stat == NULL)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Looking for the first NON-EMPTY dynamic entry, erasing immediately
|
|
||||||
KVGroup* p = list_.get();
|
|
||||||
KVPair dyn;
|
|
||||||
while (p)
|
|
||||||
{
|
|
||||||
bool stop = false;
|
|
||||||
for (int i = 0; i < KVGroup::NumKV; i++)
|
|
||||||
{
|
|
||||||
if (!p->kvs[i].match(Key())) // Non empty
|
|
||||||
{
|
|
||||||
dyn = p->kvs[i]; // Copy by value
|
|
||||||
p->kvs[i] = KVPair(); // Erase immediately
|
|
||||||
stop = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (stop)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p = p->getNextListNode();
|
|
||||||
}
|
|
||||||
if (dyn.match(Key()))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrating
|
|
||||||
*stat = dyn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // !UAVCAN_TINY
|
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
|
||||||
void MapBase<Key, Value>::compact()
|
|
||||||
{
|
{
|
||||||
KVGroup* p = list_.get();
|
KVGroup* p = list_.get();
|
||||||
while (p)
|
while (p)
|
||||||
@@ -350,7 +222,7 @@ void MapBase<Key, Value>::compact()
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
Value* MapBase<Key, Value>::access(const Key& key)
|
Value* Map<Key, Value>::access(const Key& key)
|
||||||
{
|
{
|
||||||
UAVCAN_ASSERT(!(key == Key()));
|
UAVCAN_ASSERT(!(key == Key()));
|
||||||
KVPair* const kv = findKey(key);
|
KVPair* const kv = findKey(key);
|
||||||
@@ -358,7 +230,7 @@ Value* MapBase<Key, Value>::access(const Key& key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
Value* MapBase<Key, Value>::insert(const Key& key, const Value& value)
|
Value* Map<Key, Value>::insert(const Key& key, const Value& value)
|
||||||
{
|
{
|
||||||
UAVCAN_ASSERT(!(key == Key()));
|
UAVCAN_ASSERT(!(key == Key()));
|
||||||
remove(key);
|
remove(key);
|
||||||
@@ -381,40 +253,23 @@ Value* MapBase<Key, Value>::insert(const Key& key, const Value& value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
void MapBase<Key, Value>::remove(const Key& key)
|
void Map<Key, Value>::remove(const Key& key)
|
||||||
{
|
{
|
||||||
UAVCAN_ASSERT(!(key == Key()));
|
UAVCAN_ASSERT(!(key == Key()));
|
||||||
KVPair* const kv = findKey(key);
|
KVPair* const kv = findKey(key);
|
||||||
if (kv)
|
if (kv)
|
||||||
{
|
{
|
||||||
*kv = KVPair();
|
*kv = KVPair();
|
||||||
#if !UAVCAN_TINY
|
|
||||||
optimizeStorage();
|
|
||||||
#endif
|
|
||||||
compact();
|
compact();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
template <typename Predicate>
|
template <typename Predicate>
|
||||||
void MapBase<Key, Value>::removeAllWhere(Predicate predicate)
|
void Map<Key, Value>::removeAllWhere(Predicate predicate)
|
||||||
{
|
{
|
||||||
unsigned num_removed = 0;
|
unsigned num_removed = 0;
|
||||||
|
|
||||||
#if !UAVCAN_TINY
|
|
||||||
for (unsigned i = 0; i < num_static_entries_; i++)
|
|
||||||
{
|
|
||||||
if (!static_[i].match(Key()))
|
|
||||||
{
|
|
||||||
if (predicate(static_[i].key, static_[i].value))
|
|
||||||
{
|
|
||||||
num_removed++;
|
|
||||||
static_[i] = KVPair();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
KVGroup* p = list_.get();
|
KVGroup* p = list_.get();
|
||||||
while (p != NULL)
|
while (p != NULL)
|
||||||
{
|
{
|
||||||
@@ -438,30 +293,14 @@ void MapBase<Key, Value>::removeAllWhere(Predicate predicate)
|
|||||||
|
|
||||||
if (num_removed > 0)
|
if (num_removed > 0)
|
||||||
{
|
{
|
||||||
#if !UAVCAN_TINY
|
|
||||||
optimizeStorage();
|
|
||||||
#endif
|
|
||||||
compact();
|
compact();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
template <typename Predicate>
|
template <typename Predicate>
|
||||||
const Key* MapBase<Key, Value>::find(Predicate predicate) const
|
const Key* Map<Key, Value>::find(Predicate predicate) const
|
||||||
{
|
{
|
||||||
#if !UAVCAN_TINY
|
|
||||||
for (unsigned i = 0; i < num_static_entries_; i++)
|
|
||||||
{
|
|
||||||
if (!static_[i].match(Key()))
|
|
||||||
{
|
|
||||||
if (predicate(static_[i].key, static_[i].value))
|
|
||||||
{
|
|
||||||
return &static_[i].key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
KVGroup* p = list_.get();
|
KVGroup* p = list_.get();
|
||||||
while (p != NULL)
|
while (p != NULL)
|
||||||
{
|
{
|
||||||
@@ -485,29 +324,14 @@ const Key* MapBase<Key, Value>::find(Predicate predicate) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
void MapBase<Key, Value>::clear()
|
void Map<Key, Value>::clear()
|
||||||
{
|
{
|
||||||
removeAllWhere(YesPredicate());
|
removeAllWhere(YesPredicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::getByIndex(unsigned index)
|
typename Map<Key, Value>::KVPair* Map<Key, Value>::getByIndex(unsigned index)
|
||||||
{
|
{
|
||||||
#if !UAVCAN_TINY
|
|
||||||
// Checking the static storage
|
|
||||||
for (unsigned i = 0; i < num_static_entries_; i++)
|
|
||||||
{
|
|
||||||
if (!static_[i].match(Key()))
|
|
||||||
{
|
|
||||||
if (index == 0)
|
|
||||||
{
|
|
||||||
return static_ + i;
|
|
||||||
}
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Slowly crawling through the dynamic storage
|
// Slowly crawling through the dynamic storage
|
||||||
KVGroup* p = list_.get();
|
KVGroup* p = list_.get();
|
||||||
while (p != NULL)
|
while (p != NULL)
|
||||||
@@ -534,35 +358,13 @@ typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::getByIndex(unsigned i
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
const typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::getByIndex(unsigned index) const
|
const typename Map<Key, Value>::KVPair* Map<Key, Value>::getByIndex(unsigned index) const
|
||||||
{
|
{
|
||||||
return const_cast<MapBase<Key, Value>*>(this)->getByIndex(index);
|
return const_cast<Map<Key, Value>*>(this)->getByIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
template <typename Key, typename Value>
|
||||||
unsigned MapBase<Key, Value>::getSize() const
|
unsigned Map<Key, Value>::getSize() const
|
||||||
{
|
|
||||||
return getNumStaticPairs() + getNumDynamicPairs();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
|
||||||
unsigned MapBase<Key, Value>::getNumStaticPairs() const
|
|
||||||
{
|
|
||||||
unsigned num = 0;
|
|
||||||
#if !UAVCAN_TINY
|
|
||||||
for (unsigned i = 0; i < num_static_entries_; i++)
|
|
||||||
{
|
|
||||||
if (!static_[i].match(Key()))
|
|
||||||
{
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Key, typename Value>
|
|
||||||
unsigned MapBase<Key, Value>::getNumDynamicPairs() const
|
|
||||||
{
|
{
|
||||||
unsigned num = 0;
|
unsigned num = 0;
|
||||||
KVGroup* p = list_.get();
|
KVGroup* p = list_.get();
|
||||||
|
|||||||
@@ -23,11 +23,9 @@ namespace uavcan
|
|||||||
* Slow but memory efficient unordered multiset. Unlike Map<>, this container does not move objects, so
|
* Slow but memory efficient unordered multiset. Unlike Map<>, this container does not move objects, so
|
||||||
* they don't have to be copyable.
|
* they don't have to be copyable.
|
||||||
*
|
*
|
||||||
* Items can be allocated in a static buffer or in the node's memory pool if the static buffer is exhausted.
|
* Items will be allocated in the node's memory pool.
|
||||||
*
|
|
||||||
* Number of static entries must not be less than 1.
|
|
||||||
*/
|
*/
|
||||||
template <typename T, unsigned NumStaticEntries>
|
template <typename T>
|
||||||
class UAVCAN_EXPORT Multiset : Noncopyable
|
class UAVCAN_EXPORT Multiset : Noncopyable
|
||||||
{
|
{
|
||||||
struct Item : ::uavcan::Noncopyable
|
struct Item : ::uavcan::Noncopyable
|
||||||
@@ -122,7 +120,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
LinkedListRoot<Chunk> list_;
|
LinkedListRoot<Chunk> list_;
|
||||||
IPoolAllocator& allocator_;
|
IPoolAllocator& allocator_;
|
||||||
Item static_[NumStaticEntries];
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Methods
|
* Methods
|
||||||
@@ -333,13 +330,7 @@ public:
|
|||||||
* Counts number of items stored.
|
* Counts number of items stored.
|
||||||
* Best case complexity is O(N).
|
* Best case complexity is O(N).
|
||||||
*/
|
*/
|
||||||
unsigned getSize() const { return getNumStaticItems() + getNumDynamicItems(); }
|
unsigned getSize() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* For testing, do not use directly.
|
|
||||||
*/
|
|
||||||
unsigned getNumStaticItems() const;
|
|
||||||
unsigned getNumDynamicItems() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -347,21 +338,10 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Multiset<>
|
* Multiset<>
|
||||||
*/
|
*/
|
||||||
template <typename T, unsigned NumStaticEntries>
|
template <typename T>
|
||||||
typename Multiset<T, NumStaticEntries>::Item* Multiset<T, NumStaticEntries>::findOrCreateFreeSlot()
|
typename Multiset<T>::Item* Multiset<T>::findOrCreateFreeSlot()
|
||||||
{
|
{
|
||||||
#if !UAVCAN_TINY
|
// Search
|
||||||
// Search in static pool
|
|
||||||
for (unsigned i = 0; i < NumStaticEntries; i++)
|
|
||||||
{
|
|
||||||
if (!static_[i].isConstructed())
|
|
||||||
{
|
|
||||||
return &static_[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Search in dynamic pool
|
|
||||||
{
|
{
|
||||||
Chunk* p = list_.get();
|
Chunk* p = list_.get();
|
||||||
while (p)
|
while (p)
|
||||||
@@ -375,7 +355,7 @@ typename Multiset<T, NumStaticEntries>::Item* Multiset<T, NumStaticEntries>::fin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new dynamic chunk
|
// Create new chunk
|
||||||
Chunk* const chunk = Chunk::instantiate(allocator_);
|
Chunk* const chunk = Chunk::instantiate(allocator_);
|
||||||
if (chunk == NULL)
|
if (chunk == NULL)
|
||||||
{
|
{
|
||||||
@@ -385,8 +365,8 @@ typename Multiset<T, NumStaticEntries>::Item* Multiset<T, NumStaticEntries>::fin
|
|||||||
return &chunk->items[0];
|
return &chunk->items[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, unsigned NumStaticEntries>
|
template <typename T>
|
||||||
void Multiset<T, NumStaticEntries>::compact()
|
void Multiset<T>::compact()
|
||||||
{
|
{
|
||||||
Chunk* p = list_.get();
|
Chunk* p = list_.get();
|
||||||
while (p)
|
while (p)
|
||||||
@@ -410,30 +390,12 @@ void Multiset<T, NumStaticEntries>::compact()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, unsigned NumStaticEntries>
|
template <typename T>
|
||||||
template <typename Predicate>
|
template <typename Predicate>
|
||||||
void Multiset<T, NumStaticEntries>::removeWhere(Predicate predicate, const RemoveStrategy strategy)
|
void Multiset<T>::removeWhere(Predicate predicate, const RemoveStrategy strategy)
|
||||||
{
|
{
|
||||||
unsigned num_removed = 0;
|
unsigned num_removed = 0;
|
||||||
|
|
||||||
#if !UAVCAN_TINY
|
|
||||||
for (unsigned i = 0; i < NumStaticEntries; i++)
|
|
||||||
{
|
|
||||||
if (static_[i].isConstructed())
|
|
||||||
{
|
|
||||||
if (predicate(*static_[i].ptr))
|
|
||||||
{
|
|
||||||
num_removed++;
|
|
||||||
static_[i].destroy();
|
|
||||||
if (strategy == RemoveOne)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Chunk* p = list_.get();
|
Chunk* p = list_.get();
|
||||||
while (p != NULL)
|
while (p != NULL)
|
||||||
{
|
{
|
||||||
@@ -470,23 +432,10 @@ void Multiset<T, NumStaticEntries>::removeWhere(Predicate predicate, const Remov
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, unsigned NumStaticEntries>
|
template <typename T>
|
||||||
template <typename Predicate>
|
template <typename Predicate>
|
||||||
T* Multiset<T, NumStaticEntries>::find(Predicate predicate)
|
T* Multiset<T>::find(Predicate predicate)
|
||||||
{
|
{
|
||||||
#if !UAVCAN_TINY
|
|
||||||
for (unsigned i = 0; i < NumStaticEntries; i++)
|
|
||||||
{
|
|
||||||
if (static_[i].isConstructed())
|
|
||||||
{
|
|
||||||
if (predicate(*static_[i].ptr))
|
|
||||||
{
|
|
||||||
return static_[i].ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Chunk* p = list_.get();
|
Chunk* p = list_.get();
|
||||||
while (p != NULL)
|
while (p != NULL)
|
||||||
{
|
{
|
||||||
@@ -508,21 +457,8 @@ T* Multiset<T, NumStaticEntries>::find(Predicate predicate)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, unsigned NumStaticEntries>
|
template <typename T>
|
||||||
unsigned Multiset<T, NumStaticEntries>::getNumStaticItems() const
|
unsigned Multiset<T>::getSize() const
|
||||||
{
|
|
||||||
unsigned num = 0;
|
|
||||||
#if !UAVCAN_TINY
|
|
||||||
for (unsigned i = 0; i < NumStaticEntries; i++)
|
|
||||||
{
|
|
||||||
num += static_[i].isConstructed() ? 1U : 0U;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, unsigned NumStaticEntries>
|
|
||||||
unsigned Multiset<T, NumStaticEntries>::getNumDynamicItems() const
|
|
||||||
{
|
{
|
||||||
unsigned num = 0;
|
unsigned num = 0;
|
||||||
Chunk* p = list_.get();
|
Chunk* p = list_.get();
|
||||||
|
|||||||
@@ -291,58 +291,9 @@ int StaticTransferBufferManagerEntryImpl::write(unsigned offset, const uint8_t*
|
|||||||
return buf_.write(offset, data, len);
|
return buf_.write(offset, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StaticTransferBufferManagerEntryImpl::migrateFrom(const TransferBufferManagerEntry* tbme)
|
|
||||||
{
|
|
||||||
if (tbme == NULL || tbme->isEmpty())
|
|
||||||
{
|
|
||||||
UAVCAN_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resetting self and moving all data from the source
|
|
||||||
TransferBufferManagerEntry::reset(tbme->getKey());
|
|
||||||
const int res = tbme->read(0, buf_.getRawPtr(), buf_.getSize());
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
TransferBufferManagerEntry::reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
buf_.setMaxWritePos(uint16_t(res));
|
|
||||||
if (res < int(buf_.getSize()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we need to make sure that all data can fit the storage
|
|
||||||
uint8_t dummy = 0;
|
|
||||||
if (tbme->read(buf_.getSize(), &dummy, 1) > 0)
|
|
||||||
{
|
|
||||||
TransferBufferManagerEntry::reset(); // Damn, the buffer was too large
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TransferBufferManagerImpl
|
* TransferBufferManagerImpl
|
||||||
*/
|
*/
|
||||||
StaticTransferBufferManagerEntryImpl* TransferBufferManagerImpl::findFirstStatic(const TransferBufferManagerKey& key)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; true; i++)
|
|
||||||
{
|
|
||||||
StaticTransferBufferManagerEntryImpl* const sb = getStaticByIndex(uint16_t(i));
|
|
||||||
if (sb == NULL)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (sb->getKey() == key)
|
|
||||||
{
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicTransferBufferManagerEntry* TransferBufferManagerImpl::findFirstDynamic(const TransferBufferManagerKey& key)
|
DynamicTransferBufferManagerEntry* TransferBufferManagerImpl::findFirstDynamic(const TransferBufferManagerKey& key)
|
||||||
{
|
{
|
||||||
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
|
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
|
||||||
@@ -358,40 +309,6 @@ DynamicTransferBufferManagerEntry* TransferBufferManagerImpl::findFirstDynamic(c
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransferBufferManagerImpl::optimizeStorage()
|
|
||||||
{
|
|
||||||
while (!dynamic_buffers_.isEmpty())
|
|
||||||
{
|
|
||||||
StaticTransferBufferManagerEntryImpl* const sb = findFirstStatic(TransferBufferManagerKey());
|
|
||||||
if (sb == NULL)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
|
|
||||||
UAVCAN_ASSERT(dyn);
|
|
||||||
UAVCAN_ASSERT(!dyn->isEmpty());
|
|
||||||
if (sb->migrateFrom(dyn))
|
|
||||||
{
|
|
||||||
UAVCAN_ASSERT(!dyn->isEmpty());
|
|
||||||
UAVCAN_TRACE("TransferBufferManager", "Storage optimization: Migrated %s",
|
|
||||||
dyn->getKey().toString().c_str());
|
|
||||||
dynamic_buffers_.remove(dyn);
|
|
||||||
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Migration can fail if a dynamic buffer contains more data than a static buffer can accomodate.
|
|
||||||
* This should never happen during normal operation because dynamic buffers are limited in growth.
|
|
||||||
*/
|
|
||||||
UAVCAN_TRACE("TransferBufferManager", "Storage optimization: MIGRATION FAILURE %s MAXSIZE %u",
|
|
||||||
dyn->getKey().toString().c_str(), max_buf_size_);
|
|
||||||
UAVCAN_ASSERT(0);
|
|
||||||
sb->reset();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TransferBufferManagerImpl::~TransferBufferManagerImpl()
|
TransferBufferManagerImpl::~TransferBufferManagerImpl()
|
||||||
{
|
{
|
||||||
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
|
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
|
||||||
@@ -411,11 +328,6 @@ ITransferBuffer* TransferBufferManagerImpl::access(const TransferBufferManagerKe
|
|||||||
UAVCAN_ASSERT(0);
|
UAVCAN_ASSERT(0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
TransferBufferManagerEntry* tbme = findFirstStatic(key);
|
|
||||||
if (tbme)
|
|
||||||
{
|
|
||||||
return tbme;
|
|
||||||
}
|
|
||||||
return findFirstDynamic(key);
|
return findFirstDynamic(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,27 +340,17 @@ ITransferBuffer* TransferBufferManagerImpl::create(const TransferBufferManagerKe
|
|||||||
}
|
}
|
||||||
remove(key);
|
remove(key);
|
||||||
|
|
||||||
TransferBufferManagerEntry* tbme = findFirstStatic(TransferBufferManagerKey());
|
DynamicTransferBufferManagerEntry* tbme = DynamicTransferBufferManagerEntry::instantiate(allocator_, max_buf_size_);
|
||||||
if (tbme == NULL)
|
if (tbme == NULL)
|
||||||
{
|
{
|
||||||
DynamicTransferBufferManagerEntry* dyn =
|
return NULL; // Epic fail.
|
||||||
DynamicTransferBufferManagerEntry::instantiate(allocator_, max_buf_size_);
|
|
||||||
tbme = dyn;
|
|
||||||
if (dyn == NULL)
|
|
||||||
{
|
|
||||||
return NULL; // Epic fail.
|
|
||||||
}
|
|
||||||
dynamic_buffers_.insert(dyn);
|
|
||||||
UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer created [st=%u, dyn=%u], %s",
|
|
||||||
getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UAVCAN_TRACE("TransferBufferManager", "Static buffer created [st=%u, dyn=%u], %s",
|
|
||||||
getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tbme)
|
dynamic_buffers_.insert(tbme);
|
||||||
|
|
||||||
|
UAVCAN_TRACE("TransferBufferManager", "Buffer created [num=%u], %s", getNumBuffers(), key.toString().c_str());
|
||||||
|
|
||||||
|
if (tbme != NULL)
|
||||||
{
|
{
|
||||||
UAVCAN_ASSERT(tbme->isEmpty());
|
UAVCAN_ASSERT(tbme->isEmpty());
|
||||||
tbme->reset(key);
|
tbme->reset(key);
|
||||||
@@ -460,19 +362,10 @@ void TransferBufferManagerImpl::remove(const TransferBufferManagerKey& key)
|
|||||||
{
|
{
|
||||||
UAVCAN_ASSERT(!key.isEmpty());
|
UAVCAN_ASSERT(!key.isEmpty());
|
||||||
|
|
||||||
TransferBufferManagerEntry* const tbme = findFirstStatic(key);
|
|
||||||
if (tbme)
|
|
||||||
{
|
|
||||||
UAVCAN_TRACE("TransferBufferManager", "Static buffer deleted, %s", key.toString().c_str());
|
|
||||||
tbme->reset();
|
|
||||||
optimizeStorage();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicTransferBufferManagerEntry* dyn = findFirstDynamic(key);
|
DynamicTransferBufferManagerEntry* dyn = findFirstDynamic(key);
|
||||||
if (dyn)
|
if (dyn != NULL)
|
||||||
{
|
{
|
||||||
UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer deleted, %s", key.toString().c_str());
|
UAVCAN_TRACE("TransferBufferManager", "Buffer deleted, %s", key.toString().c_str());
|
||||||
dynamic_buffers_.remove(dyn);
|
dynamic_buffers_.remove(dyn);
|
||||||
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
|
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
|
||||||
}
|
}
|
||||||
@@ -480,30 +373,12 @@ void TransferBufferManagerImpl::remove(const TransferBufferManagerKey& key)
|
|||||||
|
|
||||||
bool TransferBufferManagerImpl::isEmpty() const
|
bool TransferBufferManagerImpl::isEmpty() const
|
||||||
{
|
{
|
||||||
return (getNumStaticBuffers() == 0) && (getNumDynamicBuffers() == 0);
|
return getNumBuffers() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned TransferBufferManagerImpl::getNumDynamicBuffers() const
|
unsigned TransferBufferManagerImpl::getNumBuffers() const
|
||||||
{
|
{
|
||||||
return dynamic_buffers_.getLength();
|
return dynamic_buffers_.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned TransferBufferManagerImpl::getNumStaticBuffers() const
|
|
||||||
{
|
|
||||||
unsigned res = 0;
|
|
||||||
for (unsigned i = 0; true; i++)
|
|
||||||
{
|
|
||||||
StaticTransferBufferManagerEntryImpl* const sb = getStaticByIndex(uint16_t(i));
|
|
||||||
if (sb == NULL)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!sb->isEmpty())
|
|
||||||
{
|
|
||||||
res++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
struct TestNode : public uavcan::INode
|
struct TestNode : public uavcan::INode
|
||||||
{
|
{
|
||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 100, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 100, uavcan::MemPoolBlockSize> pool;
|
||||||
uavcan::OutgoingTransferRegistry<8> otr;
|
uavcan::OutgoingTransferRegistry otr;
|
||||||
uavcan::Scheduler scheduler;
|
uavcan::Scheduler scheduler;
|
||||||
uint64_t internal_failure_count;
|
uint64_t internal_failure_count;
|
||||||
|
|
||||||
|
|||||||
@@ -190,6 +190,5 @@ TEST(dynamic_node_id_server, ObjectSizes)
|
|||||||
std::cout << "ServiceServer<AppendEntries>: " << sizeof(ServiceServer<AppendEntries>) << std::endl;
|
std::cout << "ServiceServer<AppendEntries>: " << sizeof(ServiceServer<AppendEntries>) << std::endl;
|
||||||
std::cout << "ServiceClient<AppendEntries>: " << sizeof(ServiceClient<AppendEntries>) << std::endl;
|
std::cout << "ServiceClient<AppendEntries>: " << sizeof(ServiceClient<AppendEntries>) << std::endl;
|
||||||
std::cout << "ServiceServer<RequestVote>: " << sizeof(ServiceServer<RequestVote>) << std::endl;
|
std::cout << "ServiceServer<RequestVote>: " << sizeof(ServiceServer<RequestVote>) << std::endl;
|
||||||
std::cout << "ServiceClient<RequestVote,~,5>:"
|
std::cout << "ServiceClient<RequestVote>: " << sizeof(ServiceClient<RequestVote>) << std::endl;
|
||||||
<< sizeof(ServiceClient<RequestVote, void (*)(const ServiceCallResult<RequestVote>&), 5>) << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -281,7 +281,5 @@ TEST(dynamic_node_id_server_NodeDiscoverer, Sizes)
|
|||||||
std::cout << "BitSet<NodeID::Max + 1>: " << sizeof(BitSet<NodeID::Max + 1>) << std::endl;
|
std::cout << "BitSet<NodeID::Max + 1>: " << sizeof(BitSet<NodeID::Max + 1>) << std::endl;
|
||||||
std::cout << "ServiceClient<protocol::GetNodeInfo>: " << sizeof(ServiceClient<protocol::GetNodeInfo>) << std::endl;
|
std::cout << "ServiceClient<protocol::GetNodeInfo>: " << sizeof(ServiceClient<protocol::GetNodeInfo>) << std::endl;
|
||||||
std::cout << "protocol::GetNodeInfo::Response: " << sizeof(protocol::GetNodeInfo::Response) << std::endl;
|
std::cout << "protocol::GetNodeInfo::Response: " << sizeof(protocol::GetNodeInfo::Response) << std::endl;
|
||||||
std::cout << "Subscriber<protocol::NodeStatus, ~, 64, 0>: "
|
std::cout << "Subscriber<protocol::NodeStatus>: " << sizeof(Subscriber<protocol::NodeStatus>) << std::endl;
|
||||||
<< sizeof(Subscriber<protocol::NodeStatus,
|
|
||||||
void (*)(const ReceivedDataStructure<protocol::NodeStatus>&), 64, 0>) << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ TEST(Dispatcher, Reception)
|
|||||||
SystemClockMock clockmock(100);
|
SystemClockMock clockmock(100);
|
||||||
CanDriverMock driver(2, clockmock);
|
CanDriverMock driver(2, clockmock);
|
||||||
|
|
||||||
uavcan::OutgoingTransferRegistry<8> out_trans_reg(pool);
|
uavcan::OutgoingTransferRegistry out_trans_reg(pool);
|
||||||
|
|
||||||
uavcan::Dispatcher dispatcher(driver, pool, clockmock, out_trans_reg);
|
uavcan::Dispatcher dispatcher(driver, pool, clockmock, out_trans_reg);
|
||||||
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
||||||
@@ -86,7 +86,7 @@ TEST(Dispatcher, Reception)
|
|||||||
makeDataType(uavcan::DataTypeKindService, 1)
|
makeDataType(uavcan::DataTypeKindService, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef TestListener<512, 2, 2> Subscriber;
|
typedef TestListener<512> Subscriber;
|
||||||
typedef std::auto_ptr<Subscriber> SubscriberPtr;
|
typedef std::auto_ptr<Subscriber> SubscriberPtr;
|
||||||
static const int NUM_SUBSCRIBERS = 6;
|
static const int NUM_SUBSCRIBERS = 6;
|
||||||
SubscriberPtr subscribers[NUM_SUBSCRIBERS] =
|
SubscriberPtr subscribers[NUM_SUBSCRIBERS] =
|
||||||
@@ -255,7 +255,7 @@ TEST(Dispatcher, Transmission)
|
|||||||
SystemClockMock clockmock(100);
|
SystemClockMock clockmock(100);
|
||||||
CanDriverMock driver(2, clockmock);
|
CanDriverMock driver(2, clockmock);
|
||||||
|
|
||||||
uavcan::OutgoingTransferRegistry<8> out_trans_reg(pool);
|
uavcan::OutgoingTransferRegistry out_trans_reg(pool);
|
||||||
|
|
||||||
uavcan::Dispatcher dispatcher(driver, pool, clockmock, out_trans_reg);
|
uavcan::Dispatcher dispatcher(driver, pool, clockmock, out_trans_reg);
|
||||||
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
||||||
@@ -319,7 +319,7 @@ TEST(Dispatcher, Spin)
|
|||||||
SystemClockMock clockmock(100);
|
SystemClockMock clockmock(100);
|
||||||
CanDriverMock driver(2, clockmock);
|
CanDriverMock driver(2, clockmock);
|
||||||
|
|
||||||
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
|
uavcan::OutgoingTransferRegistry out_trans_reg(poolmgr);
|
||||||
|
|
||||||
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
||||||
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
||||||
@@ -365,7 +365,7 @@ TEST(Dispatcher, Loopback)
|
|||||||
SystemClockMock clockmock(100);
|
SystemClockMock clockmock(100);
|
||||||
CanDriverMock driver(2, clockmock);
|
CanDriverMock driver(2, clockmock);
|
||||||
|
|
||||||
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
|
uavcan::OutgoingTransferRegistry out_trans_reg(poolmgr);
|
||||||
|
|
||||||
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
||||||
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID));
|
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID));
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ TEST(MultiFrameIncomingTransfer, Basic)
|
|||||||
using uavcan::MultiFrameIncomingTransfer;
|
using uavcan::MultiFrameIncomingTransfer;
|
||||||
|
|
||||||
NullAllocator poolmgr; // We don't need dynamic memory
|
NullAllocator poolmgr; // We don't need dynamic memory
|
||||||
uavcan::TransferBufferManager<256, 1> bufmgr(poolmgr);
|
uavcan::TransferBufferManager<256> bufmgr(poolmgr);
|
||||||
|
|
||||||
const RxFrame frame = makeFrame();
|
const RxFrame frame = makeFrame();
|
||||||
uavcan::TransferBufferManagerKey bufmgr_key(frame.getSrcNodeID(), frame.getTransferType());
|
uavcan::TransferBufferManagerKey bufmgr_key(frame.getSrcNodeID(), frame.getTransferType());
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ TEST(OutgoingTransferRegistry, Basic)
|
|||||||
{
|
{
|
||||||
using uavcan::OutgoingTransferRegistryKey;
|
using uavcan::OutgoingTransferRegistryKey;
|
||||||
NullAllocator poolmgr; // Empty
|
NullAllocator poolmgr; // Empty
|
||||||
uavcan::OutgoingTransferRegistry<4> otr(poolmgr);
|
uavcan::OutgoingTransferRegistry otr(poolmgr);
|
||||||
|
|
||||||
otr.cleanup(tsMono(1000));
|
otr.cleanup(tsMono(1000));
|
||||||
|
|
||||||
|
|||||||
@@ -229,10 +229,10 @@ TEST(TransferBufferManager, Basic)
|
|||||||
using uavcan::TransferBufferManagerKey;
|
using uavcan::TransferBufferManagerKey;
|
||||||
using uavcan::ITransferBuffer;
|
using uavcan::ITransferBuffer;
|
||||||
|
|
||||||
static const int POOL_BLOCKS = 6;
|
static const int POOL_BLOCKS = 8;
|
||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
||||||
|
|
||||||
typedef TransferBufferManager<MGR_MAX_BUFFER_SIZE, 2> TransferBufferManagerType;
|
typedef TransferBufferManager<MGR_MAX_BUFFER_SIZE> TransferBufferManagerType;
|
||||||
std::auto_ptr<TransferBufferManagerType> mgr(new TransferBufferManagerType(pool));
|
std::auto_ptr<TransferBufferManagerType> mgr(new TransferBufferManagerType(pool));
|
||||||
|
|
||||||
// Empty
|
// Empty
|
||||||
@@ -250,40 +250,32 @@ TEST(TransferBufferManager, Basic)
|
|||||||
TransferBufferManagerKey(64, uavcan::TransferTypeMessageBroadcast)
|
TransferBufferManagerKey(64, uavcan::TransferTypeMessageBroadcast)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Static 0
|
|
||||||
ASSERT_TRUE((tbb = mgr->create(keys[0])));
|
ASSERT_TRUE((tbb = mgr->create(keys[0])));
|
||||||
ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[0], tbb));
|
ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[0], tbb));
|
||||||
ASSERT_EQ(1, mgr->getNumStaticBuffers());
|
ASSERT_EQ(1, mgr->getNumBuffers());
|
||||||
|
|
||||||
// Static 1
|
|
||||||
ASSERT_TRUE((tbb = mgr->create(keys[1])));
|
ASSERT_TRUE((tbb = mgr->create(keys[1])));
|
||||||
ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[1], tbb));
|
ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[1], tbb));
|
||||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
ASSERT_EQ(0, mgr->getNumBuffers());
|
||||||
ASSERT_EQ(0, mgr->getNumDynamicBuffers());
|
|
||||||
ASSERT_EQ(0, pool.getNumUsedBlocks());
|
ASSERT_EQ(0, pool.getNumUsedBlocks());
|
||||||
|
|
||||||
// Dynamic 0
|
|
||||||
ASSERT_TRUE((tbb = mgr->create(keys[2])));
|
ASSERT_TRUE((tbb = mgr->create(keys[2])));
|
||||||
ASSERT_EQ(1, pool.getNumUsedBlocks()); // Empty dynamic buffer occupies one block
|
ASSERT_EQ(1, pool.getNumUsedBlocks()); // Empty dynamic buffer occupies one block
|
||||||
ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[2], tbb));
|
ASSERT_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[2], tbb));
|
||||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
ASSERT_EQ(1, mgr->getNumBuffers());
|
||||||
ASSERT_EQ(1, mgr->getNumDynamicBuffers());
|
|
||||||
ASSERT_LT(1, pool.getNumUsedBlocks());
|
ASSERT_LT(1, pool.getNumUsedBlocks());
|
||||||
|
|
||||||
std::cout << "TransferBufferManager - Basic: Pool usage: " << pool.getNumUsedBlocks() << std::endl;
|
std::cout << "TransferBufferManager - Basic: Pool usage: " << pool.getNumUsedBlocks() << std::endl;
|
||||||
|
|
||||||
// Dynamic 2
|
|
||||||
ASSERT_TRUE((tbb = mgr->create(keys[3])));
|
ASSERT_TRUE((tbb = mgr->create(keys[3])));
|
||||||
ASSERT_LT(0, pool.getNumUsedBlocks());
|
ASSERT_LT(0, pool.getNumUsedBlocks());
|
||||||
|
|
||||||
ASSERT_LT(0, fillTestData(MGR_TEST_DATA[3], tbb));
|
ASSERT_LT(0, fillTestData(MGR_TEST_DATA[3], tbb));
|
||||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
ASSERT_EQ(2, mgr->getNumBuffers());
|
||||||
ASSERT_EQ(2, mgr->getNumDynamicBuffers());
|
|
||||||
|
|
||||||
// Dynamic 3 - will fail due to OOM
|
// Dynamic 3 - will fail due to OOM
|
||||||
ASSERT_FALSE((tbb = mgr->create(keys[4])));
|
ASSERT_FALSE((tbb = mgr->create(keys[4])));
|
||||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
ASSERT_EQ(2, mgr->getNumBuffers());
|
||||||
ASSERT_EQ(2, mgr->getNumDynamicBuffers());
|
|
||||||
|
|
||||||
// Making sure all buffers contain proper data
|
// Making sure all buffers contain proper data
|
||||||
ASSERT_TRUE((tbb = mgr->access(keys[0])));
|
ASSERT_TRUE((tbb = mgr->access(keys[0])));
|
||||||
@@ -298,18 +290,14 @@ TEST(TransferBufferManager, Basic)
|
|||||||
ASSERT_TRUE((tbb = mgr->access(keys[3])));
|
ASSERT_TRUE((tbb = mgr->access(keys[3])));
|
||||||
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
|
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
|
||||||
|
|
||||||
// Freeing one static buffer; one dynamic must migrate
|
|
||||||
mgr->remove(keys[1]);
|
mgr->remove(keys[1]);
|
||||||
ASSERT_FALSE(mgr->access(keys[1]));
|
ASSERT_FALSE(mgr->access(keys[1]));
|
||||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
ASSERT_EQ(1, mgr->getNumBuffers());
|
||||||
ASSERT_EQ(1, mgr->getNumDynamicBuffers()); // One migrated to the static
|
|
||||||
ASSERT_LT(0, pool.getNumFreeBlocks());
|
ASSERT_LT(0, pool.getNumFreeBlocks());
|
||||||
|
|
||||||
// Removing NodeID 0; one dynamic must migrate
|
|
||||||
mgr->remove(keys[0]);
|
mgr->remove(keys[0]);
|
||||||
ASSERT_FALSE(mgr->access(keys[0]));
|
ASSERT_FALSE(mgr->access(keys[0]));
|
||||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
ASSERT_EQ(0, mgr->getNumBuffers());
|
||||||
ASSERT_EQ(0, mgr->getNumDynamicBuffers());
|
|
||||||
|
|
||||||
// At this time we have the following NodeID: 2, 127
|
// At this time we have the following NodeID: 2, 127
|
||||||
ASSERT_TRUE((tbb = mgr->access(keys[2])));
|
ASSERT_TRUE((tbb = mgr->access(keys[2])));
|
||||||
@@ -336,7 +324,7 @@ TEST(TransferBufferManager, Basic)
|
|||||||
|
|
||||||
TEST(TransferBufferManager, EmptySpecialization)
|
TEST(TransferBufferManager, EmptySpecialization)
|
||||||
{
|
{
|
||||||
uavcan::TransferBufferManager<0, 0> mgr;
|
uavcan::TransferBufferManager<0> mgr;
|
||||||
(void)mgr;
|
(void)mgr;
|
||||||
ASSERT_GE(sizeof(void*), sizeof(mgr));
|
ASSERT_GE(sizeof(void*), sizeof(mgr));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ TEST(TransferListener, BasicMFT)
|
|||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * NUM_POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * NUM_POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
||||||
|
|
||||||
uavcan::TransferPerfCounter perf;
|
uavcan::TransferPerfCounter perf;
|
||||||
TestListener<256, 1, 1> subscriber(perf, type, pool);
|
TestListener<256> subscriber(perf, type, pool);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test data
|
* Test data
|
||||||
@@ -95,7 +95,7 @@ TEST(TransferListener, CrcFailure)
|
|||||||
|
|
||||||
NullAllocator poolmgr; // No dynamic memory
|
NullAllocator poolmgr; // No dynamic memory
|
||||||
uavcan::TransferPerfCounter perf;
|
uavcan::TransferPerfCounter perf;
|
||||||
TestListener<256, 2, 2> subscriber(perf, type, poolmgr); // Static buffer only, 2 entries
|
TestListener<256> subscriber(perf, type, poolmgr); // Static buffer only, 2 entries
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generating transfers with damaged payload (CRC is not valid)
|
* Generating transfers with damaged payload (CRC is not valid)
|
||||||
@@ -138,7 +138,7 @@ TEST(TransferListener, BasicSFT)
|
|||||||
|
|
||||||
NullAllocator poolmgr; // No dynamic memory. At all.
|
NullAllocator poolmgr; // No dynamic memory. At all.
|
||||||
uavcan::TransferPerfCounter perf;
|
uavcan::TransferPerfCounter perf;
|
||||||
TestListener<0, 0, 5> subscriber(perf, type, poolmgr); // Max buf size is 0, i.e. SFT-only
|
TestListener<0> subscriber(perf, type, poolmgr); // Max buf size is 0, i.e. SFT-only
|
||||||
|
|
||||||
TransferListenerEmulator emulator(subscriber, type);
|
TransferListenerEmulator emulator(subscriber, type);
|
||||||
const Transfer transfers[] =
|
const Transfer transfers[] =
|
||||||
@@ -174,7 +174,7 @@ TEST(TransferListener, Cleanup)
|
|||||||
|
|
||||||
NullAllocator poolmgr; // No dynamic memory
|
NullAllocator poolmgr; // No dynamic memory
|
||||||
uavcan::TransferPerfCounter perf;
|
uavcan::TransferPerfCounter perf;
|
||||||
TestListener<256, 1, 2> subscriber(perf, type, poolmgr); // Static buffer only, 1 entry
|
TestListener<256> subscriber(perf, type, poolmgr); // Static buffer only, 1 entry
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generating transfers
|
* Generating transfers
|
||||||
@@ -229,7 +229,7 @@ TEST(TransferListener, AnonymousTransfers)
|
|||||||
|
|
||||||
NullAllocator poolmgr;
|
NullAllocator poolmgr;
|
||||||
uavcan::TransferPerfCounter perf;
|
uavcan::TransferPerfCounter perf;
|
||||||
TestListener<0, 0, 0> subscriber(perf, type, poolmgr);
|
TestListener<0> subscriber(perf, type, poolmgr);
|
||||||
|
|
||||||
TransferListenerEmulator emulator(subscriber, type);
|
TransferListenerEmulator emulator(subscriber, type);
|
||||||
const Transfer transfers[] =
|
const Transfer transfers[] =
|
||||||
@@ -261,5 +261,5 @@ TEST(TransferListener, Sizes)
|
|||||||
{
|
{
|
||||||
using namespace uavcan;
|
using namespace uavcan;
|
||||||
|
|
||||||
std::cout << "sizeof(TransferListener<64, 1, 2>): " << sizeof(TransferListener<64, 1, 2>) << std::endl;
|
std::cout << "sizeof(TransferListener<64>): " << sizeof(TransferListener<64>) << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ struct Context
|
|||||||
{
|
{
|
||||||
NullAllocator pool; // We don't need dynamic memory for this test
|
NullAllocator pool; // We don't need dynamic memory for this test
|
||||||
uavcan::TransferReceiver receiver; // Must be default constructible and copyable
|
uavcan::TransferReceiver receiver; // Must be default constructible and copyable
|
||||||
uavcan::TransferBufferManager<BufSize, 1> bufmgr;
|
uavcan::TransferBufferManager<BufSize> bufmgr;
|
||||||
|
|
||||||
Context() :
|
Context() :
|
||||||
bufmgr(pool)
|
bufmgr(pool)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ TEST(TransferSender, Basic)
|
|||||||
SystemClockMock clockmock(100);
|
SystemClockMock clockmock(100);
|
||||||
CanDriverMock driver(2, clockmock);
|
CanDriverMock driver(2, clockmock);
|
||||||
|
|
||||||
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
|
uavcan::OutgoingTransferRegistry out_trans_reg(poolmgr);
|
||||||
|
|
||||||
static const uavcan::NodeID TX_NODE_ID(64);
|
static const uavcan::NodeID TX_NODE_ID(64);
|
||||||
static const uavcan::NodeID RX_NODE_ID(65);
|
static const uavcan::NodeID RX_NODE_ID(65);
|
||||||
@@ -123,9 +123,9 @@ TEST(TransferSender, Basic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TestListener<512, 2, 2> sub_msg(dispatcher_rx.getTransferPerfCounter(), TYPES[0], poolmgr);
|
TestListener<512> sub_msg(dispatcher_rx.getTransferPerfCounter(), TYPES[0], poolmgr);
|
||||||
TestListener<512, 2, 2> sub_srv_req(dispatcher_rx.getTransferPerfCounter(), TYPES[1], poolmgr);
|
TestListener<512> sub_srv_req(dispatcher_rx.getTransferPerfCounter(), TYPES[1], poolmgr);
|
||||||
TestListener<512, 2, 2> sub_srv_resp(dispatcher_rx.getTransferPerfCounter(), TYPES[1], poolmgr);
|
TestListener<512> sub_srv_resp(dispatcher_rx.getTransferPerfCounter(), TYPES[1], poolmgr);
|
||||||
|
|
||||||
dispatcher_rx.registerMessageListener(&sub_msg);
|
dispatcher_rx.registerMessageListener(&sub_msg);
|
||||||
dispatcher_rx.registerServiceRequestListener(&sub_srv_req);
|
dispatcher_rx.registerServiceRequestListener(&sub_srv_req);
|
||||||
@@ -195,7 +195,7 @@ TEST(TransferSender, Loopback)
|
|||||||
SystemClockMock clockmock(100);
|
SystemClockMock clockmock(100);
|
||||||
CanDriverMock driver(2, clockmock);
|
CanDriverMock driver(2, clockmock);
|
||||||
|
|
||||||
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
|
uavcan::OutgoingTransferRegistry out_trans_reg(poolmgr);
|
||||||
|
|
||||||
static const uavcan::NodeID TX_NODE_ID(64);
|
static const uavcan::NodeID TX_NODE_ID(64);
|
||||||
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
||||||
@@ -236,7 +236,7 @@ TEST(TransferSender, PassiveMode)
|
|||||||
SystemClockMock clockmock(100);
|
SystemClockMock clockmock(100);
|
||||||
CanDriverMock driver(2, clockmock);
|
CanDriverMock driver(2, clockmock);
|
||||||
|
|
||||||
uavcan::OutgoingTransferRegistry<8> out_trans_reg(poolmgr);
|
uavcan::OutgoingTransferRegistry out_trans_reg(poolmgr);
|
||||||
|
|
||||||
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ TEST(TransferTestHelpers, Transfer)
|
|||||||
{
|
{
|
||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 8, uavcan::MemPoolBlockSize> pool;
|
||||||
|
|
||||||
uavcan::TransferBufferManager<128, 1> mgr(pool);
|
uavcan::TransferBufferManager<128> mgr(pool);
|
||||||
uavcan::TransferBufferAccessor tba(mgr, uavcan::TransferBufferManagerKey(0, uavcan::TransferTypeMessageBroadcast));
|
uavcan::TransferBufferAccessor tba(mgr, uavcan::TransferBufferManagerKey(0, uavcan::TransferTypeMessageBroadcast));
|
||||||
|
|
||||||
uavcan::RxFrame frame(uavcan::Frame(123, uavcan::TransferTypeMessageBroadcast, 1, 0, 0),
|
uavcan::RxFrame frame(uavcan::Frame(123, uavcan::TransferTypeMessageBroadcast, 1, 0, 0),
|
||||||
|
|||||||
@@ -117,10 +117,10 @@ struct Transfer
|
|||||||
* In reality, uavcan::TransferListener should accept only specific transfer types
|
* In reality, uavcan::TransferListener should accept only specific transfer types
|
||||||
* which are dispatched/filtered by uavcan::Dispatcher.
|
* which are dispatched/filtered by uavcan::Dispatcher.
|
||||||
*/
|
*/
|
||||||
template <unsigned MAX_BUF_SIZE, unsigned NUM_STATIC_BUFS, unsigned NUM_STATIC_RECEIVERS>
|
template <unsigned MAX_BUF_SIZE>
|
||||||
class TestListener : public uavcan::TransferListener<MAX_BUF_SIZE, NUM_STATIC_BUFS, NUM_STATIC_RECEIVERS>
|
class TestListener : public uavcan::TransferListener<MAX_BUF_SIZE>
|
||||||
{
|
{
|
||||||
typedef uavcan::TransferListener<MAX_BUF_SIZE, NUM_STATIC_BUFS, NUM_STATIC_RECEIVERS> Base;
|
typedef uavcan::TransferListener<MAX_BUF_SIZE> Base;
|
||||||
|
|
||||||
std::queue<Transfer> transfers_;
|
std::queue<Transfer> transfers_;
|
||||||
|
|
||||||
|
|||||||
+19
-25
@@ -2,6 +2,11 @@
|
|||||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if __GNUC__
|
||||||
|
// We need auto_ptr for compatibility reasons
|
||||||
|
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -46,7 +51,7 @@ TEST(Map, Basic)
|
|||||||
static const int POOL_BLOCKS = 3;
|
static const int POOL_BLOCKS = 3;
|
||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
||||||
|
|
||||||
typedef Map<std::string, std::string, 2> MapType;
|
typedef Map<std::string, std::string> MapType;
|
||||||
std::auto_ptr<MapType> map(new MapType(pool));
|
std::auto_ptr<MapType> map(new MapType(pool));
|
||||||
|
|
||||||
// Empty
|
// Empty
|
||||||
@@ -57,25 +62,23 @@ TEST(Map, Basic)
|
|||||||
ASSERT_FALSE(map->getByIndex(1));
|
ASSERT_FALSE(map->getByIndex(1));
|
||||||
ASSERT_FALSE(map->getByIndex(10000));
|
ASSERT_FALSE(map->getByIndex(10000));
|
||||||
|
|
||||||
// Static insertion
|
// Insertion
|
||||||
ASSERT_EQ("a", *map->insert("1", "a"));
|
ASSERT_EQ("a", *map->insert("1", "a"));
|
||||||
ASSERT_EQ("b", *map->insert("2", "b"));
|
ASSERT_EQ("b", *map->insert("2", "b"));
|
||||||
ASSERT_EQ(0, pool.getNumUsedBlocks());
|
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
||||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
ASSERT_EQ(2, map->getSize());
|
||||||
ASSERT_EQ(0, map->getNumDynamicPairs());
|
|
||||||
|
|
||||||
// Ordering
|
// Ordering
|
||||||
ASSERT_TRUE(map->getByIndex(0)->match("1"));
|
ASSERT_TRUE(map->getByIndex(0)->match("1"));
|
||||||
ASSERT_TRUE(map->getByIndex(1)->match("2"));
|
ASSERT_TRUE(map->getByIndex(1)->match("2"));
|
||||||
|
|
||||||
// Dynamic insertion
|
// Insertion
|
||||||
ASSERT_EQ("c", *map->insert("3", "c"));
|
ASSERT_EQ("c", *map->insert("3", "c"));
|
||||||
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
||||||
|
|
||||||
ASSERT_EQ("d", *map->insert("4", "d"));
|
ASSERT_EQ("d", *map->insert("4", "d"));
|
||||||
ASSERT_EQ(1, pool.getNumUsedBlocks()); // Assuming that at least 2 items fit one block
|
ASSERT_EQ(2, pool.getNumUsedBlocks()); // Assuming that at least 2 items fit one block
|
||||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
ASSERT_EQ(4, map->getSize());
|
||||||
ASSERT_EQ(2, map->getNumDynamicPairs());
|
|
||||||
|
|
||||||
// Making sure everything is here
|
// Making sure everything is here
|
||||||
ASSERT_EQ("a", *map->access("1"));
|
ASSERT_EQ("a", *map->access("1"));
|
||||||
@@ -116,12 +119,11 @@ TEST(Map, Basic)
|
|||||||
ASSERT_EQ("4", *map->find(ValueFindPredicate("D")));
|
ASSERT_EQ("4", *map->find(ValueFindPredicate("D")));
|
||||||
ASSERT_FALSE(map->find(KeyFindPredicate("nonexistent_value")));
|
ASSERT_FALSE(map->find(KeyFindPredicate("nonexistent_value")));
|
||||||
|
|
||||||
// Removing one static
|
// Removing one
|
||||||
map->remove("1"); // One of dynamics now migrates to the static storage
|
map->remove("1"); // One of dynamics now migrates to the static storage
|
||||||
map->remove("foo"); // There's no such thing anyway
|
map->remove("foo"); // There's no such thing anyway
|
||||||
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
ASSERT_EQ(2, pool.getNumUsedBlocks());
|
||||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
ASSERT_EQ(3, map->getSize());
|
||||||
ASSERT_EQ(1, map->getNumDynamicPairs());
|
|
||||||
|
|
||||||
ASSERT_FALSE(map->access("1"));
|
ASSERT_FALSE(map->access("1"));
|
||||||
ASSERT_EQ("B", *map->access("2"));
|
ASSERT_EQ("B", *map->access("2"));
|
||||||
@@ -135,9 +137,8 @@ TEST(Map, Basic)
|
|||||||
|
|
||||||
// Removing another static
|
// Removing another static
|
||||||
map->remove("2");
|
map->remove("2");
|
||||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
ASSERT_EQ(1, map->getSize());
|
||||||
ASSERT_EQ(0, map->getNumDynamicPairs());
|
ASSERT_EQ(1, pool.getNumUsedBlocks()); // No dynamic entries left
|
||||||
ASSERT_EQ(0, pool.getNumUsedBlocks()); // No dynamic entries left
|
|
||||||
|
|
||||||
ASSERT_FALSE(map->access("1"));
|
ASSERT_FALSE(map->access("1"));
|
||||||
ASSERT_FALSE(map->access("2"));
|
ASSERT_FALSE(map->access("2"));
|
||||||
@@ -172,13 +173,7 @@ TEST(Map, Basic)
|
|||||||
ASSERT_FALSE(map->access("value"));
|
ASSERT_FALSE(map->access("value"));
|
||||||
|
|
||||||
// Removing odd values - nearly half of them
|
// Removing odd values - nearly half of them
|
||||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
|
||||||
const unsigned num_dynamics_old = map->getNumDynamicPairs();
|
|
||||||
map->removeAllWhere(oddValuePredicate);
|
map->removeAllWhere(oddValuePredicate);
|
||||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
|
||||||
const unsigned num_dynamics_new = map->getNumDynamicPairs();
|
|
||||||
std::cout << "Num of dynamic pairs reduced from " << num_dynamics_old << " to " << num_dynamics_new << std::endl;
|
|
||||||
ASSERT_LT(num_dynamics_new, num_dynamics_old);
|
|
||||||
|
|
||||||
// Making sure there's no odd values left
|
// Making sure there's no odd values left
|
||||||
for (unsigned kv_int = 0; kv_int <= max_key_integer; kv_int++)
|
for (unsigned kv_int = 0; kv_int <= max_key_integer; kv_int++)
|
||||||
@@ -220,8 +215,7 @@ TEST(Map, NoStatic)
|
|||||||
ASSERT_EQ("a", *map->insert("1", "a"));
|
ASSERT_EQ("a", *map->insert("1", "a"));
|
||||||
ASSERT_EQ("b", *map->insert("2", "b"));
|
ASSERT_EQ("b", *map->insert("2", "b"));
|
||||||
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
||||||
ASSERT_EQ(0, map->getNumStaticPairs());
|
ASSERT_EQ(2, map->getSize());
|
||||||
ASSERT_EQ(2, map->getNumDynamicPairs());
|
|
||||||
|
|
||||||
// Ordering
|
// Ordering
|
||||||
ASSERT_TRUE(map->getByIndex(0)->match("1"));
|
ASSERT_TRUE(map->getByIndex(0)->match("1"));
|
||||||
@@ -238,7 +232,7 @@ TEST(Map, PrimitiveKey)
|
|||||||
static const int POOL_BLOCKS = 3;
|
static const int POOL_BLOCKS = 3;
|
||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
||||||
|
|
||||||
typedef Map<short, short, 2> MapType;
|
typedef Map<short, short> MapType;
|
||||||
std::auto_ptr<MapType> map(new MapType(pool));
|
std::auto_ptr<MapType> map(new MapType(pool));
|
||||||
|
|
||||||
// Empty
|
// Empty
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ TEST(Multiset, Basic)
|
|||||||
static const int POOL_BLOCKS = 3;
|
static const int POOL_BLOCKS = 3;
|
||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
||||||
|
|
||||||
typedef Multiset<std::string, 2> MultisetType;
|
typedef Multiset<std::string> MultisetType;
|
||||||
std::auto_ptr<MultisetType> mset(new MultisetType(pool));
|
std::auto_ptr<MultisetType> mset(new MultisetType(pool));
|
||||||
|
|
||||||
typedef SummationOperator<std::string> StringConcatenationOperator;
|
typedef SummationOperator<std::string> StringConcatenationOperator;
|
||||||
@@ -86,9 +86,8 @@ TEST(Multiset, Basic)
|
|||||||
// Static addion
|
// Static addion
|
||||||
ASSERT_EQ("1", *mset->emplace("1"));
|
ASSERT_EQ("1", *mset->emplace("1"));
|
||||||
ASSERT_EQ("2", *mset->emplace("2"));
|
ASSERT_EQ("2", *mset->emplace("2"));
|
||||||
ASSERT_EQ(0, pool.getNumUsedBlocks());
|
ASSERT_LE(1, pool.getNumUsedBlocks()); // One or more
|
||||||
ASSERT_EQ(2, mset->getNumStaticItems());
|
ASSERT_EQ(2, mset->getSize());
|
||||||
ASSERT_EQ(0, mset->getNumDynamicItems());
|
|
||||||
|
|
||||||
// Ordering
|
// Ordering
|
||||||
ASSERT_TRUE(*mset->getByIndex(0) == "1");
|
ASSERT_TRUE(*mset->getByIndex(0) == "1");
|
||||||
@@ -103,12 +102,11 @@ TEST(Multiset, Basic)
|
|||||||
// Dynamic addition
|
// Dynamic addition
|
||||||
ASSERT_EQ("3", *mset->emplace("3"));
|
ASSERT_EQ("3", *mset->emplace("3"));
|
||||||
ASSERT_EQ("3", *mset->getByIndex(2));
|
ASSERT_EQ("3", *mset->getByIndex(2));
|
||||||
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
ASSERT_LE(1, pool.getNumUsedBlocks()); // One or more
|
||||||
|
|
||||||
ASSERT_EQ("4", *mset->emplace("4"));
|
ASSERT_EQ("4", *mset->emplace("4"));
|
||||||
ASSERT_LE(1, pool.getNumUsedBlocks()); // One or more
|
ASSERT_LE(1, pool.getNumUsedBlocks()); // One or more
|
||||||
ASSERT_EQ(2, mset->getNumStaticItems());
|
ASSERT_EQ(4, mset->getSize());
|
||||||
ASSERT_EQ(2, mset->getNumDynamicItems());
|
|
||||||
|
|
||||||
// Making sure everything is here
|
// Making sure everything is here
|
||||||
ASSERT_EQ("1", *mset->getByIndex(0));
|
ASSERT_EQ("1", *mset->getByIndex(0));
|
||||||
@@ -117,9 +115,6 @@ TEST(Multiset, Basic)
|
|||||||
ASSERT_FALSE(mset->getByIndex(100));
|
ASSERT_FALSE(mset->getByIndex(100));
|
||||||
ASSERT_FALSE(mset->getByIndex(4));
|
ASSERT_FALSE(mset->getByIndex(4));
|
||||||
|
|
||||||
const std::string data_at_pos2 = *mset->getByIndex(2);
|
|
||||||
const std::string data_at_pos3 = *mset->getByIndex(3);
|
|
||||||
|
|
||||||
// Finding some items
|
// Finding some items
|
||||||
ASSERT_EQ("1", *mset->find(FindPredicate("1")));
|
ASSERT_EQ("1", *mset->find(FindPredicate("1")));
|
||||||
ASSERT_EQ("2", *mset->find(FindPredicate("2")));
|
ASSERT_EQ("2", *mset->find(FindPredicate("2")));
|
||||||
@@ -134,23 +129,10 @@ TEST(Multiset, Basic)
|
|||||||
ASSERT_EQ(4, op.accumulator.size());
|
ASSERT_EQ(4, op.accumulator.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removing one static; ordering will be preserved
|
// Removing some
|
||||||
mset->removeFirst("1");
|
mset->removeFirst("1");
|
||||||
mset->removeFirst("foo"); // There's no such thing anyway
|
mset->removeFirst("foo"); // There's no such thing anyway
|
||||||
ASSERT_LE(1, pool.getNumUsedBlocks());
|
|
||||||
ASSERT_EQ(1, mset->getNumStaticItems());
|
|
||||||
ASSERT_EQ(2, mset->getNumDynamicItems()); // This container does not move items
|
|
||||||
|
|
||||||
// Ordering has not changed
|
|
||||||
ASSERT_EQ("2", *mset->getByIndex(0)); // Entry "1" was here
|
|
||||||
ASSERT_EQ(data_at_pos2, *mset->getByIndex(1));
|
|
||||||
ASSERT_EQ(data_at_pos3, *mset->getByIndex(2));
|
|
||||||
|
|
||||||
// Removing another static
|
|
||||||
mset->removeFirst("2");
|
mset->removeFirst("2");
|
||||||
ASSERT_EQ(0, mset->getNumStaticItems());
|
|
||||||
ASSERT_EQ(2, mset->getNumDynamicItems());
|
|
||||||
ASSERT_LE(1, pool.getNumUsedBlocks());
|
|
||||||
|
|
||||||
// Adding some new items
|
// Adding some new items
|
||||||
unsigned max_value_integer = 0;
|
unsigned max_value_integer = 0;
|
||||||
@@ -219,7 +201,7 @@ TEST(Multiset, PrimitiveKey)
|
|||||||
static const int POOL_BLOCKS = 3;
|
static const int POOL_BLOCKS = 3;
|
||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
||||||
|
|
||||||
typedef Multiset<int, 2> MultisetType;
|
typedef Multiset<int> MultisetType;
|
||||||
std::auto_ptr<MultisetType> mset(new MultisetType(pool));
|
std::auto_ptr<MultisetType> mset(new MultisetType(pool));
|
||||||
|
|
||||||
// Empty
|
// Empty
|
||||||
@@ -269,7 +251,7 @@ TEST(Multiset, NoncopyableWithCounter)
|
|||||||
static const int POOL_BLOCKS = 3;
|
static const int POOL_BLOCKS = 3;
|
||||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * POOL_BLOCKS, uavcan::MemPoolBlockSize> pool;
|
||||||
|
|
||||||
typedef Multiset<NoncopyableWithCounter, 2> MultisetType;
|
typedef Multiset<NoncopyableWithCounter> MultisetType;
|
||||||
std::auto_ptr<MultisetType> mset(new MultisetType(pool));
|
std::auto_ptr<MultisetType> mset(new MultisetType(pool));
|
||||||
|
|
||||||
ASSERT_EQ(0, NoncopyableWithCounter::num_objects);
|
ASSERT_EQ(0, NoncopyableWithCounter::num_objects);
|
||||||
|
|||||||
Reference in New Issue
Block a user