Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions include/Boolean.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once

#include <algorithm>
#include <istream>
#include <limits>

namespace ChimeraTK {

/********************************************************************************************************************/

/**
* Wrapper Class to avoid vector<bool> problems
*/
class Boolean {
public:
constexpr Boolean() : _value() {}
// We want implicit construction and conversion. Turn off the linter warnings.
// NOLINTBEGIN(hicpp-explicit-conversions, google-explicit-constructor)
constexpr Boolean(bool value) : _value(value) {}

constexpr operator const bool&() const { return _value; }
constexpr operator bool&() { return _value; }
// NOLINTEND(hicpp-explicit-conversions, google-explicit-constructor)
// TODO: test user types to numeric etc

private:
bool _value;
};

/********************************************************************************************************************/

inline std::istream& operator>>(std::istream& is, Boolean& value) {
std::string data;
is >> data;

std::transform(data.begin(), data.end(), data.begin(), [](unsigned char c) { return std::tolower(c); });

if(data == "false" || data == "0" || data.empty()) {
value = false;
}
else {
value = true;
}
return is;
}

/********************************************************************************************************************/

template<typename T>
constexpr bool isBoolean = std::is_same_v<T, bool> || std::is_same_v<T, Boolean>;

/********************************************************************************************************************/

// Define ChimeraTK::to_string to convert Boolean into string. We cannot define std::to_string(Boolean), as it would
// violate the C++ standard. The right definition can be autoselected with
// "using std::to_string; using ChimeraTK::to_string;".
// NOLINTNEXTLINE(readability-identifier-naming) - name is fixed by C++ standard
inline std::string to_string(Boolean& value) {
if(value) {
return "true";
}
return "false";
}

/********************************************************************************************************************/

} // namespace ChimeraTK

/********************************************************************************************************************/

namespace std {
template<>
class numeric_limits<ChimeraTK::Boolean> : public numeric_limits<bool> {};
} // namespace std

/********************************************************************************************************************/
1 change: 1 addition & 0 deletions include/DataConsistencyGroupHistorizedMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace ChimeraTK::DataConsistencyGroupDetail {
* reason, we do not provide add function with TransferElement.
*/
void add(TransferElementAbstractor& acc, unsigned histLen);
[[nodiscard]] bool isConsistent();

void updateCalled(const TransferElementID& transferElementID) { _updateCalled = transferElementID; }

Expand Down
101 changes: 46 additions & 55 deletions include/FixedPointConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include "Exception.h"
#include "NumericConverter.h"
#include "SupportedUserTypes.h"

#include <boost/fusion/algorithm.hpp>
Expand All @@ -17,7 +18,6 @@
#include <iostream>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>
#include <type_traits>

Expand Down Expand Up @@ -189,32 +189,14 @@ namespace ChimeraTK {
}

// compute minimum and maximum values in cooked representation
try {
boost::fusion::at_key<UserType>(_fpc->_minCookedValues) = _fpc->scalarToCooked<UserType>(_fpc->_minRawValue);
}
catch(boost::numeric::negative_overflow& e) {
boost::fusion::at_key<UserType>(_fpc->_minCookedValues) = std::numeric_limits<UserType>::min();
}
try {
boost::fusion::at_key<UserType>(_fpc->_maxCookedValues) = _fpc->scalarToCooked<UserType>(_fpc->_maxRawValue);
}
catch(boost::numeric::positive_overflow& e) {
boost::fusion::at_key<UserType>(_fpc->_maxCookedValues) = std::numeric_limits<UserType>::max();
}
boost::fusion::at_key<UserType>(_fpc->_minCookedValues) = _fpc->scalarToCooked<UserType>(_fpc->_minRawValue);
boost::fusion::at_key<UserType>(_fpc->_maxCookedValues) = _fpc->scalarToCooked<UserType>(_fpc->_maxRawValue);
}

private:
FixedPointConverter* _fpc;
};

/** define round type for the boost::numeric::converter */
template<class S>
struct Round {
static S nearbyint(S s) { return round(s); }

using round_style = boost::mpl::integral_c<std::float_round_style, std::round_to_nearest>;
};

