/*             ----> DO NOT REMOVE THE FOLLOWING NOTICE <----

                   Copyright (c) 2014-2015 Datalight, Inc.
                       All Rights Reserved Worldwide.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; use version 2 of the License.

    This program is distributed in the hope that it will be useful,
    but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*  Businesses and individuals that for commercial or other reasons cannot
    comply with the terms of the GPLv2 license may obtain a commercial license
    before incorporating Reliance Edge into proprietary software for
    distribution in any form.  Visit http://www.datalight.com/reliance-edge for
    more information.
*/
/** @file
    @brief This header contains macros which deviate from MISRA C:2012
*/
#ifndef REDDEVIATIONS_H
#define REDDEVIATIONS_H


/** @brief Append a suffix to a constant so that it is an unsigned 64-bit value.

    Usages of this macro deviate from MISRA C:2012 Rule 1.2 (advisory).  The
    rule prohibits the use of language extensions.  The ULL suffix became part
    of the C standard with C99.  Since this code base adheres to C89, use of
    this suffix is a language extension.  Reliance Edge needs to deal with
    64-bit quantities, which by convention are explicitly suffixed.  In at
    least one case, with the INODE_SIZE_MAX macro, the code needs a way to force
    a constant to be 64-bits even though its value is not so large that it would
    be automatically promoted to 64-bits.  Thus the need for this macro and the
    deviation.  In practice, the ULL suffix has proven to be a nearly universal
    extension among C89 compilers.

    As rule 19.2 is advisory, a deviation record is not required.  This notice
    is the only record of the deviation.  PC-Lint does not issue an error for
    this deviation so there is no error inhibition option.

    Usages of this macro also deviate from MISRA C:2012 Rule 20.10 (advisory).
    The rule prohibits use of the ## preprocessor operator.  The code is not
    obscure, and the operator is used only once, so this is deemed to be safe.

    As rule 20.10 is advisory, a deviation record is not required.  This notice
    is the only record of the deviation.

    Consistent use of this macro, even in non MISRA C code, is encouraged to
    make it easier to search for 64-bit values.

*/
#define UINT64_SUFFIX(number) (number##ULL)


/** @brief Append a suffix to a constant so that it is a signed 64-bit value.

    Usages of this macro deviate from MISRA C:2012 Rule 1.2 (advisory).  See the
    description of UINT64_SUFFIX() for details.

    Usages of this macro deviate from MISRA C:2012 Rule 20.10 (advisory).  See
    the description of UINT64_SUFFIX() for details.
*/
#define INT64_SUFFIX(number) (number##LL)


/** @brief Cast a pointer to a const uint8_t pointer.

    All usages of this macro deviate from MISRA C:2012 Rule 11.5 (advisory).
    Because there are no alignment requirements for a uint8_t pointer, this is
    safe.  However, it is technically a deviation from the rule.

    As Rule 11.5 is advisory, a deviation record is not required.  This notice
    and the PC-Lint error inhibition option are the only records of the
    deviation.
*/
#define CAST_VOID_PTR_TO_CONST_UINT8_PTR(PTR) ((const uint8_t *)(PTR))


/** @brief Cast a pointer to a uint8_t pointer.

    All usages of this macro deviate from MISRA C:2012 Rule 11.5 (advisory).
    Because there are no alignment requirements for a uint8_t pointer, this is
    safe.  However, it is technically a deviation from the rule.

    As Rule 11.5 is advisory, a deviation record is not required.  This notice
    and the PC-Lint error inhibition option are the only records of the
    deviation.
*/
#define CAST_VOID_PTR_TO_UINT8_PTR(PTR) ((uint8_t *)(PTR))


/** @brief Cast a pointer to a const uint32_t pointer.

    Usages of this macro may deviate from MISRA C:2012 Rule 11.5 (advisory).
    It is only used in cases where the pointer is known to be aligned, and thus
    it is safe to do so.

    As Rule 11.5 is advisory, a deviation record is not required.  This notice
    and the PC-Lint error inhibition option are the only records of the
    deviation.

    Usages of this macro may deviate from MISRA C:2012 Rule 11.3 (required).
    As Rule 11.3 is required, a separate deviation record is required.

    Regarding the cast to (const void *): this is there to placate some
    compilers which emit warnings when a type with lower alignment requirements
    (such as const uint8_t *) is cast to a type with higher alignment
    requirements.  In the places where this macro is used, the pointer is
    checked to be of sufficient alignment.
*/
#define CAST_CONST_UINT32_PTR(PTR) ((const uint32_t *)(const void *)(PTR))


