Compare commits

..

4 Commits

Author SHA1 Message Date
Giulio Eulisse
ac84955f72 Merge 602807e6f9 into c11506e958 2025-01-24 03:47:14 +00:00
Giulio Eulisse
c11506e958 feat(EventManager): Out of line some methods 2025-01-23 15:35:26 +01:00
Giulio Eulisse
602807e6f9 Introduce a SmallVector Container 2024-05-23 15:10:06 +02:00
Giulio Eulisse
a461bd0ae7 Hide actual container from the API 2024-05-23 15:10:06 +02:00
7 changed files with 1555 additions and 41 deletions

View File

@@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2012-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2012-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@@ -55,6 +55,7 @@ if(BUILD_FAIRMQ)
ProgOptionsFwd.h
Properties.h
PropertyOutput.h
SmallVector.h
Socket.h
StateMachine.h
States.h
@@ -119,6 +120,7 @@ if(BUILD_FAIRMQ)
Channel.cxx
Device.cxx
DeviceRunner.cxx
EventManager.cxx
JSONParser.cxx
MemoryResources.cxx
Plugin.cxx
@@ -126,6 +128,7 @@ if(BUILD_FAIRMQ)
PluginServices.cxx
ProgOptions.cxx
Properties.cxx
SmallVector.cxx
StateMachine.cxx
States.cxx
SuboptParser.cxx

20
fairmq/EventManager.cxx Normal file
View File

@@ -0,0 +1,20 @@
/********************************************************************************
* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include "EventManager.h"
#include <string>
#include <typeindex>
template std::shared_ptr<
fair::mq::EventManager::Signal<fair::mq::PropertyChangeAsString, std::string>>
fair::mq::EventManager::GetSignal<fair::mq::PropertyChangeAsString, std::string>(
const std::pair<std::type_index, std::type_index>& key) const;
template void fair::mq::EventManager::Subscribe<fair::mq::PropertyChangeAsString, std::string>(
const std::string& subscriber,
std::function<void(typename fair::mq::PropertyChangeAsString::KeyType, std::string)>);

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -57,27 +57,8 @@ class EventManager
template<typename E, typename ...Args>
using Signal = boost::signals2::signal<void(typename E::KeyType, Args...)>;
template<typename E, typename ...Args>
auto Subscribe(const std::string& subscriber, std::function<void(typename E::KeyType, Args...)> callback) -> void
{
const std::type_index event_type_index{typeid(E)};
const std::type_index callback_type_index{typeid(std::function<void(typename E::KeyType, Args...)>)};
const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
const auto connectionsKey = std::make_pair(subscriber, signalsKey);
const auto connection = GetSignal<E, Args...>(signalsKey)->connect(callback);
{
std::lock_guard<std::mutex> lock{fMutex};
if (fConnections.find(connectionsKey) != fConnections.end())
{
fConnections.at(connectionsKey).disconnect();
fConnections.erase(connectionsKey);
}
fConnections.insert({connectionsKey, connection});
}
}
template<typename E, typename... Args>
auto Subscribe(const std::string& subscriber, std::function<void(typename E::KeyType, Args...)> callback) -> void;
template<typename E, typename ...Args>
auto Unsubscribe(const std::string& subscriber) -> void
@@ -119,12 +100,17 @@ class EventManager
mutable std::mutex fMutex;
template<typename E, typename ...Args>
auto GetSignal(const SignalsKey& key) const -> std::shared_ptr<Signal<E, Args...>>
{
auto GetSignal(const SignalsKey& key) const -> std::shared_ptr<Signal<E, Args...>>;
}; /* class EventManager */
struct PropertyChangeAsString : Event<std::string> {};
template<typename E, typename... Args>
auto EventManager::GetSignal(const SignalsKey& key) const -> std::shared_ptr<Signal<E, Args...>>
{
std::lock_guard<std::mutex> lock{fMutex};
if (fSignals.find(key) == fSignals.end())
{
if (fSignals.find(key) == fSignals.end()) {
// wrapper is needed because boost::signals2::signal is neither copyable nor movable
// and I don't know how else to insert it into the map
auto signal = std::make_shared<Signal<E, Args...>>();
@@ -132,8 +118,40 @@ class EventManager
}
return boost::any_cast<std::shared_ptr<Signal<E, Args...>>>(fSignals.at(key));
}
template<typename E, typename... Args>
auto EventManager::Subscribe(const std::string& subscriber,
std::function<void(typename E::KeyType, Args...)> callback) -> void
{
const std::type_index event_type_index{typeid(E)};
const std::type_index callback_type_index{
typeid(std::function<void(typename E::KeyType, Args...)>)};
const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
const auto connectionsKey = std::make_pair(subscriber, signalsKey);
const auto connection = GetSignal<E, Args...>(signalsKey)->connect(callback);
{
std::lock_guard<std::mutex> lock{fMutex};
if (fConnections.find(connectionsKey) != fConnections.end()) {
fConnections.at(connectionsKey).disconnect();
fConnections.erase(connectionsKey);
}
}; /* class EventManager */
fConnections.insert({connectionsKey, connection});
}
}
extern template std::shared_ptr<
fair::mq::EventManager::Signal<fair::mq::PropertyChangeAsString, std::string>>
fair::mq::EventManager::GetSignal<fair::mq::PropertyChangeAsString, std::string>(
const std::pair<std::type_index, std::type_index>& key) const;
extern template void
fair::mq::EventManager::Subscribe<fair::mq::PropertyChangeAsString, std::string>(
const std::string& subscriber,
std::function<void(typename fair::mq::PropertyChangeAsString::KeyType, std::string)>);
} // namespace fair::mq