/** helper function to test if UserTyped value is negative without triggering a
* compiler warning for unsigned user types */
template<typename UserType, typename std::enable_if<std::is_signed<UserType>{}, int>::type = 0>
Expand Down Expand Up @@ -359,12 +341,20 @@ namespace ChimeraTK {
return 0;
}
else {
std::cout << "Cooked for conv to raw: " << std::dec << cookedValue
<< ", min: " << boost::fusion::at_key<UserType>(_minCookedValues)
<< ", max: " << boost::fusion::at_key<UserType>(_maxCookedValues) << std::endl;

// Do a range check first. The later overflow check in the conversion is not
// sufficient, since we can have non-standard word sizes like 12 bits.
if(cookedValue < boost::fusion::at_key<UserType>(_minCookedValues)) {
std::cout << "Neg OF . min: " << boost::fusion::at_key<UserType>(_minCookedValues) << " raw: 0x" << std::hex
<< _minRawValue << std::endl;
return _minRawValue;
}
if(cookedValue > boost::fusion::at_key<UserType>(_maxCookedValues)) {
std::cout << "Pos OF . max: " << boost::fusion::at_key<UserType>(_maxCookedValues) << " raw: 0x" << std::hex
<< _maxRawValue << std::endl;
return _maxRawValue;
}

Expand All @@ -386,7 +376,6 @@ namespace ChimeraTK {
if(_isSigned && isNegative) {
rawValue = ~rawValue;
}

// return with bit mask applied
return rawValue & _usedBitsMask;
}
Expand All @@ -400,45 +389,38 @@ namespace ChimeraTK {
// needed. Negative and positive overflow exceptions need to be caught for some corner
// cases (e.g. number of fractional bits >= number of bits in total).
RawType raw;
try {
if(_isSigned) {
if constexpr(sizeof(RawType) == 4) {
using converter_signed =
boost::numeric::converter<int32_t, double, boost::numeric::conversion_traits<int32_t, double>,
boost::numeric::def_overflow_handler, Round<double>>;
raw = static_cast<RawType>(converter_signed::convert(d_cooked));
}
else if constexpr(sizeof(RawType) == 8) {
using converter_signed =
boost::numeric::converter<int64_t, double, boost::numeric::conversion_traits<int64_t, double>,
boost::numeric::def_overflow_handler, Round<double>>;
raw = static_cast<RawType>(converter_signed::convert(d_cooked));
}
if(_isSigned) {
if constexpr(sizeof(RawType) == 4) {
raw = RawType(numeric::convert<int32_t>(d_cooked));
}
else {
if constexpr(sizeof(RawType) == 4) {
using converter_unsigned =
boost::numeric::converter<uint32_t, double, boost::numeric::conversion_traits<uint32_t, double>,
boost::numeric::def_overflow_handler, Round<double>>;
raw = static_cast<RawType>(converter_unsigned::convert(d_cooked));
}
else if constexpr(sizeof(RawType) == 8) {
using converter_unsigned =
boost::numeric::converter<uint64_t, double, boost::numeric::conversion_traits<uint64_t, double>,
boost::numeric::def_overflow_handler, Round<double>>;
raw = static_cast<RawType>(converter_unsigned::convert(d_cooked));
}
else if constexpr(sizeof(RawType) == 8) {
raw = RawType(numeric::convert<int64_t>(d_cooked));
}
}
catch(boost::numeric::negative_overflow& e) {
raw = _minRawValue;
else {
if constexpr(sizeof(RawType) == 4) {
raw = RawType(numeric::convert<uint32_t>(d_cooked));
}
else if constexpr(sizeof(RawType) == 8) {
raw = RawType(numeric::convert<uint64_t>(d_cooked));
}
}
catch(boost::numeric::positive_overflow& e) {
raw = _maxRawValue;
std::cout << "ToRawFrac . Cooked: " << cookedValue << " d_cooked: " << d_cooked << " raw: 0x" << std::hex << raw
<< std::endl;
// when cookedValue is not zero and caculated raw is not zero, but still when _usedBitsMask is applied,
// the result is the zero - fix test testInt16_fraction16 for 32bits Raw value - cases ToRaw13 and ToRaw16
// if(cookedValue && raw && !(raw & _usedBitsMask)) {
// return _minRawValue;
//}
// apply bit mask
// NOLINTNEXTLINE(hicpp-signed-bitwise)

// negative overflow not detected by boost in case when converter is signed and number of bits in converter is
// smaller than in raw type
if(cookedValue && raw && (raw & _usedBitsMask) == 0) {
return _minRawValue;
}

// apply bit mask
// NOLINTNEXTLINE(hicpp-signed-bitwise)
return raw & _usedBitsMask;
}
}
Expand Down Expand Up @@ -548,6 +530,15 @@ namespace ChimeraTK {
// fractional bit coefficients note: we loop over one of the maps only, but
// initCoefficients() will fill all maps!
boost::fusion::for_each(_minCookedValues, initCoefficients(this));

std::cout << "\n\n"
<< std::dec << "RAW BYTES: " << sizeof(RawType) << ", signed: " << _isSigned << ", nBits: " << nBits
<< ", _fractionalBits: " << _fractionalBits << std::endl;
std::cout << "_signBitMask: " << std::hex << _signBitMask << std::endl;
std::cout << "_usedBitsMask: " << std::hex << _usedBitsMask << std::endl;
std::cout << "_unusedBitsMask: " << std::hex << _unusedBitsMask << std::endl;
std::cout << "_maxRawValue: " << std::hex << _maxRawValue << std::endl;
std::cout << "_minRawValue: " << std::hex << _minRawValue << std::endl;
}

/********************************************************************************************************************/
Expand Down
61 changes: 13 additions & 48 deletions include/IEEE754_SingleConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once

#include "SupportedUserTypes.h"
#include "NumericConverter.h"

#include <boost/numeric/conversion/cast.hpp>

Expand All @@ -12,51 +12,26 @@

namespace ChimeraTK {

template<typename SourceType, typename DestType>
struct RoundingRangeCheckingDataConverter {
/** define round type for the boost::numeric::converter */
template<class S>
struct Round {
static S nearbyint(S s) { return round(s); }

using round_style = boost::mpl::integral_c<std::float_round_style, std::round_to_nearest>;
};

using converter =
boost::numeric::converter<DestType, SourceType, boost::numeric::conversion_traits<DestType, SourceType>,
boost::numeric::def_overflow_handler, Round<SourceType>>;
};

template<typename SourceType>
struct RoundingRangeCheckingDataConverter<SourceType, Void> {
struct converter {
static Void convert(__attribute__((unused)) SourceType s) { return {}; }
};
};

template<typename DestType>
struct RoundingRangeCheckingDataConverter<Void, DestType> {
struct converter {
static DestType convert(__attribute__((unused)) Void s) { return 0.0; }
};
};

/** Needs to have the same interface as FixedPointConverter, except for the
* constructor. Converter for IEEE754 single precision (32bit) floating point.
/**
* Needs to have the same interface as FixedPointConverter, except for the constructor. Converter for IEEE754 single
* precision (32bit) floating point.
*/
struct IEEE754_SingleConverter {
template<typename CookedType, typename RAW_ITERATOR, typename COOKED_ITERATOR>
void vectorToCooked(
const RAW_ITERATOR& raw_begin, const RAW_ITERATOR& raw_end, const COOKED_ITERATOR& cooked_begin) const {
// Note: IEEE754_SingleConverter must be instantiable for all raw user types but can only be used for int32_t
assert((std::is_same<typename std::iterator_traits<RAW_ITERATOR>::value_type, int32_t>::value));

static_assert(std::is_same<typename std::iterator_traits<RAW_ITERATOR>::value_type, int8_t>::value ||
std::is_same<typename std::iterator_traits<RAW_ITERATOR>::value_type, int16_t>::value ||
std::is_same<typename std::iterator_traits<RAW_ITERATOR>::value_type, int32_t>::value,
"RAW_ITERATOR template argument must be an iterator with value type equal to int8_t, int16_t or int32_t.");

static_assert(std::is_same<typename std::iterator_traits<COOKED_ITERATOR>::value_type, CookedType>::value,
"COOKED_ITERATOR template argument must be an iterator with value type equal to the CookedType template "
"argument.");

vectorToCooked_impl<CookedType, RAW_ITERATOR, COOKED_ITERATOR>::impl(raw_begin, raw_end, cooked_begin);
}

Expand Down Expand Up @@ -92,7 +67,7 @@ namespace ChimeraTK {
memcpy(&genericRepresentation, &(*it), sizeof(float));

// Step 2: convert the float to the cooked type
*cooked_begin = RoundingRangeCheckingDataConverter<float, CookedType>::converter::convert(genericRepresentation);
*cooked_begin = numeric::convert<CookedType>(genericRepresentation);
++cooked_begin;
}
}
Expand All @@ -101,21 +76,11 @@ namespace ChimeraTK {
uint32_t IEEE754_SingleConverter::toRaw(CookedType cookedValue) const {
// step 1: convert from cooked to the generic representation in the CPU
// (float)
float genericRepresentation;
try {
genericRepresentation = RoundingRangeCheckingDataConverter<CookedType, float>::converter::convert(cookedValue);
}
catch(boost::numeric::positive_overflow&) {
genericRepresentation = FLT_MAX;
}
catch(boost::numeric::negative_overflow&) {
genericRepresentation = -FLT_MAX;
}
float genericRepresentation = numeric::convert<float>(cookedValue);

// step 2: reinterpret float to int32 to send it to the device
void* warningAvoider = &genericRepresentation;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
int32_t rawValue = *(reinterpret_cast<int32_t*>(warningAvoider));
int32_t rawValue;
memcpy(&rawValue, &genericRepresentation, sizeof(float));

return rawValue;
}
Expand All @@ -125,8 +90,8 @@ namespace ChimeraTK {
static void impl(const RAW_ITERATOR& raw_begin, const RAW_ITERATOR& raw_end, COOKED_ITERATOR cooked_begin) {
for(auto it = raw_begin; it != raw_end; ++it) {
// Step 1: convert the raw data to the "generic" representation in the CPU: float
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
float genericRepresentation = *(reinterpret_cast<const float*>(&(*it)));
float genericRepresentation;
memcpy(&genericRepresentation, &(*it), sizeof(float));

// Step 2: convert the float to the cooked type
*cooked_begin = std::to_string(genericRepresentation);
Expand Down
4 changes: 4 additions & 0 deletions include/NDRegisterAccessorDecorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ namespace ChimeraTK {
for(size_t i = 0; i < _target->getNumberOfChannels(); ++i) {
buffer_2D[i].resize(_target->getNumberOfSamples());
}
// Here we do not take over the buffer contents of the target, since specific implementations
// of NDRegisterAccessorDecorator will handle this differently.
// In case UserType=TargetUserType a buffer swap would be efficient, but the specific implementation should
// have that under control.

if(target->isReadTransactionInProgress()) {
// In case accessor was already used from ReadAnyGroup, it has readTransactionInProgress set. We must copy
Expand Down
Loading