diff --git a/sys/include/seq.h b/sys/include/seq.h new file mode 100644 index 0000000000..942c0d4a2f --- /dev/null +++ b/sys/include/seq.h @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2015 Cenk Gündoğan + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup sys_seq Serial Number Arithmetic + * @ingroup sys + * @brief Serial Number Arithmetic (RFC 1982) + * @{ + * + * @file + * @brief Serial Number Arithmetic (RFC 1982) + * @see + * RFC 1982 - Serial Number Arithmetic + * + * + * @author Cenk Gündoğan + */ + +#ifndef SEQ_H +#define SEQ_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Maximum for the addition of a positive integer. X denotes the size of the space + */ +#define SEQ_LIMIT(X) (X >> 1) + +/** + * @brief A 8 bit sequence number + */ +typedef uint8_t seq8_t; + +/** + * @brief A 16 bit sequence number + */ +typedef uint16_t seq16_t; + +/** + * @brief A 32 bit sequence number + */ +typedef uint32_t seq32_t; + +/** + * @brief A 64 bit sequence number + */ +typedef uint64_t seq64_t; + +/** + * @brief Addition of a 8 bit sequence number @p s and a positive integer @p n + * in the serial number @p space + * @see + * 3.1. Addition + * + * @param[in] s sequence number + * @param[in] n positive integer in the range of [0 .. ((@p space / 2) - 1)] + * @param[in] space serial number space must be a power of 2 minus 1 + * @return s + n, if valid + * @return s, if n is out of range + */ +seq8_t seq8_adds(seq8_t s, uint8_t n, uint8_t space); + +/** + * @brief Addition of a 8 bit sequence number @p s and a positive integer @p n + * in the serial number space UINT8_MAX + * @see + * 3.1. Addition + * + * @param[in] s sequence number + * @param[in] n positive integer in the range of [0 .. 127] + * @return s + n, if valid + * @return s, if n is out of range + */ +static inline seq8_t seq8_add(seq8_t s, uint8_t n) +{ + return seq8_adds(s, n, UINT8_MAX); +} + +/** + * @brief Increment a sequence number @p s by 1 in the serial number @p space + * @param[in] s sequence number + * @param[in] space serial number space must be a power of 2 minus 1 + * @return s + 1 + */ +static inline seq8_t seq8_incs(seq8_t s, uint8_t space) +{ + return seq8_adds(s, 1, space); +} + +/** + * @brief Increment a sequence number @p s by 1 in the serial number space UINT8_MAX + * @param[in] s sequence number + * @return s + 1 + */ +static inline seq8_t seq8_inc(seq8_t s) +{ + return seq8_adds(s, 1, UINT8_MAX); +} + +/** + * @brief Compare sequence numbers @p s1, @p s2 in the serial number @p space + * @see + * 3.2. Comparison + * + * @param[in] s1 first sequence number + * @param[in] s2 second sequence number + * @param[in] space serial number space must be a power of 2 minus 1 + * @return -1, if s1 < s2 + * @return 0, if s1 == s2 + * @return 1, if s1 > s2 + * @return -EINVAL, if comparison of the pair (s1,s2) is undefined + */ +int seq8_compares(seq8_t s1, seq8_t s2, uint8_t space); + +/** + * @brief Compare sequence numbers @p s1, @p s2 in the serial number space UINT8_MAX + * @see + * 3.2. Comparison + * + * @param[in] s1 first sequence number + * @param[in] s2 second sequence number + * @return -1, if s1 < s2 + * @return 0, if s1 == s2 + * @return 1, if s1 > s2 + * @return -EINVAL, if comparison of the pair (s1,s2) is undefined + */ +static inline int seq8_compare(seq8_t s1, seq8_t s2) +{ + return seq8_compares(s1, s2, UINT8_MAX); +} + +/** + * @brief Addition of a 16 bit sequence number @p s and a positive integer @p n + * in the serial number @p space + * @see + * 3.1. Addition + * + * @param[in] s sequence number + * @param[in] n positive integer in the range of [0 .. ((@p space / 2) - 1)] + * @param[in] space serial number space must be a power of 2 minus 1 + * @return s + n, if valid + * @return s, if n is out of range + */ +seq16_t seq16_adds(seq16_t s, uint16_t n, uint16_t space); + +/** + * @brief Addition of a 16 bit sequence number @p s and a positive integer @p n + * in the serial number space UINT16_MAX + * @see + * 3.1. Addition + * + * @param[in] s sequence number + * @param[in] n positive integer in the range of [0 .. 127] + * @return s + n, if valid + * @return s, if n is out of range + */ +static inline seq16_t seq16_add(seq16_t s, uint16_t n) +{ + return seq16_adds(s, n, UINT16_MAX); +} + +/** + * @brief Increment a sequence number @p s by 1 in the serial number @p space + * @param[in] s sequence number + * @param[in] space serial number space must be a power of 2 minus 1 + * @return s + 1 + */ +static inline seq16_t seq16_incs(seq16_t s, uint16_t space) +{ + return seq16_adds(s, 1, space); +} + +/** + * @brief Increment a sequence number @p s by 1 in the serial number space UINT16_MAX + * @param[in] s sequence number + * @return s + 1 + */ +static inline seq16_t seq16_inc(seq16_t s) +{ + return seq16_adds(s, 1, UINT16_MAX); +} + +/** + * @brief Compare sequence numbers @p s1, @p s2 in the serial number @p space + * @see + * 3.2. Comparison + * + * @param[in] s1 first sequence number + * @param[in] s2 second sequence number + * @param[in] space serial number space must be a power of 2 minus 1 + * @return -1, if s1 < s2 + * @return 0, if s1 == s2 + * @return 1, if s1 > s2 + * @return -EINVAL, if comparison of the pair (s1,s2) is undefined + */ +int seq16_compares(seq16_t s1, seq16_t s2, uint16_t space); + +/** + * @brief Compare sequence numbers @p s1, @p s2 in the serial number space UINT16_MAX + * @see + * 3.2. Comparison + * + * @param[in] s1 first sequence number + * @param[in] s2 second sequence number + * @return -1, if s1 < s2 + * @return 0, if s1 == s2 + * @return 1, if s1 > s2 + * @return -EINVAL, if comparison of the pair (s1,s2) is undefined + */ +static inline int seq16_compare(seq16_t s1, seq16_t s2) +{ + return seq16_compares(s1, s2, UINT16_MAX); +} + +/** + * @brief Addition of a 32 bit sequence number @p s and a positive integer @p n + * in the serial number @p space + * @see + * 3.1. Addition + * + * @param[in] s sequence number + * @param[in] n positive integer in the range of [0 .. ((@p space / 2) - 1)] + * @param[in] space serial number space must be a power of 2 minus 1 + * @return s + n, if valid + * @return s, if n is out of range + */ +seq32_t seq32_adds(seq32_t s, uint32_t n, uint32_t space); + +/** + * @brief Addition of a 32 bit sequence number @p s and a positive integer @p n + * in the serial number space UINT32_MAX + * @see + * 3.1. Addition + * + * @param[in] s sequence number + * @param[in] n positive integer in the range of [0 .. 127] + * @return s + n, if valid + * @return s, if n is out of range + */ +static inline seq32_t seq32_add(seq32_t s, uint32_t n) +{ + return seq32_adds(s, n, UINT32_MAX); +} + +/** + * @brief Increment a sequence number @p s by 1 in the serial number @p space + * @param[in] s sequence number + * @param[in] space serial number space must be a power of 2 minus 1 + * @return s + 1 + */ +static inline seq32_t seq32_incs(seq32_t s, uint32_t space) +{ + return seq32_adds(s, 1, space); +} + +/** + * @brief Increment a sequence number @p s by 1 in the serial number space UINT32_MAX + * @param[in] s sequence number + * @return s + 1 + */ +static inline seq32_t seq32_inc(seq32_t s) +{ + return seq32_adds(s, 1, UINT32_MAX); +} + +/** + * @brief Compare sequence numbers @p s1, @p s2 in the serial number @p space + * @see + * 3.2. Comparison + * + * @param[in] s1 first sequence number + * @param[in] s2 second sequence number + * @param[in] space serial number space must be a power of 2 minus 1 + * @return -1, if s1 < s2 + * @return 0, if s1 == s2 + * @return 1, if s1 > s2 + * @return -EINVAL, if comparison of the pair (s1,s2) is undefined + */ +int seq32_compares(seq32_t s1, seq32_t s2, uint32_t space); + +/** + * @brief Compare sequence numbers @p s1, @p s2 in the serial number space UINT32_MAX + * @see + * 3.2. Comparison + * + * @param[in] s1 first sequence number + * @param[in] s2 second sequence number + * @return -1, if s1 < s2 + * @return 0, if s1 == s2 + * @return 1, if s1 > s2 + * @return -EINVAL, if comparison of the pair (s1,s2) is undefined + */ +static inline int seq32_compare(seq32_t s1, seq32_t s2) +{ + return seq32_compares(s1, s2, UINT32_MAX); +} + +/** + * @brief Addition of a 64 bit sequence number @p s and a positive integer @p n + * in the serial number @p space + * @see + * 3.1. Addition + * + * @param[in] s sequence number + * @param[in] n positive integer in the range of [0 .. ((@p space / 2) - 1)] + * @param[in] space serial number space must be a power of 2 minus 1 + * @return s + n, if valid + * @return s, if n is out of range + */ +seq64_t seq64_adds(seq64_t s, uint64_t n, uint64_t space); + +/** + * @brief Addition of a 64 bit sequence number @p s and a positive integer @p n + * in the serial number space UINT64_MAX + * @see + * 3.1. Addition + * + * @param[in] s sequence number + * @param[in] n positive integer in the range of [0 .. 127] + * @return s + n, if valid + * @return s, if n is out of range + */ +static inline seq64_t seq64_add(seq64_t s, uint64_t n) +{ + return seq64_adds(s, n, UINT64_MAX); +} + +/** + * @brief Increment a sequence number @p s by 1 in the serial number @p space + * @param[in] s sequence number + * @param[in] space serial number space must be a power of 2 minus 1 + * @return s + 1 + */ +static inline seq64_t seq64_incs(seq64_t s, uint64_t space) +{ + return seq64_adds(s, 1, space); +} + +/** + * @brief Increment a sequence number @p s by 1 in the serial number space UINT64_MAX + * @param[in] s sequence number + * @return s + 1 + */ +static inline seq64_t seq64_inc(seq64_t s) +{ + return seq64_adds(s, 1, UINT64_MAX); +} + +/** + * @brief Compare sequence numbers @p s1, @p s2 in the serial number @p space + * @see + * 3.2. Comparison + * + * @param[in] s1 first sequence number + * @param[in] s2 second sequence number + * @param[in] space serial number space must be a power of 2 minus 1 + * @return -1, if s1 < s2 + * @return 0, if s1 == s2 + * @return 1, if s1 > s2 + * @return -EINVAL, if comparison of the pair (s1,s2) is undefined + */ +int seq64_compares(seq64_t s1, seq64_t s2, uint64_t space); + +/** + * @brief Compare sequence numbers @p s1, @p s2 in the serial number space UINT64_MAX + * @see + * 3.2. Comparison + * + * @param[in] s1 first sequence number + * @param[in] s2 second sequence number + * @return -1, if s1 < s2 + * @return 0, if s1 == s2 + * @return 1, if s1 > s2 + * @return -EINVAL, if comparison of the pair (s1,s2) is undefined + */ +static inline int seq64_compare(seq64_t s1, seq64_t s2) +{ + return seq64_compares(s1, s2, UINT64_MAX); +} + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* SEQ_H */ diff --git a/sys/seq/Makefile b/sys/seq/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/seq/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/seq/seq.c b/sys/seq/seq.c new file mode 100644 index 0000000000..4f8c172df5 --- /dev/null +++ b/sys/seq/seq.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2015 Cenk Gündoğan + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup sys_seq + * @{ + * + * @file + * @brief Serial Number Arithmetic (RFC 1982) + * + * @author Cenk Gündoğan + * + * @} + */ + +#include +#include "seq.h" + +seq8_t seq8_adds(seq8_t s, uint8_t n, uint8_t space) +{ + /* check if space is a power of 2 minus 1 */ + assert((space != 0) && ((space & (space + 1)) == 0)); + + if (n > SEQ_LIMIT(space)) { + return s; + } + + return (space == UINT8_MAX) ? (s + n) : (s + n) % (space + 1); +} + +int seq8_compares(seq8_t s1, seq8_t s2, uint8_t space) +{ + /* check if space is a power of 2 minus 1 */ + assert((space != 0) && ((space & (space + 1)) == 0)); + + if (s1 == s2) { + return 0; + } + + if (((s1 < s2) && ((uint8_t)(s2 - s1) < (SEQ_LIMIT(space) + 1))) || + ((s1 > s2) && ((uint8_t)(s1 - s2) > (SEQ_LIMIT(space) + 1)))) { + return -1; + } + + if (((s1 < s2) && ((uint8_t)(s2 - s1) > (SEQ_LIMIT(space) + 1))) || + ((s1 > s2) && ((uint8_t)(s1 - s2) < (SEQ_LIMIT(space) + 1)))) { + return 1; + } + + return -EINVAL; +} + +seq16_t seq16_adds(seq16_t s, uint16_t n, uint16_t space) +{ + /* check if space is a power of 2 minus 1 */ + assert((space != 0) && ((space & (space + 1)) == 0)); + + if (n > SEQ_LIMIT(space)) { + return s; + } + + return (space == UINT16_MAX) ? (s + n) : (s + n) % (space + 1); +} + +int seq16_compares(seq16_t s1, seq16_t s2, uint16_t space) +{ + /* check if space is a power of 2 minus 1 */ + assert((space != 0) && ((space & (space + 1)) == 0)); + + if (s1 == s2) { + return 0; + } + + if (((s1 < s2) && ((uint16_t)(s2 - s1) < (SEQ_LIMIT(space) + 1))) || + ((s1 > s2) && ((uint16_t)(s1 - s2) > (SEQ_LIMIT(space) + 1)))) { + return -1; + } + + if (((s1 < s2) && ((uint16_t)(s2 - s1) > (SEQ_LIMIT(space) + 1))) || + ((s1 > s2) && ((uint16_t)(s1 - s2) < (SEQ_LIMIT(space) + 1)))) { + return 1; + } + + return -EINVAL; +} + +seq32_t seq32_adds(seq32_t s, uint32_t n, uint32_t space) +{ + /* check if space is a power of 2 minus 1 */ + assert((space != 0) && ((space & (space + 1)) == 0)); + + if (n > SEQ_LIMIT(space)) { + return s; + } + + return (space == UINT32_MAX) ? (s + n) : (s + n) % (space + 1); +} + +int seq32_compares(seq32_t s1, seq32_t s2, uint32_t space) +{ + /* check if space is a power of 2 minus 1 */ + assert((space != 0) && ((space & (space + 1)) == 0)); + + if (s1 == s2) { + return 0; + } + + if (((s1 < s2) && ((uint32_t)(s2 - s1) < (SEQ_LIMIT(space) + 1))) || + ((s1 > s2) && ((uint32_t)(s1 - s2) > (SEQ_LIMIT(space) + 1)))) { + return -1; + } + + if (((s1 < s2) && ((uint32_t)(s2 - s1) > (SEQ_LIMIT(space) + 1))) || + ((s1 > s2) && ((uint32_t)(s1 - s2) < (SEQ_LIMIT(space) + 1)))) { + return 1; + } + + return -EINVAL; +} + +seq64_t seq64_adds(seq64_t s, uint64_t n, uint64_t space) +{ + /* check if space is a power of 2 minus 1 */ + assert((space != 0) && ((space & (space + 1)) == 0)); + + if (n > SEQ_LIMIT(space)) { + return s; + } + + return (space == UINT64_MAX) ? (s + n) : (s + n) % (space + 1); +} + +int seq64_compares(seq64_t s1, seq64_t s2, uint64_t space) +{ + /* check if space is a power of 2 minus 1 */ + assert((space != 0) && ((space & (space + 1)) == 0)); + + if (s1 == s2) { + return 0; + } + + if (((s1 < s2) && ((uint64_t)(s2 - s1) < (SEQ_LIMIT(space) + 1))) || + ((s1 > s2) && ((uint64_t)(s1 - s2) > (SEQ_LIMIT(space) + 1)))) { + return -1; + } + + if (((s1 < s2) && ((uint64_t)(s2 - s1) > (SEQ_LIMIT(space) + 1))) || + ((s1 > s2) && ((uint64_t)(s1 - s2) < (SEQ_LIMIT(space) + 1)))) { + return 1; + } + + return -EINVAL; +}