TSLQueue(TSLQueue &&other);
TSLQueue &operator=(TSLQueue &&other);
+ // in place of std::optional which is only available in C++17
+ struct Entry {
+ Entry();
+ Entry(const T& value);
+ Entry(T&& rvalue);
+
+ // enable copy
+ Entry(const Entry& other) = default;
+ Entry &operator =(const Entry& other) = default;
+
+ // enable move
+ Entry(Entry&& other) = default;
+ Entry &operator =(Entry&& other) = default;
+
+ enum Type {
+ NONE,
+ SOME
+ } type;
+ T value;
+
+ bool has_value() const;
+ operator bool () const;
+ T& operator *();
+ const T& operator *() const;
+ };
+
void push(const T &data);
bool push_nb(const T &data);
- std::optional<T> top();
- std::optional<T> top_nb();
+ Entry top();
+ Entry top_nb();
bool pop();
- std::optional<T> top_and_pop();
- std::optional<T> top_and_pop_and_empty(bool *isEmpty);
- std::optional<T> top_and_pop_and_rsize(unsigned long *rsize);
+ Entry top_and_pop();
+ Entry top_and_pop_and_empty(bool *isEmpty);
+ Entry top_and_pop_and_rsize(unsigned long *rsize);
void clear();
bool empty();
class TSLQIter {
public:
- TSLQIter(std::mutex &mutex,
+ TSLQIter(std::mutex *mutex,
std::weak_ptr<TSLQNode> currentNode,
unsigned long *msize);
~TSLQIter();
- std::optional<T> current();
+ Entry current();
bool next();
bool prev();
bool remove();
private:
- std::lock_guard<std::mutex> lock;
+ std::mutex *mutex;
std::weak_ptr<TSLQNode> currentNode;
unsigned long *const msize;
template <typename T>
TSLQueue<T>::TSLQueue(TSLQueue &&other)
{
- std::lock_guard lock(other.mutex);
+ std::lock_guard<std::mutex> lock(other.mutex);
head = std::move(other.head);
tail = std::move(other.tail);
msize = std::move(other.msize);
template <typename T>
TSLQueue<T> & TSLQueue<T>::operator=(TSLQueue &&other) {
- std::scoped_lock lock(mutex, other.mutex);
+ std::lock_guard<std::mutex> lock(mutex);
+ std::lock_guard<std::mutex> otherLock(other.mutex);
head = std::move(other.head);
tail = std::move(other.tail);
msize = std::move(other.msize);
}
+template <typename T>
+TSLQueue<T>::Entry::Entry() :
+ type(Type::NONE),
+ value()
+{}
+
+template <typename T>
+TSLQueue<T>::Entry::Entry(const T& value) :
+ type(Type::SOME),
+ value(value)
+{}
+
+template <typename T>
+TSLQueue<T>::Entry::Entry(T&& value) :
+ type(Type::SOME),
+ value(std::forward<T>(value))
+{}
+
+template <typename T>
+bool TSLQueue<T>::Entry::has_value() const {
+ return type == Type::SOME;
+}
+
+template <typename T>
+TSLQueue<T>::Entry::operator bool() const {
+ return has_value();
+}
+
+template <typename T>
+T& TSLQueue<T>::Entry::operator *() {
+ return value;
+}
+
+template <typename T>
+const T& TSLQueue<T>::Entry::operator *() const {
+ return value;
+}
+
template <typename T>
void TSLQueue<T>::push(const T &data) {
- std::lock_guard lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
auto newNode = std::make_shared<TSLQNode>();
newNode->data = std::make_unique<T>(data);
}
template <typename T>
-std::optional<T> TSLQueue<T>::top() {
- std::lock_guard lock(mutex);
+typename TSLQueue<T>::Entry TSLQueue<T>::top() {
+ std::lock_guard<std::mutex> lock(mutex);
if(head->next != tail) {
assert(head->next->data);
- return *head->next->data.get();
+ return Entry(*head->next->data.get());
} else {
- return std::nullopt;
+ return Entry();
}
}
template <typename T>
-std::optional<T> TSLQueue<T>::top_nb() {
+typename TSLQueue<T>::Entry TSLQueue<T>::top_nb() {
if(mutex.try_lock()) {
- std::optional<T> ret = std::nullopt;
+ Entry ret;
if(head->next != tail) {
assert(head->next->data);
- ret = *head->next->data.get();
+ ret = Entry(*head->next->data.get());
}
mutex.unlock();
return ret;
} else {
- return std::nullopt;
+ return Entry();
}
}
template <typename T>
bool TSLQueue<T>::pop() {
- std::lock_guard lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
if(head->next == tail) {
return false;
} else {
}
template <typename T>
-std::optional<T> TSLQueue<T>::top_and_pop() {
- std::optional<T> ret = std::nullopt;
- std::lock_guard lock(mutex);
+typename TSLQueue<T>::Entry TSLQueue<T>::top_and_pop() {
+ Entry ret;
+ std::lock_guard<std::mutex> lock(mutex);
if(head->next != tail) {
assert(head->next->data);
- ret = *head->next->data.get();
+ ret = Entry(*head->next->data.get());
auto& newNext = head->next->next;
newNext->prev = head;
}
template <typename T>
-std::optional<T> TSLQueue<T>::top_and_pop_and_empty(bool *isEmpty) {
- std::optional<T> ret = std::nullopt;
- std::lock_guard lock(mutex);
+typename TSLQueue<T>::Entry TSLQueue<T>::top_and_pop_and_empty(bool *isEmpty) {
+ Entry ret;
+ std::lock_guard<std::mutex> lock(mutex);
if(head->next == tail) {
if(isEmpty) {
*isEmpty = true;
}
} else {
assert(head->next->data);
- ret = *head->next->data.get();
+ ret = Entry(*head->next->data.get());
auto& newNext = head->next->next;
newNext->prev = head;
}
template <typename T>
-std::optional<T> TSLQueue<T>::top_and_pop_and_rsize(unsigned long *rsize) {
- std::optional<T> ret = std::nullopt;
- std::lock_guard lock(mutex);
+typename TSLQueue<T>::Entry TSLQueue<T>::top_and_pop_and_rsize(unsigned long *rsize) {
+ Entry ret;
+ std::lock_guard<std::mutex> lock(mutex);
if(head->next == tail) {
if(rsize) {
*rsize = 0;
}
} else {
assert(head->next->data);
- ret = *head->next->data.get();
+ ret = Entry(*head->next->data.get());
auto& newNext = head->next->next;
newNext->prev = head;
template <typename T>
void TSLQueue<T>::clear() {
- std::lock_guard lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
head->next = tail;
tail->prev = head;
template <typename T>
bool TSLQueue<T>::empty() {
- std::lock_guard lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
return head->next == tail;
}
template <typename T>
unsigned long TSLQueue<T>::size() {
- std::lock_guard lock(mutex);
+ std::lock_guard<std::mutex> lock(mutex);
return msize;
}
}
template <typename T>
-TSLQueue<T>::TSLQIter::TSLQIter(std::mutex &mutex,
+TSLQueue<T>::TSLQIter::TSLQIter(std::mutex *mutex,
std::weak_ptr<TSLQNode> currentNode,
unsigned long *msize) :
-lock(mutex),
+mutex(mutex),
currentNode(currentNode),
msize(msize)
{
+ mutex->lock();
}
template <typename T>
TSLQueue<T>::TSLQIter::~TSLQIter() {
+ mutex->unlock();
}
template <typename T>
-std::optional<T> TSLQueue<T>::TSLQIter::current() {
+typename TSLQueue<T>::Entry TSLQueue<T>::TSLQIter::current() {
std::shared_ptr<TSLQNode> currentNode = this->currentNode.lock();
assert(currentNode);
if(currentNode->isNormal()) {
- return *currentNode->data.get();
+ return Entry(*currentNode->data.get());
} else {
- return std::nullopt;
+ return Entry();
}
}
template <typename T>
typename TSLQueue<T>::TSLQIter TSLQueue<T>::begin() {
- return TSLQIter(mutex, head->next, &msize);
+ return TSLQIter(&mutex, head->next, &msize);
}
#endif
do {
auto optE = internalEvents.top_and_pop();
if(optE.has_value()) {
- switch(optE.value().type) {
+ switch(optE.value.type) {
case UDPC_ET_REQUEST_CONNECT:
{
unsigned char *sk = nullptr;
UDPC::ConnectionData newCon(
false,
this,
- optE.value().conId.addr,
- optE.value().conId.scope_id,
- optE.value().conId.port,
+ optE.value.conId.addr,
+ optE.value.conId.scope_id,
+ optE.value.conId.port,
#ifdef UDPC_LIBSODIUM_ENABLED
- flags.test(2) && optE.value().v.enableLibSodium != 0,
+ flags.test(2) && optE.value.v.enableLibSodium != 0,
sk, pk);
#else
false,
UDPC_LoggingType::UDPC_ERROR,
"Failed to init ConnectionData instance (libsodium "
"init fail) while client establishing connection with ",
- UDPC_atostr((UDPC_HContext)this, optE.value().conId.addr),
+ UDPC_atostr((UDPC_HContext)this, optE.value.conId.addr),
" port ",
- optE.value().conId.port);
+ optE.value.conId.port);
continue;
}
newCon.sent = std::chrono::steady_clock::now() - UDPC::INIT_PKT_INTERVAL_DT;
#endif
}
- if(conMap.find(optE.value().conId) == conMap.end()) {
+ if(conMap.find(optE.value.conId) == conMap.end()) {
conMap.insert(std::make_pair(
- optE.value().conId,
+ optE.value.conId,
std::move(newCon)));
- auto addrConIter = addrConMap.find(optE.value().conId.addr);
+ auto addrConIter = addrConMap.find(optE.value.conId.addr);
if(addrConIter == addrConMap.end()) {
auto insertResult = addrConMap.insert(std::make_pair(
- optE.value().conId.addr,
+ optE.value.conId.addr,
std::unordered_set<UDPC_ConnectionId, UDPC::ConnectionIdHasher>{}));
assert(insertResult.second &&
"new connection insert into addrConMap must not fail");
addrConIter = insertResult.first;
}
- addrConIter->second.insert(optE.value().conId);
+ addrConIter->second.insert(optE.value.conId);
UDPC_CHECK_LOG(this,
UDPC_LoggingType::UDPC_INFO,
"Client initiating connection to ",
- UDPC_atostr((UDPC_HContext)this, optE.value().conId.addr),
+ UDPC_atostr((UDPC_HContext)this, optE.value.conId.addr),
" port ",
- optE.value().conId.port,
+ optE.value.conId.port,
" ...");
} else {
UDPC_CHECK_LOG(this,
UDPC_LoggingType::UDPC_WARNING,
"Client initiate connection, already connected to peer ",
- UDPC_atostr((UDPC_HContext)this, optE.value().conId.addr),
+ UDPC_atostr((UDPC_HContext)this, optE.value.conId.addr),
" port ",
- optE.value().conId.port);
+ optE.value.conId.port);
}
}
break;
UDPC::ConnectionData newCon(
false,
this,
- optE.value().conId.addr,
- optE.value().conId.scope_id,
- optE.value().conId.port,
+ optE.value.conId.addr,
+ optE.value.conId.scope_id,
+ optE.value.conId.port,
#ifdef UDPC_LIBSODIUM_ENABLED
true,
sk, pk);
false,
sk, pk);
assert(!"compiled without libsodium support");
- delete[] optE.value().v.pk;
+ delete[] optE.value.v.pk;
break;
#endif
if(newCon.flags.test(5)) {
- delete[] optE.value().v.pk;
+ delete[] optE.value.v.pk;
UDPC_CHECK_LOG(this,
UDPC_LoggingType::UDPC_ERROR,
"Failed to init ConnectionData instance (libsodium "
"init fail) while client establishing connection with ",
- UDPC_atostr((UDPC_HContext)this, optE.value().conId.addr),
+ UDPC_atostr((UDPC_HContext)this, optE.value.conId.addr),
" port ",
- optE.value().conId.port);
+ optE.value.conId.port);
continue;
}
newCon.sent = std::chrono::steady_clock::now() - UDPC::INIT_PKT_INTERVAL_DT;
// set peer public key
std::memcpy(
newCon.peer_pk,
- optE.value().v.pk,
+ optE.value.v.pk,
crypto_sign_PUBLICKEYBYTES);
newCon.flags.set(7);
}
- delete[] optE.value().v.pk;
+ delete[] optE.value.v.pk;
- if(conMap.find(optE.value().conId) == conMap.end()) {
+ if(conMap.find(optE.value.conId) == conMap.end()) {
conMap.insert(std::make_pair(
- optE.value().conId,
+ optE.value.conId,
std::move(newCon)));
- auto addrConIter = addrConMap.find(optE.value().conId.addr);
+ auto addrConIter = addrConMap.find(optE.value.conId.addr);
if(addrConIter == addrConMap.end()) {
auto insertResult = addrConMap.insert(std::make_pair(
- optE.value().conId.addr,
+ optE.value.conId.addr,
std::unordered_set<UDPC_ConnectionId, UDPC::ConnectionIdHasher>{}));
assert(insertResult.second &&
"new connection insert into addrConMap must not fail");
addrConIter = insertResult.first;
}
- addrConIter->second.insert(optE.value().conId);
+ addrConIter->second.insert(optE.value.conId);
UDPC_CHECK_LOG(this,
UDPC_LoggingType::UDPC_INFO,
"Client initiating connection to ",
- UDPC_atostr((UDPC_HContext)this, optE.value().conId.addr),
+ UDPC_atostr((UDPC_HContext)this, optE.value.conId.addr),
" port ",
- optE.value().conId.port,
+ optE.value.conId.port,
" ...");
} else {
UDPC_CHECK_LOG(this,
UDPC_LoggingType::UDPC_WARNING,
"Client initiate connection, already connected to peer ",
- UDPC_atostr((UDPC_HContext)this, optE.value().conId.addr),
+ UDPC_atostr((UDPC_HContext)this, optE.value.conId.addr),
" port ",
- optE.value().conId.port);
+ optE.value.conId.port);
}
}
break;
case UDPC_ET_REQUEST_DISCONNECT:
- if(optE.value().v.dropAllWithAddr != 0) {
+ if(optE.value.v.dropAllWithAddr != 0) {
// drop all connections with same address
- auto addrConIter = addrConMap.find(optE.value().conId.addr);
+ auto addrConIter = addrConMap.find(optE.value.conId.addr);
if(addrConIter != addrConMap.end()) {
for(auto identIter = addrConIter->second.begin();
identIter != addrConIter->second.end();
}
} else {
// drop only specific connection with addr and port
- auto iter = conMap.find(optE.value().conId);
+ auto iter = conMap.find(optE.value.conId);
if(iter != conMap.end()) {
if(iter->second.flags.test(4)) {
idMap.erase(iter->second.id);
}
- auto addrConIter = addrConMap.find(optE.value().conId.addr);
+ auto addrConIter = addrConMap.find(optE.value.conId.addr);
if(addrConIter != addrConMap.end()) {
- addrConIter->second.erase(optE.value().conId);
+ addrConIter->second.erase(optE.value.conId);
if(addrConIter->second.empty()) {
addrConMap.erase(addrConIter);
}
while(true) {
auto next = sendIter.current();
if(next) {
- if(auto iter = conMap.find(next.value().receiver);
- iter != conMap.end()) {
+ auto iter = conMap.find(next.value.receiver);
+ if(iter != conMap.end()) {
if(iter->second.sendPkts.size() >= UDPC_QUEUED_PKTS_MAX_SIZE) {
- if(notQueued.find(next.value().receiver) == notQueued.end()) {
- notQueued.insert(next.value().receiver);
+ if(notQueued.find(next.value.receiver) == notQueued.end()) {
+ notQueued.insert(next.value.receiver);
UDPC_CHECK_LOG(this,
UDPC_LoggingType::UDPC_DEBUG,
"Not queueing packet to ",
UDPC_atostr((UDPC_HContext)this,
- next.value().receiver.addr),
+ next.value.receiver.addr),
", port = ",
- next.value().receiver.port,
+ next.value.receiver.port,
", connection's queue reached max size");
}
if(sendIter.next()) {
break;
}
}
- iter->second.sendPkts.push_back(next.value());
+ iter->second.sendPkts.push_back(next.value);
if(sendIter.remove()) {
continue;
} else {
break;
}
} else {
- if(dropped.find(next.value().receiver) == dropped.end()) {
+ if(dropped.find(next.value.receiver) == dropped.end()) {
UDPC_CHECK_LOG(this,
UDPC_LoggingType::UDPC_WARNING,
"Dropped queued packets to ",
UDPC_atostr(
(UDPC_HContext)this,
- next.value().receiver.addr),
+ next.value.receiver.addr),
", port = ",
- next.value().receiver.port,
+ next.value.receiver.port,
" due to connection not existing");
- dropped.insert(next.value().receiver);
+ dropped.insert(next.value.receiver);
}
if(sendIter.remove()) {
continue;
}
bool UDPC::isBigEndian() {
- static std::optional<bool> isBigEndian = std::nullopt;
- if(isBigEndian) {
- return *isBigEndian;
+ /*
+ * 0 - unset
+ * 1 - is big endian
+ * 2 - is not big endian
+ */
+ static char isBigEndian = 0;
+ if(isBigEndian != 0) {
+ return isBigEndian == 1;
}
union {
uint32_t i;
char c[4];
} bint = {0x01020304};
- isBigEndian = (bint.c[0] == 1);
- return *isBigEndian;
+ isBigEndian = (bint.c[0] == 1 ? 1 : 2);
+ return isBigEndian;
}
void UDPC::preparePacket(
#endif
while(!UDPC_ctx->internalEvents.empty()) {
auto optE = UDPC_ctx->internalEvents.top_and_pop();
- if(optE.has_value() && optE.value().type == UDPC_ET_REQUEST_CONNECT_PK) {
- delete[] optE.value().v.pk;
+ if(optE.has_value() && optE.value.type == UDPC_ET_REQUEST_CONNECT_PK) {
+ delete[] optE.value.v.pk;
}
}
UDPC_ctx->_contextIdentifier = 0;
auto optE = c->externalEvents.top_and_pop_and_rsize(remaining);
if(optE) {
- return optE.value();
+ return optE.value;
} else {
return UDPC_Event{UDPC_ET_NONE, UDPC_create_id_anyaddr(0), 0};
}
for(int i = 0; i < 10; ++i) {
auto v = q.top();
ASSERT_TRUE(v.has_value());
- EXPECT_EQ(v.value(), i);
+ EXPECT_EQ(v.value, i);
EXPECT_EQ(10 - i, q.size());
EXPECT_TRUE(q.pop());
}
for(int i = 0; i < 10; ++i) {
auto v = q.top_nb();
ASSERT_TRUE(v.has_value());
- EXPECT_EQ(v.value(), i);
+ EXPECT_EQ(v.value, i);
EXPECT_EQ(q.size(), 10 - i);
v = q.top_and_pop();
ASSERT_TRUE(v.has_value());
- EXPECT_EQ(v.value(), i);
+ EXPECT_EQ(v.value, i);
}
{
EXPECT_EQ(q.size(), 10 - i);
auto v = q.top_and_pop_and_empty(&isEmpty);
ASSERT_TRUE(v.has_value());
- EXPECT_EQ(v.value(), i);
+ EXPECT_EQ(v.value, i);
EXPECT_EQ(i == 9, isEmpty);
}
EXPECT_EQ(q.size(), 0);
EXPECT_EQ(q.size(), 100 - i);
auto v = q.top_and_pop();
ASSERT_TRUE(v.has_value());
- EXPECT_GE(v.value(), 0);
- EXPECT_LE(v.value(), 100);
+ EXPECT_GE(v.value, 0);
+ EXPECT_LE(v.value, 100);
EXPECT_EQ(i == 99, q.empty());
}
EXPECT_EQ(q.size(), 0);
int i = 0;
auto op = iter.current();
while(op.has_value()) {
- EXPECT_EQ(op.value(), i++);
+ EXPECT_EQ(op.value, i++);
if(i < 10) {
EXPECT_TRUE(iter.next());
} else {
EXPECT_TRUE(iter.prev());
op = iter.current();
while(op.has_value()) {
- EXPECT_EQ(op.value(), --i);
+ EXPECT_EQ(op.value, --i);
if(i > 0) {
EXPECT_TRUE(iter.prev());
} else {
auto op = iter.current();
EXPECT_TRUE(op.has_value());
- EXPECT_EQ(op.value(), 4);
+ EXPECT_EQ(op.value, 4);
EXPECT_TRUE(iter.prev());
op = iter.current();
EXPECT_TRUE(op.has_value());
- EXPECT_EQ(op.value(), 2);
+ EXPECT_EQ(op.value, 2);
}
EXPECT_EQ(q.size(), 9);
// check that "3" was removed from queue
int i = 0;
- std::optional<int> op;
+ TSLQueue<int>::Entry op;
while(!q.empty()) {
op = q.top();
EXPECT_TRUE(op.has_value());
- EXPECT_EQ(i++, op.value());
+ EXPECT_EQ(i++, op.value);
if(i == 3) {
++i;
}
while(!q.empty()) {
op = q.top();
EXPECT_TRUE(op.has_value());
- EXPECT_EQ(i++, op.value());
+ EXPECT_EQ(i++, op.value);
EXPECT_TRUE(q.pop());
}
EXPECT_TRUE(iter.next());
op = iter.current();
EXPECT_TRUE(op.has_value());
- if(op.value() == 3) {
+ if(op.value == 3) {
EXPECT_FALSE(iter.remove());
break;
}
while(!q.empty()) {
op = q.top();
EXPECT_TRUE(op.has_value());
- EXPECT_EQ(i++, op.value());
+ EXPECT_EQ(i++, op.value);
EXPECT_TRUE(q.pop());
if(i == 3) {
EXPECT_TRUE(q.empty());