Skip to content

Commit

Permalink
Merge pull request eclipse-iceoryx#1698 from ApexAI/iox-1394-fix-axiv…
Browse files Browse the repository at this point in the history
…ion-violations-in-cxx-function

Iox 1394 fix axivion violations in cxx function
  • Loading branch information
MatthiasKillat authored Oct 18, 2022
2 parents 45ccd1c + d1bf26c commit 9a96e81
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020 - 2021 by Apex.AI Inc. All rights reserved.
// Copyright (c) 2020 - 2022 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -42,7 +42,7 @@ template <uint64_t Capacity, uint64_t Align = 1>
/// @NOLINTJUSTIFICATION static_storage provides uninitialized memory, correct initialization is the users
/// responsibility whenever memory with "allocate" is acquired
/// @NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
class static_storage
class static_storage final
{
public:
constexpr static_storage() noexcept = default;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2020 - 2021 by Apex.AI Inc. All rights reserved.
// Copyright (c) 2020 - 2022 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -26,12 +26,12 @@ namespace cxx
template <uint64_t Capacity, uint64_t Align>
constexpr uint64_t static_storage<Capacity, Align>::align_mismatch(uint64_t align, uint64_t requiredAlign) noexcept
{
auto r = align % requiredAlign;
const auto r = align % requiredAlign;

// If r != 0 we are not aligned with requiredAlign and need to add r to an align
// aligned address to be aligned with requiredAlign.
// In the worst case r is requiredAlign - 1
return r != 0 ? requiredAlign - r : 0;
return (r != 0) ? (requiredAlign - r) : 0;
}

template <uint64_t Capacity, uint64_t Align>
Expand All @@ -54,6 +54,8 @@ template <typename T>
constexpr T* static_storage<Capacity, Align>::allocate() noexcept
{
static_assert(is_allocatable<T>(), "type does not fit into static storage");
// AXIVION Next Construct AutosarC++19_03-M5.2.8: conversion to typed pointer is intentional,
// it is correctly aligned and points to sufficient memory for a T by design
return static_cast<T*>(allocate(alignof(T), sizeof(T)));
}

Expand All @@ -65,7 +67,7 @@ constexpr void* static_storage<Capacity, Align>::allocate(const uint64_t align,
return nullptr; // cannot allocate, already in use
}

size_t space = Capacity;
size_t space{Capacity};
m_ptr = m_bytes;
if (std::align(align, size, m_ptr, space) != nullptr)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class storable_function;
/// @tparam ReturnType The return type of the stored callable.
/// @tparam Args The arguments of the stored callable.
template <uint64_t Capacity, typename ReturnType, typename... Args>
class storable_function<Capacity, signature<ReturnType, Args...>>
class storable_function<Capacity, signature<ReturnType, Args...>> final
{
public:
using StorageType = static_storage<Capacity>;
Expand All @@ -56,9 +56,10 @@ class storable_function<Capacity, signature<ReturnType, Args...>>
typename = typename std::enable_if<std::is_class<Functor>::value
&& is_invocable_r<ReturnType, Functor, Args...>::value,
void>::type>
/// @NOLINTJUSTIFICATION the storable function should implicitly behave like any generic constructor, adding
/// explicit would require a static_cast. Furthermore, the storable_functor stores a copy
/// which avoids implicit misbehaviors or ownership problems caused by implicit conversion.
// AXIVION Next Construct AutosarC++19_03-A12.1.4: implicit conversion of functors is intentional,
// the storable function should implicitly behave like any generic constructor, adding
// explicit would require a static_cast. Furthermore, the storable_functor stores a copy
// which avoids implicit misbehaviors or ownership problems caused by implicit conversion.
/// @NOLINTNEXTLINE(hicpp-explicit-conversions)
storable_function(const Functor& functor) noexcept;

Expand Down Expand Up @@ -93,19 +94,13 @@ class storable_function<Capacity, signature<ReturnType, Args...>>
/// @param args arguments to invoke the stored function with
/// @return return value of the stored function
///
/// @note 1) Invoking the function if there is no stored function (i.e. operator bool returns false)
/// leads to terminate being called.
///
/// 2) Deliberately not noexcept but can only throw if the stored callable can throw an exception (hence
/// will never throw if we use only our own noexcept functions).
///
/// 3) If arguments are passed by value, the copy constructor may be invoked twice:
/// @note 1) If arguments are passed by value, the copy constructor may be invoked twice:
/// once when passing the arguments to operator() and once when they are passed to the stored callable
/// itself. This appears to be unavoidable and also happens in std::function.
/// The user can always provide a wrapped callable which takes a reference,
/// which is generally preferable for large objects anyway.
///
/// 4) Arguments of class type cannot have the move constructor explicitly deleted since the arguments
/// 2) Arguments of class type cannot have the move constructor explicitly deleted since the arguments
/// must be forwarded internally which is done by move or, if no move is specified, by copy.
/// If the move operation is explicitly deleted the compiler will not fall back to copy but emit an error.
/// Not specifying move or using a default implementation is fine.
Expand Down Expand Up @@ -136,7 +131,7 @@ class storable_function<Capacity, signature<ReturnType, Args...>>
// This means storable_function cannot be used where pointers become invalid, e.g. across process boundaries
// Therefore we cannot store a storable_function in shared memory (the same holds for std::function).
// This is inherent to the type erasure technique we (have to) use.
struct operations
struct operations final
{
// function pointers defining copy, move and destroy semantics
void (*copyFunction)(const storable_function& src, storable_function& dest){nullptr};
Expand All @@ -150,11 +145,11 @@ class storable_function<Capacity, signature<ReturnType, Args...>>
operations& operator=(operations&& other) noexcept = default;
~operations() = default;

void copy(const storable_function& src, storable_function& dest) noexcept;
void copy(const storable_function& src, storable_function& dest) const noexcept;

void move(storable_function& src, storable_function& dest) noexcept;
void move(storable_function& src, storable_function& dest) const noexcept;

void destroy(storable_function& f) noexcept;
void destroy(storable_function& f) const noexcept;
};

private:
Expand Down Expand Up @@ -187,13 +182,16 @@ class storable_function<Capacity, signature<ReturnType, Args...>>
static void destroy(storable_function& f) noexcept;

template <typename CallableType>
static ReturnType invoke(void* callable, Args&&... args);
static ReturnType invoke(void* callable, Args&&... args) noexcept;

static void copyFreeFunction(const storable_function& src, storable_function& dest) noexcept;

static void moveFreeFunction(storable_function& src, storable_function& dest) noexcept;

static ReturnType invokeFreeFunction(void* callable, Args&&... args);
// AXIVION Next Construct AutosarC++19_03-M7.1.2: callable cannot be const void* since
// m_invoker is initialized with this function and has to work with functors as well
// (functors may change due to invocation)
static ReturnType invokeFreeFunction(void* callable, Args&&... args) noexcept;
};

/// @brief swap two storable functions
Expand Down
Loading

0 comments on commit 9a96e81

Please sign in to comment.