GlobalDataTypeRegistry partially implemented

This commit is contained in:
Pavel Kirienko
2014-02-27 11:30:38 +04:00
parent d71ec29fcf
commit 3b67b15ff5
6 changed files with 397 additions and 8 deletions
+3 -8
View File
@@ -120,17 +120,12 @@ public:
const DataTypeSignature& getSignature() const { return signature_; }
const char* getName() const { return name_; }
bool match(DataTypeKind kind, const char* name) const;
std::string toString() const;
bool operator!=(const DataTypeDescriptor& rhs) const { return !operator==(rhs); }
bool operator==(const DataTypeDescriptor& rhs) const
{
return
(kind_ == rhs.kind_) &&
(id_ == rhs.id_) &&
(signature_ == rhs.signature_) &&
!std::strcmp(name_, rhs.name_);
}
bool operator==(const DataTypeDescriptor& rhs) const;
};
}
@@ -0,0 +1,105 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
*/
#pragma once
#include <cassert>
#include <bitset>
#include <stdexcept>
#include <stdint.h>
#include <algorithm>
#include <uavcan/data_type.hpp>
#include <uavcan/internal/linked_list.hpp>
namespace uavcan
{
typedef std::bitset<DataTypeDescriptor::MaxDataTypeID + 1> DataTypeIDMask;
class GlobalDataTypeRegistry : Noncopyable
{
struct Entry : public LinkedListNode<Entry>
{
DataTypeDescriptor decriptor;
Entry() { }
Entry(DataTypeKind kind, uint16_t id, const DataTypeSignature& signature, const char* name)
: decriptor(kind, id, signature, name)
{ }
};
typedef LinkedListRoot<Entry> List;
List msgs_;
List srvs_;
bool frozen_;
GlobalDataTypeRegistry() : frozen_(false) { }
const List* selectList(DataTypeKind kind) const;
List* selectList(DataTypeKind kind);
void remove(Entry* dtd);
bool add(Entry* dtd);
public:
static GlobalDataTypeRegistry& instance();
/// Last call wins
template <typename Type>
bool assign(uint16_t id)
{
if (isFrozen())
return false;
static Entry entry;
remove(&entry);
entry = Entry(DataTypeKind(Type::DataTypeKind), id, Type::getDataTypeSignature(), Type::getDataTypeName());
return add(&entry);
}
/// Further calls to add() will fail
void freeze() { frozen_ = true; }
bool isFrozen() const { return frozen_; }
const DataTypeDescriptor* find(DataTypeKind kind, const char* name) const;
DataTypeSignature computeAggregateSignature(const DataTypeIDMask& msgs, const DataTypeIDMask& srvs) const;
void getDataTypeIDMask(DataTypeKind kind, DataTypeIDMask& mask) const;
unsigned int getNumMessageTypes() const { return msgs_.getLength(); }
unsigned int getNumServiceTypes() const { return srvs_.getLength(); }
#if UAVCAN_DEBUG
/// Required for unit testing
void reset()
{
frozen_ = false;
while (msgs_.get())
msgs_.remove(msgs_.get());
while (srvs_.get())
srvs_.remove(srvs_.get());
}
#endif
};
template <typename Type>
struct DefaultDataTypeRegistrator
{
DefaultDataTypeRegistrator()
{
if (!GlobalDataTypeRegistry::instance().assign<Type>(Type::DefaultDataTypeID))
{
#if UAVCAN_EXCEPTIONS
throw std::logic_error("Type registration failed");
#else
assert(0);
std::abort();
#endif
}
}
};
}
+15
View File
@@ -3,6 +3,7 @@
*/
#include <sstream>
#include <cstring>
#include <iomanip>
#include <cassert>
#include <uavcan/data_type.hpp>
@@ -38,6 +39,11 @@ TransferCRC DataTypeSignature::toTransferCRC() const
/*
* DataTypeDescriptor
*/
bool DataTypeDescriptor::match(DataTypeKind kind, const char* name) const
{
return (kind_ == kind) && !std::strcmp(name_, name);
}
std::string DataTypeDescriptor::toString() const
{
char kindch = '?';
@@ -53,4 +59,13 @@ std::string DataTypeDescriptor::toString() const
return os.str();
}
bool DataTypeDescriptor::operator==(const DataTypeDescriptor& rhs) const
{
return
(kind_ == rhs.kind_) &&
(id_ == rhs.id_) &&
(signature_ == rhs.signature_) &&
!std::strcmp(name_, rhs.name_);
}
}
+120
View File
@@ -0,0 +1,120 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
*/
#include <cassert>
#include <cstdlib>
#include <uavcan/global_data_type_registry.hpp>
namespace uavcan
{
const GlobalDataTypeRegistry::List* GlobalDataTypeRegistry::selectList(DataTypeKind kind) const
{
switch (kind)
{
case DataTypeKindMessage: return &msgs_;
case DataTypeKindService: return &srvs_;
default:
assert(0);
return NULL;
}
}
GlobalDataTypeRegistry::List* GlobalDataTypeRegistry::selectList(DataTypeKind kind)
{
switch (kind)
{
case DataTypeKindMessage: return &msgs_;
case DataTypeKindService: return &srvs_;
default:
assert(0);
return NULL;
}
}
void GlobalDataTypeRegistry::remove(Entry* dtd)
{
assert(dtd);
if (isFrozen())
return;
List* list = selectList(dtd->decriptor.getKind());
if (!list)
return;
Entry* p = list->get();
while (p)
{
Entry* const next = p->getNextListNode();
if (p->decriptor.match(dtd->decriptor.getKind(), dtd->decriptor.getName()))
list->remove(dtd);
p = next;
}
}
bool GlobalDataTypeRegistry::add(Entry* dtd)
{
assert(dtd);
if (isFrozen())
return false;
List* list = selectList(dtd->decriptor.getKind());
if (!list)
return false;
list->insert(dtd);
return true;
}
GlobalDataTypeRegistry& GlobalDataTypeRegistry::instance()
{
static GlobalDataTypeRegistry inst;
return inst;
}
const DataTypeDescriptor* GlobalDataTypeRegistry::find(DataTypeKind kind, const char* name) const
{
const List* list = selectList(kind);
if (list == NULL)
{
assert(0);
return NULL;
}
Entry* p = list->get();
while (p)
{
if (p->decriptor.match(kind, name))
return &p->decriptor;
p = p->getNextListNode();
}
return NULL;
}
DataTypeSignature GlobalDataTypeRegistry::computeAggregateSignature(const DataTypeIDMask& msgs,
const DataTypeIDMask& srvs) const
{
(void)msgs;
(void)srvs;
return DataTypeSignature::zero(); // TODO: implementation
}
void GlobalDataTypeRegistry::getDataTypeIDMask(DataTypeKind kind, DataTypeIDMask& mask) const
{
mask.reset();
const List* list = selectList(kind);
if (list == NULL)
{
assert(0);
return;
}
Entry* p = list->get();
while (p)
{
assert(p->decriptor.getKind() == kind);
mask[p->decriptor.getID()] = true;
p = p->getNextListNode();
}
}
}
+10
View File
@@ -102,3 +102,13 @@ TEST(DataTypeDescriptor, ToString)
uavcan::DataTypeSignature(0xdeadbeef1234), "Bar");
ASSERT_EQ("Bar:123m:0000deadbeef1234", desc.toString());
}
TEST(DataTypeDescriptor, Match)
{
uavcan::DataTypeDescriptor desc(uavcan::DataTypeKindMessage, 123,
uavcan::DataTypeSignature(0xdeadbeef1234), "namespace.TypeName");
ASSERT_TRUE(desc.match(uavcan::DataTypeKindMessage, "namespace.TypeName"));
ASSERT_FALSE(desc.match(uavcan::DataTypeKindMessage, "boo"));
ASSERT_FALSE(desc.match(uavcan::DataTypeKindService, "namespace.TypeName"));
}
@@ -0,0 +1,144 @@
/*
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
*/
#include <gtest/gtest.h>
#include <uavcan/global_data_type_registry.hpp>
namespace
{
struct DataTypeAMessage
{
enum { DefaultDataTypeID = 0 };
enum { DataTypeKind = uavcan::DataTypeKindMessage };
static uavcan::DataTypeSignature getDataTypeSignature() { return uavcan::DataTypeSignature(123); }
static const char* getDataTypeName() { return "my_namespace.DataTypeA"; }
};
struct DataTypeAService
{
enum { DefaultDataTypeID = 0 };
enum { DataTypeKind = uavcan::DataTypeKindService };
static uavcan::DataTypeSignature getDataTypeSignature() { return uavcan::DataTypeSignature(789); }
static const char* getDataTypeName() { return "my_namespace.DataTypeA"; }
};
struct DataTypeB
{
enum { DefaultDataTypeID = 42 };
enum { DataTypeKind = uavcan::DataTypeKindMessage };
static uavcan::DataTypeSignature getDataTypeSignature() { return uavcan::DataTypeSignature(456); }
static const char* getDataTypeName() { return "my_namespace.DataTypeB"; }
};
template <typename Type>
uavcan::DataTypeDescriptor extractDescriptor(uint16_t dtid = Type::DefaultDataTypeID)
{
return uavcan::DataTypeDescriptor(uavcan::DataTypeKind(Type::DataTypeKind), dtid,
Type::getDataTypeSignature(), Type::getDataTypeName());
}
}
TEST(GlobalDataTypeRegistry, Basic)
{
using uavcan::GlobalDataTypeRegistry;
GlobalDataTypeRegistry::instance().reset();
ASSERT_FALSE(GlobalDataTypeRegistry::instance().isFrozen());
ASSERT_EQ(0, GlobalDataTypeRegistry::instance().getNumMessageTypes());
ASSERT_EQ(0, GlobalDataTypeRegistry::instance().getNumServiceTypes());
uavcan::DataTypeIDMask dtmask;
dtmask.set();
GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindMessage, dtmask);
ASSERT_FALSE(dtmask.any());
dtmask.set();
GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindService, dtmask);
ASSERT_FALSE(dtmask.any());
/*
* Static registrations
*/
uavcan::DefaultDataTypeRegistrator<DataTypeAMessage> reg_DataTypeAMessage;
uavcan::DefaultDataTypeRegistrator<DataTypeB> reg_DataTypeB;
ASSERT_EQ(2, GlobalDataTypeRegistry::instance().getNumMessageTypes());
ASSERT_EQ(0, GlobalDataTypeRegistry::instance().getNumServiceTypes());
GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindMessage, dtmask);
ASSERT_TRUE(dtmask[0]);
ASSERT_TRUE(dtmask[42]);
dtmask[0] = dtmask[42] = false;
ASSERT_FALSE(dtmask.any());
/*
* Runtime registrations
*/
ASSERT_TRUE(GlobalDataTypeRegistry::instance().assign<DataTypeAService>(DataTypeAService::DefaultDataTypeID));
ASSERT_EQ(2, GlobalDataTypeRegistry::instance().getNumMessageTypes());
ASSERT_EQ(1, GlobalDataTypeRegistry::instance().getNumServiceTypes());
GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindService, dtmask);
ASSERT_TRUE(dtmask[0]);
dtmask[0] = false;
ASSERT_FALSE(dtmask.any());
/*
* Runtime re-registration
*/
ASSERT_TRUE(GlobalDataTypeRegistry::instance().assign<DataTypeAService>(147));
ASSERT_TRUE(GlobalDataTypeRegistry::instance().assign<DataTypeB>(741));
ASSERT_EQ(2, GlobalDataTypeRegistry::instance().getNumMessageTypes());
ASSERT_EQ(1, GlobalDataTypeRegistry::instance().getNumServiceTypes());
GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindMessage, dtmask);
ASSERT_TRUE(dtmask[0]);
ASSERT_TRUE(dtmask[741]);
dtmask[0] = dtmask[741] = false;
ASSERT_FALSE(dtmask.any());
GlobalDataTypeRegistry::instance().getDataTypeIDMask(uavcan::DataTypeKindService, dtmask);
ASSERT_TRUE(dtmask[147]);
dtmask[147] = false;
ASSERT_FALSE(dtmask.any());
/*
* Frozen state
*/
GlobalDataTypeRegistry::instance().freeze();
ASSERT_FALSE(GlobalDataTypeRegistry::instance().assign<DataTypeAService>(555)); // Rejected
ASSERT_FALSE(GlobalDataTypeRegistry::instance().assign<DataTypeAMessage>(999)); // Rejected
ASSERT_FALSE(GlobalDataTypeRegistry::instance().assign<DataTypeB>(888)); // Rejected
/*
* Searching
*/
const uavcan::DataTypeDescriptor* pdtd = NULL;
ASSERT_FALSE(GlobalDataTypeRegistry::instance().find(uavcan::DataTypeKindMessage, "Nonexistent"));
// Asking for service, but this is a message:
ASSERT_FALSE(GlobalDataTypeRegistry::instance().find(uavcan::DataTypeKindService, "my_namespace.DataTypeB"));
ASSERT_TRUE((pdtd = GlobalDataTypeRegistry::instance().find(uavcan::DataTypeKindMessage, "my_namespace.DataTypeB")));
ASSERT_EQ(extractDescriptor<DataTypeB>(741), *pdtd);
ASSERT_TRUE((pdtd = GlobalDataTypeRegistry::instance().find(uavcan::DataTypeKindMessage, "my_namespace.DataTypeA")));
ASSERT_EQ(extractDescriptor<DataTypeAMessage>(), *pdtd);
ASSERT_TRUE((pdtd = GlobalDataTypeRegistry::instance().find(uavcan::DataTypeKindService, "my_namespace.DataTypeA")));
ASSERT_EQ(extractDescriptor<DataTypeAService>(147), *pdtd);
/*
* Aggregate signature computation
*/
// TODO: test
/*
* Since we're dealing with singleton, we need to reset it for other tests to use
*/
GlobalDataTypeRegistry::instance().reset();
}