View File

@@ -11,6 +11,7 @@
#include <algorithm> // std::move
#include <fairmq/Message.h> // fair::mq::MessagePtr
#include <fairmq/SmallVector.h>
#include <iterator> // std::back_inserter
#include <utility> // std::move, std::forward
#include <vector> // std::vector
@@ -21,7 +22,7 @@ namespace fair::mq {
/// Message, used for sending multi-part messages
struct Parts
{
using container = std::vector<MessagePtr>;
using container = fair::llvm_copy::SmallVector<MessagePtr, 8>;
using size_type = container::size_type;
using reference = container::reference;
using const_reference = container::const_reference;
@@ -71,9 +72,9 @@ struct Parts
// const_reference operator[](size_type index) const { return fParts[index]; }
[[deprecated("Redundant, dereference at call site e.g. '*(parts.At(index))' instead.")]]
Message& AtRef(size_type index) { return *(fParts.at(index)); }
reference At(size_type index) { return fParts.at(index); }
const_reference At(size_type index) const { return fParts.at(index); }
Message& AtRef(size_type index) { return *(fParts[index]); }
reference At(size_type index) { return fParts[index]; }
const_reference At(size_type index) const { return fParts[index]; }
size_type Size() const noexcept { return fParts.size(); }
bool Empty() const noexcept { return fParts.empty(); }
@@ -82,10 +83,10 @@ struct Parts
// range access
iterator begin() noexcept { return fParts.begin(); }
const_iterator begin() const noexcept { return fParts.begin(); }
const_iterator cbegin() const noexcept { return fParts.cbegin(); }
const_iterator cbegin() const noexcept { return fParts.begin(); }
iterator end() noexcept { return fParts.end(); }
const_iterator end() const noexcept { return fParts.end(); }
const_iterator cend() const noexcept { return fParts.cend(); }
const_iterator cend() const noexcept { return fParts.end(); }
container fParts{};
};

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -29,7 +29,6 @@ using Property = boost::any;
using Properties = std::map<std::string, Property>;
struct PropertyChange : Event<std::string> {};
struct PropertyChangeAsString : Event<std::string> {};
class PropertyHelper
{

120
fairmq/SmallVector.cxx Normal file
View File

@@ -0,0 +1,120 @@
//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the SmallVector class.
//
//===----------------------------------------------------------------------===//
#include <SmallVector.h>
//#include "llvm/Support/MemAlloc.h"
#include <cstdint>
using namespace fair::llvm_copy;
// Check that no bytes are wasted and everything is well-aligned.
namespace {
struct Struct16B {
alignas(16) void *X;
};
struct Struct32B {
alignas(32) void *X;
};
}
static_assert(sizeof(SmallVector<void *, 0>) ==
sizeof(unsigned) * 2 + sizeof(void *),
"wasted space in SmallVector size 0");
static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
"wrong alignment for 16-byte aligned T");
static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
"wrong alignment for 32-byte aligned T");
static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
"missing padding for 16-byte aligned T");
static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
"missing padding for 32-byte aligned T");
static_assert(sizeof(SmallVector<void *, 1>) ==
sizeof(unsigned) * 2 + sizeof(void *) * 2,
"wasted space in SmallVector size 1");
static_assert(sizeof(SmallVector<char, 0>) ==
sizeof(void *) * 2 + sizeof(void *),
"1 byte elements have word-sized type for size and capacity");
// Note: Moving this function into the header may cause performance regression.
template <class Size_T>
static size_t getNewCapacity(size_t MinSize, size_t , size_t OldCapacity) {
constexpr size_t MaxSize = std::numeric_limits<Size_T>::max();
// In theory 2*capacity can overflow if the capacity is 64 bit, but the
// original capacity would never be large enough for this to be a problem.
size_t NewCapacity = 2 * OldCapacity + 1; // Always grow.
return std::clamp(NewCapacity, MinSize, MaxSize);
}
template <class Size_T>
void *SmallVectorBase<Size_T>::replaceAllocation(void *NewElts, size_t TSize,
size_t NewCapacity,
size_t VSize) {
void *NewEltsReplace = malloc(NewCapacity * TSize);
if (VSize)
memcpy(NewEltsReplace, NewElts, VSize * TSize);
free(NewElts);
return NewEltsReplace;
}
// Note: Moving this function into the header may cause performance regression.
template <class Size_T>
void *SmallVectorBase<Size_T>::mallocForGrow(void *FirstEl, size_t MinSize,
size_t TSize,
size_t &NewCapacity) {
NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity());
// Even if capacity is not 0 now, if the vector was originally created with
// capacity 0, it's possible for the malloc to return FirstEl.
void *NewElts = malloc(NewCapacity * TSize);
if (NewElts == FirstEl)
NewElts = replaceAllocation(NewElts, TSize, NewCapacity);
return NewElts;
}
// Note: Moving this function into the header may cause performance regression.
template <class Size_T>
void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize,
size_t TSize) {
size_t NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity());
void *NewElts;
if (BeginX == FirstEl) {
NewElts = malloc(NewCapacity * TSize);
if (NewElts == FirstEl)
NewElts = replaceAllocation(NewElts, TSize, NewCapacity);
// Copy the elements over. No need to run dtors on PODs.
memcpy(NewElts, this->BeginX, size() * TSize);
} else {
// If this wasn't grown from the inline copy, grow the allocated space.
NewElts = realloc(this->BeginX, NewCapacity * TSize);
if (NewElts == FirstEl)
NewElts = replaceAllocation(NewElts, TSize, NewCapacity, size());
}
this->set_allocation_range(NewElts, NewCapacity);
}
template class fair::llvm_copy::SmallVectorBase<uint32_t>;
// Disable the uint64_t instantiation for 32-bit builds.
// Both uint32_t and uint64_t instantiations are needed for 64-bit builds.
// This instantiation will never be used in 32-bit builds, and will cause
// warnings when sizeof(Size_T) > sizeof(size_t).
#if SIZE_MAX > UINT32_MAX
template class fair::llvm_copy::SmallVectorBase<uint64_t>;
// Assertions to ensure this #if stays in sync with SmallVectorSizeType.
static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint64_t),
"Expected SmallVectorBase<uint64_t> variant to be in use.");
#else
static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint32_t),
"Expected SmallVectorBase<uint32_t> variant to be in use.");
#endif

1353
fairmq/SmallVector.h Normal file

File diff suppressed because it is too large Load Diff