mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-04-14 10:07:39 +08:00
First stab at global refactoring of memory management - the library builds, but unit tests are failing horribly
This commit is contained in:
parent
0643879922
commit
be84897ed6
@ -239,24 +239,6 @@ static const unsigned MaxCanAcceptanceFilters = UAVCAN_MAX_CAN_ACCEPTANCE_FILTER
|
||||
static const unsigned MaxCanAcceptanceFilters = 32;
|
||||
#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
|
||||
|
||||
@ -119,25 +119,16 @@ public:
|
||||
* This helper class does some compile-time magic on the transport layer machinery. For authorized personnel only.
|
||||
*/
|
||||
template <typename DataStruct_,
|
||||
unsigned NumStaticReceivers_,
|
||||
unsigned NumStaticBufs_,
|
||||
template<unsigned, unsigned, unsigned> class TransferListenerTemplate = TransferListener
|
||||
template<unsigned> class TransferListenerTemplate = TransferListener
|
||||
>
|
||||
class UAVCAN_EXPORT TransferListenerInstantiationHelper
|
||||
{
|
||||
enum { DataTypeMaxByteLen = BitLenToByteLen<DataStruct_::MaxBitLen>::Result };
|
||||
enum { NeedsBuffer = int(DataTypeMaxByteLen) > int(GuaranteedPayloadLenPerFrame) };
|
||||
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:
|
||||
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 high-traffic nodes the recommended minimum is
|
||||
* 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_,
|
||||
#if UAVCAN_TINY
|
||||
unsigned OutgoingTransferRegistryStaticEntries = 0
|
||||
#else
|
||||
unsigned OutgoingTransferRegistryStaticEntries = 10
|
||||
#endif
|
||||
>
|
||||
template <std::size_t MemPoolSize_>
|
||||
class UAVCAN_EXPORT Node : public INode
|
||||
{
|
||||
enum
|
||||
@ -61,7 +47,7 @@ class UAVCAN_EXPORT Node : public INode
|
||||
typedef PoolAllocator<MemPoolSize, MemPoolBlockSize> Allocator;
|
||||
|
||||
Allocator pool_allocator_;
|
||||
OutgoingTransferRegistry<OutgoingTransferRegistryStaticEntries> outgoing_trans_reg_;
|
||||
OutgoingTransferRegistry outgoing_trans_reg_;
|
||||
Scheduler scheduler_;
|
||||
|
||||
NodeStatusProvider proto_nsp_;
|
||||
@ -260,9 +246,8 @@ public:
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
template <std::size_t MemPoolSize_, unsigned OutgoingTransferRegistryStaticEntries>
|
||||
int Node<MemPoolSize_, OutgoingTransferRegistryStaticEntries>::start(
|
||||
const TransferPriority priority)
|
||||
template <std::size_t MemPoolSize_>
|
||||
int Node<MemPoolSize_>::start(const TransferPriority priority)
|
||||
{
|
||||
if (started_)
|
||||
{
|
||||
|
||||
@ -21,13 +21,11 @@
|
||||
namespace uavcan
|
||||
{
|
||||
|
||||
template <typename ServiceDataType, unsigned NumStaticReceiversAndBuffers>
|
||||
template <typename ServiceDataType>
|
||||
class UAVCAN_EXPORT ServiceResponseTransferListenerInstantiationHelper
|
||||
{
|
||||
public: // so much templating it hurts
|
||||
public:
|
||||
typedef typename TransferListenerInstantiationHelper<typename ServiceDataType::Response,
|
||||
NumStaticReceiversAndBuffers,
|
||||
NumStaticReceiversAndBuffers,
|
||||
TransferListenerWithFilter>::Type Type;
|
||||
};
|
||||
|
||||
@ -217,24 +215,18 @@ public:
|
||||
* 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
|
||||
* 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_,
|
||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||
typename Callback_ = std::function<void (const ServiceCallResult<DataType_>&)>,
|
||||
typename Callback_ = std::function<void (const ServiceCallResult<DataType_>&)>
|
||||
#else
|
||||
typename Callback_ = void (*)(const ServiceCallResult<DataType_>&),
|
||||
typename Callback_ = void (*)(const ServiceCallResult<DataType_>&)
|
||||
#endif
|
||||
unsigned NumStaticCalls_ = 1
|
||||
>
|
||||
class UAVCAN_EXPORT ServiceClient
|
||||
: public GenericSubscriber<DataType_,
|
||||
typename DataType_::Response,
|
||||
typename ServiceResponseTransferListenerInstantiationHelper<DataType_,
|
||||
NumStaticCalls_>::Type>
|
||||
typename ServiceResponseTransferListenerInstantiationHelper<DataType_>::Type>
|
||||
, public ServiceClientBase
|
||||
{
|
||||
public:
|
||||
@ -244,16 +236,13 @@ public:
|
||||
typedef ServiceCallResult<DataType> ServiceCallResultType;
|
||||
typedef Callback_ Callback;
|
||||
|
||||
enum { NumStaticCalls = NumStaticCalls_ };
|
||||
|
||||
private:
|
||||
typedef ServiceClient<DataType, Callback> SelfType;
|
||||
typedef GenericPublisher<DataType, RequestType> PublisherType;
|
||||
typedef typename ServiceResponseTransferListenerInstantiationHelper<DataType, NumStaticCalls>::Type
|
||||
TransferListenerType;
|
||||
typedef typename ServiceResponseTransferListenerInstantiationHelper<DataType>::Type TransferListenerType;
|
||||
typedef GenericSubscriber<DataType, ResponseType, TransferListenerType> SubscriberType;
|
||||
|
||||
typedef Multiset<CallState, NumStaticCalls> CallRegistry;
|
||||
typedef Multiset<CallState> CallRegistry;
|
||||
|
||||
struct TimeoutCallbackCaller
|
||||
{
|
||||
@ -424,8 +413,8 @@ public:
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::invokeCallback(ServiceCallResultType& result)
|
||||
template <typename DataType_, typename Callback_>
|
||||
void ServiceClient<DataType_, Callback_>::invokeCallback(ServiceCallResultType& result)
|
||||
{
|
||||
if (coerceOrFallback<bool>(callback_, true))
|
||||
{
|
||||
@ -437,8 +426,8 @@ void ServiceClient<DataType_, Callback_, NumStaticCalls_>::invokeCallback(Servic
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
bool ServiceClient<DataType_, Callback_, NumStaticCalls_>::shouldAcceptFrame(const RxFrame& frame) const
|
||||
template <typename DataType_, typename Callback_>
|
||||
bool ServiceClient<DataType_, Callback_>::shouldAcceptFrame(const RxFrame& frame) const
|
||||
{
|
||||
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_>
|
||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::
|
||||
handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response)
|
||||
template <typename DataType_, typename Callback_>
|
||||
void ServiceClient<DataType_, Callback_>::handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response)
|
||||
{
|
||||
UAVCAN_ASSERT(response.getTransferType() == TransferTypeServiceResponse);
|
||||
|
||||
@ -460,8 +448,8 @@ handleReceivedDataStruct(ReceivedDataStructure<ResponseType>& response)
|
||||
}
|
||||
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::handleDeadline(MonotonicTime)
|
||||
template <typename DataType_, typename Callback_>
|
||||
void ServiceClient<DataType_, Callback_>::handleDeadline(MonotonicTime)
|
||||
{
|
||||
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_>
|
||||
int ServiceClient<DataType_, Callback_, NumStaticCalls_>::addCallState(ServiceCallID call_id)
|
||||
template <typename DataType_, typename Callback_>
|
||||
int ServiceClient<DataType_, Callback_>::addCallState(ServiceCallID call_id)
|
||||
{
|
||||
if (call_registry_.isEmpty())
|
||||
{
|
||||
@ -507,16 +495,16 @@ int ServiceClient<DataType_, Callback_, NumStaticCalls_>::addCallState(ServiceCa
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
int ServiceClient<DataType_, Callback_, NumStaticCalls_>::call(NodeID server_node_id, const RequestType& request)
|
||||
template <typename DataType_, typename Callback_>
|
||||
int ServiceClient<DataType_, Callback_>::call(NodeID server_node_id, const RequestType& request)
|
||||
{
|
||||
ServiceCallID dummy;
|
||||
return call(server_node_id, request, dummy);
|
||||
}
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
int ServiceClient<DataType_, Callback_, NumStaticCalls_>::call(NodeID server_node_id, const RequestType& request,
|
||||
ServiceCallID& out_call_id)
|
||||
template <typename DataType_, typename Callback_>
|
||||
int ServiceClient<DataType_, Callback_>::call(NodeID server_node_id, const RequestType& request,
|
||||
ServiceCallID& out_call_id)
|
||||
{
|
||||
if (!coerceOrFallback<bool>(callback_, true))
|
||||
{
|
||||
@ -573,8 +561,8 @@ int ServiceClient<DataType_, Callback_, NumStaticCalls_>::call(NodeID server_nod
|
||||
return publisher_res;
|
||||
}
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::cancelCall(ServiceCallID call_id)
|
||||
template <typename DataType_, typename Callback_>
|
||||
void ServiceClient<DataType_, Callback_>::cancelCall(ServiceCallID call_id)
|
||||
{
|
||||
call_registry_.removeFirstWhere(CallStateMatchingPredicate(call_id));
|
||||
if (call_registry_.isEmpty())
|
||||
@ -583,21 +571,21 @@ void ServiceClient<DataType_, Callback_, NumStaticCalls_>::cancelCall(ServiceCal
|
||||
}
|
||||
}
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
void ServiceClient<DataType_, Callback_, NumStaticCalls_>::cancelAllCalls()
|
||||
template <typename DataType_, typename Callback_>
|
||||
void ServiceClient<DataType_, Callback_>::cancelAllCalls()
|
||||
{
|
||||
call_registry_.clear();
|
||||
SubscriberType::stop();
|
||||
}
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
bool ServiceClient<DataType_, Callback_, NumStaticCalls_>::hasPendingCallToServer(NodeID server_node_id) const
|
||||
template <typename DataType_, typename Callback_>
|
||||
bool ServiceClient<DataType_, Callback_>::hasPendingCallToServer(NodeID server_node_id) const
|
||||
{
|
||||
return NULL != call_registry_.find(ServerSearchPredicate(server_node_id));
|
||||
}
|
||||
|
||||
template <typename DataType_, typename Callback_, unsigned NumStaticCalls_>
|
||||
ServiceCallID ServiceClient<DataType_, Callback_, NumStaticCalls_>::getCallIDByIndex(unsigned index) const
|
||||
template <typename DataType_, typename Callback_>
|
||||
ServiceCallID ServiceClient<DataType_, Callback_>::getCallIDByIndex(unsigned index) const
|
||||
{
|
||||
const CallState* const id = call_registry_.getByIndex(index);
|
||||
return (id == NULL) ? ServiceCallID() : id->getCallID();
|
||||
|
||||
@ -77,33 +77,19 @@ public:
|
||||
* 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
|
||||
* 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_,
|
||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||
typename Callback_ = std::function<void (const ReceivedDataStructure<typename DataType_::Request>&,
|
||||
ServiceResponseDataStructure<typename DataType_::Response>&)>,
|
||||
ServiceResponseDataStructure<typename DataType_::Response>&)>
|
||||
#else
|
||||
typename Callback_ = void (*)(const ReceivedDataStructure<typename DataType_::Request>&,
|
||||
ServiceResponseDataStructure<typename DataType_::Response>&),
|
||||
#endif
|
||||
#if UAVCAN_TINY
|
||||
unsigned NumStaticReceivers = 0,
|
||||
unsigned NumStaticBufs = 0
|
||||
#else
|
||||
unsigned NumStaticReceivers = 2,
|
||||
unsigned NumStaticBufs = 1
|
||||
ServiceResponseDataStructure<typename DataType_::Response>&)
|
||||
#endif
|
||||
>
|
||||
class UAVCAN_EXPORT ServiceServer
|
||||
: public GenericSubscriber<DataType_, typename DataType_::Request,
|
||||
typename TransferListenerInstantiationHelper<typename DataType_::Request,
|
||||
NumStaticReceivers, NumStaticBufs>::Type>
|
||||
typename TransferListenerInstantiationHelper<typename DataType_::Request>::Type>
|
||||
{
|
||||
public:
|
||||
typedef DataType_ DataType;
|
||||
@ -112,8 +98,7 @@ public:
|
||||
typedef Callback_ Callback;
|
||||
|
||||
private:
|
||||
typedef typename TransferListenerInstantiationHelper<RequestType, NumStaticReceivers, NumStaticBufs>::Type
|
||||
TransferListenerType;
|
||||
typedef typename TransferListenerInstantiationHelper<RequestType>::Type TransferListenerType;
|
||||
typedef GenericSubscriber<DataType, RequestType, TransferListenerType> SubscriberType;
|
||||
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
|
||||
* to lean how to use libuavcan in multiprocess applications.
|
||||
*/
|
||||
template <std::size_t MemPoolSize_,
|
||||
unsigned OutgoingTransferRegistryStaticEntries = 10
|
||||
>
|
||||
template <std::size_t MemPoolSize_>
|
||||
class UAVCAN_EXPORT SubNode : public INode
|
||||
{
|
||||
enum
|
||||
@ -33,7 +31,7 @@ class UAVCAN_EXPORT SubNode : public INode
|
||||
typedef PoolAllocator<MemPoolSize, MemPoolBlockSize> Allocator;
|
||||
|
||||
Allocator pool_allocator_;
|
||||
OutgoingTransferRegistry<OutgoingTransferRegistryStaticEntries> outgoing_trans_reg_;
|
||||
OutgoingTransferRegistry outgoing_trans_reg_;
|
||||
Scheduler scheduler_;
|
||||
|
||||
uint64_t internal_failure_cnt_;
|
||||
|
||||
@ -34,38 +34,23 @@ namespace uavcan
|
||||
* 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
|
||||
* 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_,
|
||||
#if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
|
||||
typename Callback_ = std::function<void (const ReceivedDataStructure<DataType_>&)>,
|
||||
typename Callback_ = std::function<void (const ReceivedDataStructure<DataType_>&)>
|
||||
#else
|
||||
typename Callback_ = void (*)(const ReceivedDataStructure<DataType_>&),
|
||||
#endif
|
||||
#if UAVCAN_TINY
|
||||
unsigned NumStaticReceivers = 0,
|
||||
unsigned NumStaticBufs = 0
|
||||
#else
|
||||
unsigned NumStaticReceivers = 2,
|
||||
unsigned NumStaticBufs = 1
|
||||
typename Callback_ = void (*)(const ReceivedDataStructure<DataType_>&)
|
||||
#endif
|
||||
>
|
||||
class UAVCAN_EXPORT Subscriber
|
||||
: public GenericSubscriber<DataType_, DataType_,
|
||||
typename TransferListenerInstantiationHelper<DataType_, NumStaticReceivers,
|
||||
NumStaticBufs>::Type>
|
||||
typename TransferListenerInstantiationHelper<DataType_>::Type>
|
||||
{
|
||||
public:
|
||||
typedef Callback_ Callback;
|
||||
|
||||
private:
|
||||
typedef typename TransferListenerInstantiationHelper<DataType_, NumStaticReceivers, NumStaticBufs>::Type
|
||||
TransferListenerType;
|
||||
typedef typename TransferListenerInstantiationHelper<DataType_>::Type TransferListenerType;
|
||||
typedef GenericSubscriber<DataType_, DataType_, TransferListenerType> BaseType;
|
||||
|
||||
Callback callback_;
|
||||
|
||||
@ -126,8 +126,8 @@ private:
|
||||
*/
|
||||
ServiceServer<AppendEntries, AppendEntriesCallback> append_entries_srv_;
|
||||
ServiceClient<AppendEntries, AppendEntriesResponseCallback> append_entries_client_;
|
||||
ServiceServer<RequestVote, RequestVoteCallback> request_vote_srv_;
|
||||
ServiceClient<RequestVote, RequestVoteResponseCallback, MaxNumFollowers> request_vote_client_;
|
||||
ServiceServer<RequestVote, RequestVoteCallback> request_vote_srv_;
|
||||
ServiceClient<RequestVote, RequestVoteResponseCallback> request_vote_client_;
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -101,10 +101,10 @@ class NodeDiscoverer : TimerBase
|
||||
IEventTracer& tracer_;
|
||||
|
||||
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_;
|
||||
Subscriber<protocol::NodeStatus, NodeStatusCallback, MaxNetworkSizeHint, 0> node_status_sub_;
|
||||
Subscriber<protocol::NodeStatus, NodeStatusCallback> node_status_sub_;
|
||||
|
||||
/*
|
||||
* Methods
|
||||
|
||||
@ -31,8 +31,7 @@ class UAVCAN_EXPORT GlobalTimeSyncSlave : Noncopyable
|
||||
void (GlobalTimeSyncSlave::*)(const ReceivedDataStructure<protocol::GlobalTimeSync>&)>
|
||||
GlobalTimeSyncCallback;
|
||||
|
||||
// Static buffers are explicitly disabled because time should never be unicasted.
|
||||
Subscriber<protocol::GlobalTimeSync, GlobalTimeSyncCallback, 2, 0> sub_;
|
||||
Subscriber<protocol::GlobalTimeSync, GlobalTimeSyncCallback> sub_;
|
||||
|
||||
UtcTime prev_ts_utc_;
|
||||
MonotonicTime prev_ts_mono_;
|
||||
|
||||
@ -156,7 +156,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
enum { NumStaticCalls = 2 };
|
||||
enum { DefaultNumRequestAttempts = 16 };
|
||||
enum { DefaultTimerIntervalMSec = 40 }; ///< Read explanation in the class documentation
|
||||
|
||||
@ -165,9 +164,9 @@ private:
|
||||
*/
|
||||
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_;
|
||||
|
||||
|
||||
@ -75,7 +75,7 @@ private:
|
||||
|
||||
typedef MethodBinder<NodeStatusMonitor*, void (NodeStatusMonitor::*)(const TimerEvent&)> TimerCallback;
|
||||
|
||||
Subscriber<protocol::NodeStatus, NodeStatusCallback, MaxNetworkSizeHint, 0> sub_;
|
||||
Subscriber<protocol::NodeStatus, NodeStatusCallback> sub_;
|
||||
|
||||
TimerEventForwarder<TimerCallback> timer_;
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ private:
|
||||
static const unsigned DefaultAnonMsgMask = 0xFF;
|
||||
static const unsigned DefaultAnonMsgID = 0x0;
|
||||
|
||||
typedef uavcan::Multiset<CanFilterConfig, 1> MultisetConfigContainer;
|
||||
typedef uavcan::Multiset<CanFilterConfig> MultisetConfigContainer;
|
||||
|
||||
static CanFilterConfig mergeFilters(CanFilterConfig &a_, CanFilterConfig &b_);
|
||||
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.
|
||||
* If a local transfer sender was inactive for a sufficiently long time, the outgoing transfer registry will
|
||||
* remove the respective Transfer ID tracking object.
|
||||
*
|
||||
* TODO: Deinterface this.
|
||||
*/
|
||||
class UAVCAN_EXPORT IOutgoingTransferRegistry
|
||||
{
|
||||
@ -74,7 +76,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
template <int NumStaticEntries>
|
||||
class UAVCAN_EXPORT OutgoingTransferRegistry : public IOutgoingTransferRegistry, Noncopyable
|
||||
{
|
||||
struct Value
|
||||
@ -123,7 +124,7 @@ class UAVCAN_EXPORT OutgoingTransferRegistry : public IOutgoingTransferRegistry,
|
||||
}
|
||||
};
|
||||
|
||||
Map<OutgoingTransferRegistryKey, Value, NumStaticEntries> map_;
|
||||
Map<OutgoingTransferRegistryKey, Value> map_;
|
||||
|
||||
public:
|
||||
explicit OutgoingTransferRegistry(IPoolAllocator& allocator)
|
||||
@ -140,11 +141,12 @@ public:
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* OutgoingTransferRegistry<>
|
||||
* OutgoingTransferRegistry
|
||||
* TODO: deinterface and move to .cpp
|
||||
*/
|
||||
template <int NumStaticEntries>
|
||||
TransferID* OutgoingTransferRegistry<NumStaticEntries>::accessOrCreate(const OutgoingTransferRegistryKey& key,
|
||||
MonotonicTime new_deadline)
|
||||
inline
|
||||
TransferID* OutgoingTransferRegistry::accessOrCreate(const OutgoingTransferRegistryKey& key,
|
||||
MonotonicTime new_deadline)
|
||||
{
|
||||
UAVCAN_ASSERT(!new_deadline.isZero());
|
||||
Value* p = map_.access(key);
|
||||
@ -161,14 +163,14 @@ TransferID* OutgoingTransferRegistry<NumStaticEntries>::accessOrCreate(const Out
|
||||
return &p->tid;
|
||||
}
|
||||
|
||||
template <int NumStaticEntries>
|
||||
bool OutgoingTransferRegistry<NumStaticEntries>::exists(DataTypeID dtid, TransferType tt) const
|
||||
inline
|
||||
bool OutgoingTransferRegistry::exists(DataTypeID dtid, TransferType tt) const
|
||||
{
|
||||
return NULL != map_.find(ExistenceCheckingPredicate(dtid, tt));
|
||||
}
|
||||
|
||||
template <int NumStaticEntries>
|
||||
void OutgoingTransferRegistry<NumStaticEntries>::cleanup(MonotonicTime ts)
|
||||
inline
|
||||
void OutgoingTransferRegistry::cleanup(MonotonicTime ts)
|
||||
{
|
||||
map_.removeAllWhere(DeadlineExpiredPredicate(ts));
|
||||
}
|
||||
|
||||
@ -194,8 +194,6 @@ public:
|
||||
|
||||
virtual int read(unsigned offset, uint8_t* data, unsigned len) const;
|
||||
virtual int write(unsigned offset, const uint8_t* data, unsigned len);
|
||||
|
||||
bool migrateFrom(const TransferBufferManagerEntry* tbme);
|
||||
};
|
||||
|
||||
template <uint16_t Size>
|
||||
@ -250,11 +248,7 @@ class TransferBufferManagerImpl : public ITransferBufferManager, Noncopyable
|
||||
IPoolAllocator& allocator_;
|
||||
const uint16_t max_buf_size_;
|
||||
|
||||
virtual StaticTransferBufferManagerEntryImpl* getStaticByIndex(uint16_t index) const = 0;
|
||||
|
||||
StaticTransferBufferManagerEntryImpl* findFirstStatic(const TransferBufferManagerKey& key);
|
||||
DynamicTransferBufferManagerEntry* findFirstDynamic(const TransferBufferManagerKey& key);
|
||||
void optimizeStorage();
|
||||
|
||||
public:
|
||||
TransferBufferManagerImpl(uint16_t max_buf_size, IPoolAllocator& allocator)
|
||||
@ -269,49 +263,20 @@ public:
|
||||
virtual void remove(const TransferBufferManagerKey& key);
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
unsigned getNumDynamicBuffers() 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();
|
||||
}
|
||||
unsigned getNumBuffers() const;
|
||||
};
|
||||
|
||||
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:
|
||||
explicit TransferBufferManager(IPoolAllocator& allocator)
|
||||
: TransferBufferManagerImpl(MaxBufSize, allocator)
|
||||
{
|
||||
StaticAssert<(MaxBufSize > 0)>::check();
|
||||
}
|
||||
explicit TransferBufferManager(IPoolAllocator& allocator) :
|
||||
TransferBufferManagerImpl(MaxBufSize, allocator)
|
||||
{ }
|
||||
};
|
||||
|
||||
template <>
|
||||
class UAVCAN_EXPORT TransferBufferManager<0, 0> : public ITransferBufferManager
|
||||
class UAVCAN_EXPORT TransferBufferManager<0> : public ITransferBufferManager
|
||||
{
|
||||
public:
|
||||
TransferBufferManager() { }
|
||||
|
||||
@ -99,7 +99,7 @@ public:
|
||||
class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListenerBase>, Noncopyable
|
||||
{
|
||||
const DataTypeDescriptor& data_type_;
|
||||
MapBase<TransferBufferManagerKey, TransferReceiver>& receivers_;
|
||||
Map<TransferBufferManagerKey, TransferReceiver>& receivers_;
|
||||
ITransferBufferManager& bufmgr_;
|
||||
TransferPerfCounter& perf_;
|
||||
const TransferCRC crc_base_; ///< Pre-initialized with data type hash, thus constant
|
||||
@ -123,7 +123,7 @@ class UAVCAN_EXPORT TransferListenerBase : public LinkedListNode<TransferListene
|
||||
|
||||
protected:
|
||||
TransferListenerBase(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
||||
MapBase<TransferBufferManagerKey, TransferReceiver>& receivers,
|
||||
Map<TransferBufferManagerKey, TransferReceiver>& receivers,
|
||||
ITransferBufferManager& bufmgr)
|
||||
: data_type_(data_type)
|
||||
, receivers_(receivers)
|
||||
@ -157,24 +157,18 @@ public:
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
TransferBufferManager<MaxBufSize, NumStaticBufs> bufmgr_;
|
||||
Map<TransferBufferManagerKey, TransferReceiver, NumStaticReceivers> receivers_;
|
||||
TransferBufferManager<MaxBufSize> bufmgr_;
|
||||
Map<TransferBufferManagerKey, TransferReceiver> receivers_;
|
||||
|
||||
public:
|
||||
TransferListener(TransferPerfCounter& perf, const DataTypeDescriptor& data_type, IPoolAllocator& allocator)
|
||||
: TransferListenerBase(perf, data_type, receivers_, bufmgr_)
|
||||
, bufmgr_(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()
|
||||
{
|
||||
@ -200,15 +194,15 @@ public:
|
||||
/**
|
||||
* This class should be derived by callers.
|
||||
*/
|
||||
template <unsigned MaxBufSize, unsigned NumStaticBufs, unsigned NumStaticReceivers>
|
||||
class UAVCAN_EXPORT TransferListenerWithFilter : public TransferListener<MaxBufSize, NumStaticBufs, NumStaticReceivers>
|
||||
template <unsigned MaxBufSize>
|
||||
class UAVCAN_EXPORT TransferListenerWithFilter : public TransferListener<MaxBufSize>
|
||||
{
|
||||
const ITransferAcceptanceFilter* filter_;
|
||||
|
||||
virtual void handleFrame(const RxFrame& frame);
|
||||
|
||||
public:
|
||||
typedef TransferListener<MaxBufSize, NumStaticBufs, NumStaticReceivers> BaseType;
|
||||
typedef TransferListener<MaxBufSize> BaseType;
|
||||
|
||||
TransferListenerWithFilter(TransferPerfCounter& perf, const DataTypeDescriptor& data_type,
|
||||
IPoolAllocator& allocator)
|
||||
@ -227,8 +221,8 @@ public:
|
||||
/*
|
||||
* TransferListenerWithFilter<>
|
||||
*/
|
||||
template <unsigned MaxBufSize, unsigned NumStaticBufs, unsigned NumStaticReceivers>
|
||||
void TransferListenerWithFilter<MaxBufSize, NumStaticBufs, NumStaticReceivers>::handleFrame(const RxFrame& frame)
|
||||
template <unsigned MaxBufSize>
|
||||
void TransferListenerWithFilter<MaxBufSize>::handleFrame(const RxFrame& frame)
|
||||
{
|
||||
if (filter_ != NULL)
|
||||
{
|
||||
|
||||
@ -18,9 +18,7 @@ namespace uavcan
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
* KV pairs will be allocated in the node's memory pool.
|
||||
*
|
||||
* 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).
|
||||
@ -32,10 +30,8 @@ namespace uavcan
|
||||
* Size of Key + Value + padding must not exceed MemPoolBlockSize.
|
||||
*/
|
||||
template <typename Key, typename Value>
|
||||
class UAVCAN_EXPORT MapBase : Noncopyable
|
||||
class UAVCAN_EXPORT Map : Noncopyable
|
||||
{
|
||||
template <typename, typename, unsigned> friend class Map;
|
||||
|
||||
public:
|
||||
struct KVPair
|
||||
{
|
||||
@ -102,16 +98,9 @@ private:
|
||||
|
||||
LinkedListRoot<KVGroup> list_;
|
||||
IPoolAllocator& allocator_;
|
||||
#if !UAVCAN_TINY
|
||||
KVPair* const static_;
|
||||
const unsigned num_static_entries_;
|
||||
#endif
|
||||
|
||||
KVPair* findKey(const Key& key);
|
||||
|
||||
#if !UAVCAN_TINY
|
||||
void optimizeStorage();
|
||||
#endif
|
||||
void compact();
|
||||
|
||||
struct YesPredicate
|
||||
@ -119,30 +108,18 @@ private:
|
||||
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:
|
||||
Map(IPoolAllocator& allocator) :
|
||||
allocator_(allocator)
|
||||
{
|
||||
UAVCAN_ASSERT(Key() == Key());
|
||||
}
|
||||
|
||||
~Map()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null pointer if there's no such entry.
|
||||
*/
|
||||
@ -192,69 +169,20 @@ public:
|
||||
*/
|
||||
bool isEmpty() const { return find(YesPredicate()) == NULL; }
|
||||
|
||||
unsigned getSize() const;
|
||||
|
||||
/**
|
||||
* For testing, do not use directly.
|
||||
* Complexity is O(N).
|
||||
*/
|
||||
unsigned getNumStaticPairs() 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(); }
|
||||
unsigned getSize() const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* MapBase<>
|
||||
* Map<>
|
||||
*/
|
||||
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();
|
||||
while (p)
|
||||
{
|
||||
@ -268,64 +196,8 @@ typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::findKey(const Key& ke
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !UAVCAN_TINY
|
||||
|
||||
template <typename Key, typename Value>
|
||||
void MapBase<Key, Value>::optimizeStorage()
|
||||
{
|
||||
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()
|
||||
void Map<Key, Value>::compact()
|
||||
{
|
||||
KVGroup* p = list_.get();
|
||||
while (p)
|
||||
@ -350,7 +222,7 @@ void MapBase<Key, Value>::compact()
|
||||
}
|
||||
|
||||
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()));
|
||||
KVPair* const kv = findKey(key);
|
||||
@ -358,7 +230,7 @@ Value* MapBase<Key, Value>::access(const Key& key)
|
||||
}
|
||||
|
||||
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()));
|
||||
remove(key);
|
||||
@ -381,40 +253,23 @@ Value* MapBase<Key, Value>::insert(const Key& key, const Value& 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()));
|
||||
KVPair* const kv = findKey(key);
|
||||
if (kv)
|
||||
{
|
||||
*kv = KVPair();
|
||||
#if !UAVCAN_TINY
|
||||
optimizeStorage();
|
||||
#endif
|
||||
compact();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
template <typename Predicate>
|
||||
void MapBase<Key, Value>::removeAllWhere(Predicate predicate)
|
||||
void Map<Key, Value>::removeAllWhere(Predicate predicate)
|
||||
{
|
||||
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();
|
||||
while (p != NULL)
|
||||
{
|
||||
@ -438,30 +293,14 @@ void MapBase<Key, Value>::removeAllWhere(Predicate predicate)
|
||||
|
||||
if (num_removed > 0)
|
||||
{
|
||||
#if !UAVCAN_TINY
|
||||
optimizeStorage();
|
||||
#endif
|
||||
compact();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
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();
|
||||
while (p != NULL)
|
||||
{
|
||||
@ -485,29 +324,14 @@ const Key* MapBase<Key, Value>::find(Predicate predicate) const
|
||||
}
|
||||
|
||||
template <typename Key, typename Value>
|
||||
void MapBase<Key, Value>::clear()
|
||||
void Map<Key, Value>::clear()
|
||||
{
|
||||
removeAllWhere(YesPredicate());
|
||||
}
|
||||
|
||||
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
|
||||
KVGroup* p = list_.get();
|
||||
while (p != NULL)
|
||||
@ -534,35 +358,13 @@ typename MapBase<Key, Value>::KVPair* MapBase<Key, Value>::getByIndex(unsigned i
|
||||
}
|
||||
|
||||
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>
|
||||
unsigned MapBase<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 Map<Key, Value>::getSize() const
|
||||
{
|
||||
unsigned num = 0;
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* Number of static entries must not be less than 1.
|
||||
* Items will be allocated in the node's memory pool.
|
||||
*/
|
||||
template <typename T, unsigned NumStaticEntries>
|
||||
template <typename T>
|
||||
class UAVCAN_EXPORT Multiset : Noncopyable
|
||||
{
|
||||
struct Item : ::uavcan::Noncopyable
|
||||
@ -122,7 +120,6 @@ private:
|
||||
*/
|
||||
LinkedListRoot<Chunk> list_;
|
||||
IPoolAllocator& allocator_;
|
||||
Item static_[NumStaticEntries];
|
||||
|
||||
/*
|
||||
* Methods
|
||||
@ -333,13 +330,7 @@ public:
|
||||
* Counts number of items stored.
|
||||
* Best case complexity is O(N).
|
||||
*/
|
||||
unsigned getSize() const { return getNumStaticItems() + getNumDynamicItems(); }
|
||||
|
||||
/**
|
||||
* For testing, do not use directly.
|
||||
*/
|
||||
unsigned getNumStaticItems() const;
|
||||
unsigned getNumDynamicItems() const;
|
||||
unsigned getSize() const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -347,21 +338,10 @@ public:
|
||||
/*
|
||||
* Multiset<>
|
||||
*/
|
||||
template <typename T, unsigned NumStaticEntries>
|
||||
typename Multiset<T, NumStaticEntries>::Item* Multiset<T, NumStaticEntries>::findOrCreateFreeSlot()
|
||||
template <typename T>
|
||||
typename Multiset<T>::Item* Multiset<T>::findOrCreateFreeSlot()
|
||||
{
|
||||
#if !UAVCAN_TINY
|
||||
// Search in static pool
|
||||
for (unsigned i = 0; i < NumStaticEntries; i++)
|
||||
{
|
||||
if (!static_[i].isConstructed())
|
||||
{
|
||||
return &static_[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Search in dynamic pool
|
||||
// Search
|
||||
{
|
||||
Chunk* p = list_.get();
|
||||
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_);
|
||||
if (chunk == NULL)
|
||||
{
|
||||
@ -385,8 +365,8 @@ typename Multiset<T, NumStaticEntries>::Item* Multiset<T, NumStaticEntries>::fin
|
||||
return &chunk->items[0];
|
||||
}
|
||||
|
||||
template <typename T, unsigned NumStaticEntries>
|
||||
void Multiset<T, NumStaticEntries>::compact()
|
||||
template <typename T>
|
||||
void Multiset<T>::compact()
|
||||
{
|
||||
Chunk* p = list_.get();
|
||||
while (p)
|
||||
@ -410,30 +390,12 @@ void Multiset<T, NumStaticEntries>::compact()
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, unsigned NumStaticEntries>
|
||||
template <typename T>
|
||||
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;
|
||||
|
||||
#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();
|
||||
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>
|
||||
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();
|
||||
while (p != NULL)
|
||||
{
|
||||
@ -508,21 +457,8 @@ T* Multiset<T, NumStaticEntries>::find(Predicate predicate)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename T, unsigned NumStaticEntries>
|
||||
unsigned Multiset<T, NumStaticEntries>::getNumStaticItems() 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
|
||||
template <typename T>
|
||||
unsigned Multiset<T>::getSize() const
|
||||
{
|
||||
unsigned num = 0;
|
||||
Chunk* p = list_.get();
|
||||
|
||||
@ -291,58 +291,9 @@ int StaticTransferBufferManagerEntryImpl::write(unsigned offset, const uint8_t*
|
||||
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
|
||||
*/
|
||||
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* dyn = dynamic_buffers_.get();
|
||||
@ -358,40 +309,6 @@ DynamicTransferBufferManagerEntry* TransferBufferManagerImpl::findFirstDynamic(c
|
||||
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()
|
||||
{
|
||||
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
|
||||
@ -411,11 +328,6 @@ ITransferBuffer* TransferBufferManagerImpl::access(const TransferBufferManagerKe
|
||||
UAVCAN_ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
TransferBufferManagerEntry* tbme = findFirstStatic(key);
|
||||
if (tbme)
|
||||
{
|
||||
return tbme;
|
||||
}
|
||||
return findFirstDynamic(key);
|
||||
}
|
||||
|
||||
@ -428,27 +340,17 @@ ITransferBuffer* TransferBufferManagerImpl::create(const TransferBufferManagerKe
|
||||
}
|
||||
remove(key);
|
||||
|
||||
TransferBufferManagerEntry* tbme = findFirstStatic(TransferBufferManagerKey());
|
||||
DynamicTransferBufferManagerEntry* tbme = DynamicTransferBufferManagerEntry::instantiate(allocator_, max_buf_size_);
|
||||
if (tbme == NULL)
|
||||
{
|
||||
DynamicTransferBufferManagerEntry* dyn =
|
||||
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());
|
||||
return NULL; // Epic fail.
|
||||
}
|
||||
|
||||
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());
|
||||
tbme->reset(key);
|
||||
@ -460,19 +362,10 @@ void TransferBufferManagerImpl::remove(const TransferBufferManagerKey& key)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
|
||||
}
|
||||
@ -480,30 +373,12 @@ void TransferBufferManagerImpl::remove(const TransferBufferManagerKey& key)
|
||||
|
||||
bool TransferBufferManagerImpl::isEmpty() const
|
||||
{
|
||||
return (getNumStaticBuffers() == 0) && (getNumDynamicBuffers() == 0);
|
||||
return getNumBuffers() == 0;
|
||||
}
|
||||
|
||||
unsigned TransferBufferManagerImpl::getNumDynamicBuffers() const
|
||||
unsigned TransferBufferManagerImpl::getNumBuffers() const
|
||||
{
|
||||
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
|
||||
{
|
||||
uavcan::PoolAllocator<uavcan::MemPoolBlockSize * 100, uavcan::MemPoolBlockSize> pool;
|
||||
uavcan::OutgoingTransferRegistry<8> otr;
|
||||
uavcan::OutgoingTransferRegistry otr;
|
||||
uavcan::Scheduler scheduler;
|
||||
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 << "ServiceClient<AppendEntries>: " << sizeof(ServiceClient<AppendEntries>) << std::endl;
|
||||
std::cout << "ServiceServer<RequestVote>: " << sizeof(ServiceServer<RequestVote>) << std::endl;
|
||||
std::cout << "ServiceClient<RequestVote,~,5>:"
|
||||
<< sizeof(ServiceClient<RequestVote, void (*)(const ServiceCallResult<RequestVote>&), 5>) << std::endl;
|
||||
std::cout << "ServiceClient<RequestVote>: " << sizeof(ServiceClient<RequestVote>) << 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 << "ServiceClient<protocol::GetNodeInfo>: " << sizeof(ServiceClient<protocol::GetNodeInfo>) << std::endl;
|
||||
std::cout << "protocol::GetNodeInfo::Response: " << sizeof(protocol::GetNodeInfo::Response) << std::endl;
|
||||
std::cout << "Subscriber<protocol::NodeStatus, ~, 64, 0>: "
|
||||
<< sizeof(Subscriber<protocol::NodeStatus,
|
||||
void (*)(const ReceivedDataStructure<protocol::NodeStatus>&), 64, 0>) << std::endl;
|
||||
std::cout << "Subscriber<protocol::NodeStatus>: " << sizeof(Subscriber<protocol::NodeStatus>) << std::endl;
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ TEST(Dispatcher, Reception)
|
||||
SystemClockMock clockmock(100);
|
||||
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);
|
||||
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
||||
@ -86,7 +86,7 @@ TEST(Dispatcher, Reception)
|
||||
makeDataType(uavcan::DataTypeKindService, 1)
|
||||
};
|
||||
|
||||
typedef TestListener<512, 2, 2> Subscriber;
|
||||
typedef TestListener<512> Subscriber;
|
||||
typedef std::auto_ptr<Subscriber> SubscriberPtr;
|
||||
static const int NUM_SUBSCRIBERS = 6;
|
||||
SubscriberPtr subscribers[NUM_SUBSCRIBERS] =
|
||||
@ -255,7 +255,7 @@ TEST(Dispatcher, Transmission)
|
||||
SystemClockMock clockmock(100);
|
||||
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);
|
||||
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
||||
@ -319,7 +319,7 @@ TEST(Dispatcher, Spin)
|
||||
SystemClockMock clockmock(100);
|
||||
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);
|
||||
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID)); // Can be set only once
|
||||
@ -365,7 +365,7 @@ TEST(Dispatcher, Loopback)
|
||||
SystemClockMock clockmock(100);
|
||||
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);
|
||||
ASSERT_TRUE(dispatcher.setNodeID(SELF_NODE_ID));
|
||||
|
||||
@ -73,7 +73,7 @@ TEST(MultiFrameIncomingTransfer, Basic)
|
||||
using uavcan::MultiFrameIncomingTransfer;
|
||||
|
||||
NullAllocator poolmgr; // We don't need dynamic memory
|
||||
uavcan::TransferBufferManager<256, 1> bufmgr(poolmgr);
|
||||
uavcan::TransferBufferManager<256> bufmgr(poolmgr);
|
||||
|
||||
const RxFrame frame = makeFrame();
|
||||
uavcan::TransferBufferManagerKey bufmgr_key(frame.getSrcNodeID(), frame.getTransferType());
|
||||
|
||||
@ -13,7 +13,7 @@ TEST(OutgoingTransferRegistry, Basic)
|
||||
{
|
||||
using uavcan::OutgoingTransferRegistryKey;
|
||||
NullAllocator poolmgr; // Empty
|
||||
uavcan::OutgoingTransferRegistry<4> otr(poolmgr);
|
||||
uavcan::OutgoingTransferRegistry otr(poolmgr);
|
||||
|
||||
otr.cleanup(tsMono(1000));
|
||||
|
||||
|
||||
@ -229,10 +229,10 @@ TEST(TransferBufferManager, Basic)
|
||||
using uavcan::TransferBufferManagerKey;
|
||||
using uavcan::ITransferBuffer;
|
||||
|
||||
static const int POOL_BLOCKS = 6;
|
||||
static const int POOL_BLOCKS = 8;
|
||||
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));
|
||||
|
||||
// Empty
|
||||
@ -250,40 +250,32 @@ TEST(TransferBufferManager, Basic)
|
||||
TransferBufferManagerKey(64, uavcan::TransferTypeMessageBroadcast)
|
||||
};
|
||||
|
||||
// Static 0
|
||||
ASSERT_TRUE((tbb = mgr->create(keys[0])));
|
||||
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_EQ(MGR_MAX_BUFFER_SIZE, fillTestData(MGR_TEST_DATA[1], tbb));
|
||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
||||
ASSERT_EQ(0, mgr->getNumDynamicBuffers());
|
||||
ASSERT_EQ(0, mgr->getNumBuffers());
|
||||
ASSERT_EQ(0, pool.getNumUsedBlocks());
|
||||
|
||||
// Dynamic 0
|
||||
ASSERT_TRUE((tbb = mgr->create(keys[2])));
|
||||
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(2, mgr->getNumStaticBuffers());
|
||||
ASSERT_EQ(1, mgr->getNumDynamicBuffers());
|
||||
ASSERT_EQ(1, mgr->getNumBuffers());
|
||||
ASSERT_LT(1, pool.getNumUsedBlocks());
|
||||
|
||||
std::cout << "TransferBufferManager - Basic: Pool usage: " << pool.getNumUsedBlocks() << std::endl;
|
||||
|
||||
// Dynamic 2
|
||||
ASSERT_TRUE((tbb = mgr->create(keys[3])));
|
||||
ASSERT_LT(0, pool.getNumUsedBlocks());
|
||||
|
||||
ASSERT_LT(0, fillTestData(MGR_TEST_DATA[3], tbb));
|
||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
||||
ASSERT_EQ(2, mgr->getNumDynamicBuffers());
|
||||
ASSERT_EQ(2, mgr->getNumBuffers());
|
||||
|
||||
// Dynamic 3 - will fail due to OOM
|
||||
ASSERT_FALSE((tbb = mgr->create(keys[4])));
|
||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
||||
ASSERT_EQ(2, mgr->getNumDynamicBuffers());
|
||||
ASSERT_EQ(2, mgr->getNumBuffers());
|
||||
|
||||
// Making sure all buffers contain proper data
|
||||
ASSERT_TRUE((tbb = mgr->access(keys[0])));
|
||||
@ -298,18 +290,14 @@ TEST(TransferBufferManager, Basic)
|
||||
ASSERT_TRUE((tbb = mgr->access(keys[3])));
|
||||
ASSERT_TRUE(matchAgainst(MGR_TEST_DATA[3], *tbb));
|
||||
|
||||
// Freeing one static buffer; one dynamic must migrate
|
||||
mgr->remove(keys[1]);
|
||||
ASSERT_FALSE(mgr->access(keys[1]));
|
||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
||||
ASSERT_EQ(1, mgr->getNumDynamicBuffers()); // One migrated to the static
|
||||
ASSERT_EQ(1, mgr->getNumBuffers());
|
||||
ASSERT_LT(0, pool.getNumFreeBlocks());
|
||||
|
||||
// Removing NodeID 0; one dynamic must migrate
|
||||
mgr->remove(keys[0]);
|
||||
ASSERT_FALSE(mgr->access(keys[0]));
|
||||
ASSERT_EQ(2, mgr->getNumStaticBuffers());
|
||||
ASSERT_EQ(0, mgr->getNumDynamicBuffers());
|
||||
ASSERT_EQ(0, mgr->getNumBuffers());
|
||||
|
||||
// At this time we have the following NodeID: 2, 127
|
||||
ASSERT_TRUE((tbb = mgr->access(keys[2])));
|
||||
@ -336,7 +324,7 @@ TEST(TransferBufferManager, Basic)
|
||||
|
||||
TEST(TransferBufferManager, EmptySpecialization)
|
||||
{
|
||||
uavcan::TransferBufferManager<0, 0> mgr;
|
||||
uavcan::TransferBufferManager<0> mgr;
|
||||
(void)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::TransferPerfCounter perf;
|
||||
TestListener<256, 1, 1> subscriber(perf, type, pool);
|
||||
TestListener<256> subscriber(perf, type, pool);
|
||||
|
||||
/*
|
||||
* Test data
|
||||
@ -95,7 +95,7 @@ TEST(TransferListener, CrcFailure)
|
||||
|
||||
NullAllocator poolmgr; // No dynamic memory
|
||||
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)
|
||||
@ -138,7 +138,7 @@ TEST(TransferListener, BasicSFT)
|
||||
|
||||
NullAllocator poolmgr; // No dynamic memory. At all.
|
||||
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);
|
||||
const Transfer transfers[] =
|
||||
@ -174,7 +174,7 @@ TEST(TransferListener, Cleanup)
|
||||
|
||||
NullAllocator poolmgr; // No dynamic memory
|
||||
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
|
||||
@ -229,7 +229,7 @@ TEST(TransferListener, AnonymousTransfers)
|
||||
|
||||
NullAllocator poolmgr;
|
||||
uavcan::TransferPerfCounter perf;
|
||||
TestListener<0, 0, 0> subscriber(perf, type, poolmgr);
|
||||
TestListener<0> subscriber(perf, type, poolmgr);
|
||||
|
||||
TransferListenerEmulator emulator(subscriber, type);
|
||||
const Transfer transfers[] =
|
||||
@ -261,5 +261,5 @@ TEST(TransferListener, Sizes)
|
||||
{
|
||||
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
|
||||
uavcan::TransferReceiver receiver; // Must be default constructible and copyable
|
||||
uavcan::TransferBufferManager<BufSize, 1> bufmgr;
|
||||
uavcan::TransferBufferManager<BufSize> bufmgr;
|
||||
|
||||
Context() :
|
||||
bufmgr(pool)
|
||||
|
||||
@ -34,7 +34,7 @@ TEST(TransferSender, Basic)
|
||||
SystemClockMock clockmock(100);
|
||||
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 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, 2, 2> 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_msg(dispatcher_rx.getTransferPerfCounter(), TYPES[0], poolmgr);
|
||||
TestListener<512> sub_srv_req(dispatcher_rx.getTransferPerfCounter(), TYPES[1], poolmgr);
|
||||
TestListener<512> sub_srv_resp(dispatcher_rx.getTransferPerfCounter(), TYPES[1], poolmgr);
|
||||
|
||||
dispatcher_rx.registerMessageListener(&sub_msg);
|
||||
dispatcher_rx.registerServiceRequestListener(&sub_srv_req);
|
||||
@ -195,7 +195,7 @@ TEST(TransferSender, Loopback)
|
||||
SystemClockMock clockmock(100);
|
||||
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);
|
||||
uavcan::Dispatcher dispatcher(driver, poolmgr, clockmock, out_trans_reg);
|
||||
@ -236,7 +236,7 @@ TEST(TransferSender, PassiveMode)
|
||||
SystemClockMock clockmock(100);
|
||||
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);
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ TEST(TransferTestHelpers, Transfer)
|
||||
{
|
||||
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::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
|
||||
* which are dispatched/filtered by uavcan::Dispatcher.
|
||||
*/
|
||||
template <unsigned MAX_BUF_SIZE, unsigned NUM_STATIC_BUFS, unsigned NUM_STATIC_RECEIVERS>
|
||||
class TestListener : public uavcan::TransferListener<MAX_BUF_SIZE, NUM_STATIC_BUFS, NUM_STATIC_RECEIVERS>
|
||||
template <unsigned MAX_BUF_SIZE>
|
||||
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_;
|
||||
|
||||
|
||||
@ -2,6 +2,11 @@
|
||||
* 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 <cstdio>
|
||||
#include <memory>
|
||||
@ -46,7 +51,7 @@ TEST(Map, Basic)
|
||||
static const int POOL_BLOCKS = 3;
|
||||
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));
|
||||
|
||||
// Empty
|
||||
@ -57,25 +62,23 @@ TEST(Map, Basic)
|
||||
ASSERT_FALSE(map->getByIndex(1));
|
||||
ASSERT_FALSE(map->getByIndex(10000));
|
||||
|
||||
// Static insertion
|
||||
// Insertion
|
||||
ASSERT_EQ("a", *map->insert("1", "a"));
|
||||
ASSERT_EQ("b", *map->insert("2", "b"));
|
||||
ASSERT_EQ(0, pool.getNumUsedBlocks());
|
||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
||||
ASSERT_EQ(0, map->getNumDynamicPairs());
|
||||
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
||||
ASSERT_EQ(2, map->getSize());
|
||||
|
||||
// Ordering
|
||||
ASSERT_TRUE(map->getByIndex(0)->match("1"));
|
||||
ASSERT_TRUE(map->getByIndex(1)->match("2"));
|
||||
|
||||
// Dynamic insertion
|
||||
// Insertion
|
||||
ASSERT_EQ("c", *map->insert("3", "c"));
|
||||
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
||||
|
||||
ASSERT_EQ("d", *map->insert("4", "d"));
|
||||
ASSERT_EQ(1, pool.getNumUsedBlocks()); // Assuming that at least 2 items fit one block
|
||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
||||
ASSERT_EQ(2, map->getNumDynamicPairs());
|
||||
ASSERT_EQ(2, pool.getNumUsedBlocks()); // Assuming that at least 2 items fit one block
|
||||
ASSERT_EQ(4, map->getSize());
|
||||
|
||||
// Making sure everything is here
|
||||
ASSERT_EQ("a", *map->access("1"));
|
||||
@ -116,12 +119,11 @@ TEST(Map, Basic)
|
||||
ASSERT_EQ("4", *map->find(ValueFindPredicate("D")));
|
||||
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("foo"); // There's no such thing anyway
|
||||
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
||||
ASSERT_EQ(1, map->getNumDynamicPairs());
|
||||
ASSERT_EQ(2, pool.getNumUsedBlocks());
|
||||
ASSERT_EQ(3, map->getSize());
|
||||
|
||||
ASSERT_FALSE(map->access("1"));
|
||||
ASSERT_EQ("B", *map->access("2"));
|
||||
@ -135,9 +137,8 @@ TEST(Map, Basic)
|
||||
|
||||
// Removing another static
|
||||
map->remove("2");
|
||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
||||
ASSERT_EQ(0, map->getNumDynamicPairs());
|
||||
ASSERT_EQ(0, pool.getNumUsedBlocks()); // No dynamic entries left
|
||||
ASSERT_EQ(1, map->getSize());
|
||||
ASSERT_EQ(1, pool.getNumUsedBlocks()); // No dynamic entries left
|
||||
|
||||
ASSERT_FALSE(map->access("1"));
|
||||
ASSERT_FALSE(map->access("2"));
|
||||
@ -172,13 +173,7 @@ TEST(Map, Basic)
|
||||
ASSERT_FALSE(map->access("value"));
|
||||
|
||||
// Removing odd values - nearly half of them
|
||||
ASSERT_EQ(2, map->getNumStaticPairs());
|
||||
const unsigned num_dynamics_old = map->getNumDynamicPairs();
|
||||
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
|
||||
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("b", *map->insert("2", "b"));
|
||||
ASSERT_EQ(1, pool.getNumUsedBlocks());
|
||||
ASSERT_EQ(0, map->getNumStaticPairs());
|
||||
ASSERT_EQ(2, map->getNumDynamicPairs());
|
||||
ASSERT_EQ(2, map->getSize());
|
||||
|
||||
// Ordering
|
||||
ASSERT_TRUE(map->getByIndex(0)->match("1"));
|
||||
@ -238,7 +232,7 @@ TEST(Map, PrimitiveKey)
|
||||
static const int POOL_BLOCKS = 3;
|
||||
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));
|
||||
|
||||
// Empty
|
||||
|
||||
@ -71,7 +71,7 @@ TEST(Multiset, Basic)
|
||||
static const int POOL_BLOCKS = 3;
|
||||
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));
|
||||
|
||||
typedef SummationOperator<std::string> StringConcatenationOperator;
|
||||
@ -86,9 +86,8 @@ TEST(Multiset, Basic)
|
||||
// Static addion
|
||||
ASSERT_EQ("1", *mset->emplace("1"));
|
||||
ASSERT_EQ("2", *mset->emplace("2"));
|
||||
ASSERT_EQ(0, pool.getNumUsedBlocks());
|
||||
ASSERT_EQ(2, mset->getNumStaticItems());
|
||||
ASSERT_EQ(0, mset->getNumDynamicItems());
|
||||
ASSERT_LE(1, pool.getNumUsedBlocks()); // One or more
|
||||
ASSERT_EQ(2, mset->getSize());
|
||||
|
||||
// Ordering
|
||||
ASSERT_TRUE(*mset->getByIndex(0) == "1");
|
||||
@ -103,12 +102,11 @@ TEST(Multiset, Basic)
|
||||
// Dynamic addition
|
||||
ASSERT_EQ("3", *mset->emplace("3"));
|
||||
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_LE(1, pool.getNumUsedBlocks()); // One or more
|
||||
ASSERT_EQ(2, mset->getNumStaticItems());
|
||||
ASSERT_EQ(2, mset->getNumDynamicItems());
|
||||
ASSERT_EQ(4, mset->getSize());
|
||||
|
||||
// Making sure everything is here
|
||||
ASSERT_EQ("1", *mset->getByIndex(0));
|
||||
@ -117,9 +115,6 @@ TEST(Multiset, Basic)
|
||||
ASSERT_FALSE(mset->getByIndex(100));
|
||||
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
|
||||
ASSERT_EQ("1", *mset->find(FindPredicate("1")));
|
||||
ASSERT_EQ("2", *mset->find(FindPredicate("2")));
|
||||
@ -134,23 +129,10 @@ TEST(Multiset, Basic)
|
||||
ASSERT_EQ(4, op.accumulator.size());
|
||||
}
|
||||
|
||||
// Removing one static; ordering will be preserved
|
||||
// Removing some
|
||||
mset->removeFirst("1");
|
||||
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");
|
||||
ASSERT_EQ(0, mset->getNumStaticItems());
|
||||
ASSERT_EQ(2, mset->getNumDynamicItems());
|
||||
ASSERT_LE(1, pool.getNumUsedBlocks());
|
||||
|
||||
// Adding some new items
|
||||
unsigned max_value_integer = 0;
|
||||
@ -219,7 +201,7 @@ TEST(Multiset, PrimitiveKey)
|
||||
static const int POOL_BLOCKS = 3;
|
||||
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));
|
||||
|
||||
// Empty
|
||||
@ -269,7 +251,7 @@ TEST(Multiset, NoncopyableWithCounter)
|
||||
static const int POOL_BLOCKS = 3;
|
||||
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));
|
||||
|
||||
ASSERT_EQ(0, NoncopyableWithCounter::num_objects);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user