/** @brief Cast a pointer to a pointer to (void **).

    Usages of this macro deviate from MISRA C:2012 Rule 11.3 (required).
    It is only used for populating a node structure pointer with a buffer
    pointer.  Buffer pointers are 8-byte aligned, thus it is safe to do so.

    As Rule 11.3 is required, a separate deviation record is required.
*/
#define CAST_VOID_PTR_PTR(PTRPTR) ((void **)(PTRPTR))


/** @brief Create a two-dimensional byte array which is safely aligned.

    Usages of this macro deviate from MISRA C:2012 Rule 19.2 (advisory).
    A union is required to force alignment of the block buffers, which are used
    to access metadata nodes, which must be safely aligned for 64-bit types.

    As rule 19.2 is advisory, a deviation record is not required.  This notice
    and the PC-Lint error inhibition option are the only records of the
    deviation.
*/
#define ALIGNED_2D_BYTE_ARRAY(un, nam, size1, size2)    \
    union                                               \
    {                                                   \
        uint8_t     nam[size1][size2];                  \
        uint64_t    DummyAlign;                         \
    } un


/** @brief Determine whether RedMemMove() must copy memory in the forward
           direction, instead of in the reverse.

    In order to copy between overlapping memory regions, RedMemMove() must copy
    forward if the destination memory is lower, and backward if the destination
    memory is higher.  Failure to do so would yield incorrect results.

    The only way to make this determination without gross inefficiency is to
    use pointer comparison.  Pointer comparisons are undefined unless both
    pointers point within the same object or array (or one element past the end
    of the array); see section 6.3.8 of ANSI C89.  While RedMemMove() is
    normally only used when memory regions overlap, which would not result in
    undefined behavior, it (like memmove()) is supposed to work even for non-
    overlapping regions, which would make this function invoke undefined
    behavior.  Experience has shown the pointer comparisons of this sort behave
    intuitively on common platforms, even though the behavior is undefined.  For
    those platforms where this is not the case, this implementation of memmove()
    should be replaced with an alternate one.

    Usages of this macro deviate from MISRA-C:2012 Rule 18.3 (required).  As
    Rule 18.3 is required, a separate deviation record is required.
*/
#define MEMMOVE_MUST_COPY_FORWARD(dest, src) ((dest) < (src))


/** @brief Cast a pointer to a (const DIRENT *).

    Usages of this macro deviate from MISRA-C:2012 Rule 11.3 (required).
    It is used for populating a directory entry structure pointer with a
    buffer pointer.  Buffer pointers are 8-byte aligned, and DIRENT only
    requires 4-byte alignment, thus the typecast is safe.

    As Rule 11.3 is required, a separate deviation record is required.
*/
#define CAST_CONST_DIRENT_PTR(PTR) ((const DIRENT *)(PTR))


/** @brief Determine whether a pointer is aligned.

    A pointer is aligned if its address is an even multiple of
    ::REDCONF_ALIGNMENT_SIZE.

    This is used in the slice-by-8 RedCrc32Update() function, which needs to
    know whether a pointer is aligned, since the slice-by-8 algorithm needs to
    access the memory in an aligned fashion, and if the pointer is not aligned,
    this can result in faults or suboptimal performance (depending on platform).

    There is no way to perform this check without deviating from MISRA C rules
    against casting pointers to integer types.  Usage of this macro deviates
    from MISRA C:2012 Rule 11.4 (advisory).  The main rationale the rule cites
    against converting pointers to integers is that the chosen integer type may
    not be able to represent the pointer; this is a non-issue here since we use
    uintptr_t.  The text says the rule still applies when using uintptr_t due to
    concern about unaligned pointers, but that is not an issue here since the
    integer value of the pointer is not saved and not converted back into a
    pointer and dereferenced.  The result of casting a pointer to a sufficiently
    large integer is implementation-defined, but macros similar to this one have
    been used by Datalight for a long time in a wide variety of environments and
    they have always worked as expected.

    As Rule 11.4 is advisory, a deviation record is not required.  This notice
    and the PC-Lint error inhibition option are the only records of the
    deviation.

    @note PC-Lint also thinks this macro as it is used below violates Rule 11.6
          (required).  This is a false positive, since Rule 11.6 only applies to
          void pointers.  Below, we use it on a pointer-to-object (uint8_t *),
          which is covered by Rule 11.4.
*/
#define IS_ALIGNED_PTR(ptr) (((uintptr_t)(ptr) & (REDCONF_ALIGNMENT_SIZE - 1U)) == 0U)


#endif

