First stab at global refactoring of memory management - the library builds, but unit tests are failing horribly

This commit is contained in:
Pavel Kirienko 2015-10-14 08:29:50 +03:00
parent 0643879922
commit be84897ed6
33 changed files with 203 additions and 756 deletions

View File

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

View File

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

View File

@ -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_)
{

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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_);

View File

@ -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));
}

View File

@ -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() { }

View File

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

View File

@ -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();

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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());

View File

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

View File

@ -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));
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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