// bsls_byteorder.h                                                   -*-C++-*-
#ifndef INCLUDED_BSLS_BYTEORDER
#define INCLUDED_BSLS_BYTEORDER

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide byte-order manipulation macros.
//
//@CLASSES:
//
//@SEE_ALSO: bsls_byteorderutil
//
//@MACROS:
//  BSLS_BYTEORDER_HTON(x):   Convert value from host to network order
//  BSLS_BYTEORDER_HTONS(x):  Convert 16-bit value from host to network order
//  BSLS_BYTEORDER_HTONL(x):  Convert 32-bit value from host to network order
//  BSLS_BYTEORDER_HTONLL(x): Convert 64-bit value from host to network order
//  BSLS_BYTEORDER_NTOH(x):   Convert value from network to host order
//  BSLS_BYTEORDER_NTOHS(x):  Convert 16-bit value from network to host order
//  BSLS_BYTEORDER_NTOHL(x):  Convert 32-bit value from network to host order
//  BSLS_BYTEORDER_NTOHLL(x): Convert 64-bit value from network to host order
//  ---
//  BSLS_BYTEORDER_HTON_CONSTANT(x):   static host to network order
//  BSLS_BYTEORDER_HTONS_CONSTANT(x):  static 16-bit network to host order
//  BSLS_BYTEORDER_HTONL_CONSTANT(x):  static 32-bit network to host order
//  BSLS_BYTEORDER_HTONLL_CONSTANT(x): static 64-bit network to host order
//  BSLS_BYTEORDER_NTOH_CONSTANT(x):   static network to host order
//  BSLS_BYTEORDER_NTOHS_CONSTANT(x):  static 16-bit network to host order
//  BSLS_BYTEORDER_NTOHL_CONSTANT(x):  static 32-bit network to host order
//  BSLS_BYTEORDER_NTOHLL_CONSTANT(x): static 64-bit network to host order
//  ---
//  BSLS_BYTEORDER_LE_TO_HOST(x):     little-endian to host-endian
//  BSLS_BYTEORDER_LE_U16_TO_HOST(x): 16-bit little-endian to host-endian
//  BSLS_BYTEORDER_LE_U32_TO_HOST(x): 32-bit little-endian to host-endian
//  BSLS_BYTEORDER_LE_U64_TO_HOST(x): 64-bit little-endian to host-endian
//  BSLS_BYTEORDER_BE_TO_HOST(x):     big-endian to host-endian
//  BSLS_BYTEORDER_BE_U16_TO_HOST(x): 16-bit    big-endian to host-endian
//  BSLS_BYTEORDER_BE_U32_TO_HOST(x): 32-bit    big-endian to host-endian
//  BSLS_BYTEORDER_BE_U64_TO_HOST(x): 64-bit    big-endian to host-endian
//  ---
//  BSLS_BYTEORDER_HOST_TO_LE(x):     host-endian to little-endian
//  BSLS_BYTEORDER_HOST_U16_TO_LE(x): 16-bit host-endian to little-endian
//  BSLS_BYTEORDER_HOST_U32_TO_LE(x): 32-bit host-endian to little-endian
//  BSLS_BYTEORDER_HOST_U64_TO_LE(x): 64-bit host-endian to little-endian
//  BSLS_BYTEORDER_HOST_TO_BE(x):     host-endian to big-endian
//  BSLS_BYTEORDER_HOST_U16_TO_BE(x): 16-bit host-endian to    big-endian
//  BSLS_BYTEORDER_HOST_U32_TO_BE(x): 32-bit host-endian to    big-endian
//  BSLS_BYTEORDER_HOST_U64_TO_BE(x): 64-bit host-endian to    big-endian
//
//@DESCRIPTION: This component provides a set of byte-order manipulation macros
// that replace the standard `htonl`, `htons`, `ntohl`, and `ntohs` functions,
// and which do not require including any system header files:
// ```
// BSLS_BYTEORDER_HTON(x)
// BSLS_BYTEORDER_HTONS(x)
// BSLS_BYTEORDER_HTONL(x)
// BSLS_BYTEORDER_HTONLL(x)
// BSLS_BYTEORDER_NTOH(x)
// BSLS_BYTEORDER_NTOHS(x)
// BSLS_BYTEORDER_NTOHL(x)
// BSLS_BYTEORDER_NTOHLL(x)
// ```
// The "S", "L", and "LL" suffices in the names of the above macros indicate
// their applicability to 16-bit (`short`), 32-bit (`int`, *not* `long`), and
// 64-bit (`long long`) values, respectively.
//
// The macros without "S", "L", or "LL" suffices in their names indicate that
// they take the word size to be swapped from the word size of `x`, and return
// a value of the same type as `x`.  These should only be passed fundamental
// integral types, and not `enum` values, as the sizes of `enum` values are
// implementation defined.
//
// This set of host-to-network and network-to-host conversion macros are very
// efficient, but sacrifices the ability to perform compile-time
// initialization.  To compensate, the following set of functionally equivalent
// "CONSTANT" macros are provided.  These macros can be used for compile-time
// initialization, but are less efficient than non-"CONSTANT" versions:
// ```
// BSLS_BYTEORDER_HTONS_CONSTANT(x)
// BSLS_BYTEORDER_HTONL_CONSTANT(x)
// BSLS_BYTEORDER_HTONLL_CONSTANT(x)
// BSLS_BYTEORDER_NTOHS_CONSTANT(x)
// BSLS_BYTEORDER_NTOHL_CONSTANT(x)
// BSLS_BYTEORDER_NTOHLL_CONSTANT(x)
// ```
// Another set of macros provides conversion from big-endian or little-endian
// byte order to host-endian order.  The macros take 16-, 32- or 64-bit values
// and perform the indicated byte-order conversion on those values:
// ```
// BSLS_BYTEORDER_LE_TO_HOST(x)
// BSLS_BYTEORDER_LE_U16_TO_HOST(x)
// BSLS_BYTEORDER_LE_U32_TO_HOST(x)
// BSLS_BYTEORDER_LE_U64_TO_HOST(x)
// BSLS_BYTEORDER_BE_TO_HOST(x)
// BSLS_BYTEORDER_BE_U16_TO_HOST(x)
// BSLS_BYTEORDER_BE_U32_TO_HOST(x)
// BSLS_BYTEORDER_BE_U64_TO_HOST(x)
// ```
// The "LE" and "BE" embedded in the above macro names indicate Little-Endian
// and Big-Endian, respectively.
//
// Finally, a complementary set of macros provides conversion from host-endian
// byte order to big-endian or little-endian order:
// ```
// BSLS_BYTEORDER_HOST_TO_LE(x)
// BSLS_BYTEORDER_HOST_U16_TO_LE(x)
// BSLS_BYTEORDER_HOST_U32_TO_LE(x)
// BSLS_BYTEORDER_HOST_U64_TO_LE(x)
// BSLS_BYTEORDER_HOST_TO_BE(x)
// BSLS_BYTEORDER_HOST_U16_TO_BE(x)
// BSLS_BYTEORDER_HOST_U32_TO_BE(x)
// BSLS_BYTEORDER_HOST_U64_TO_BE(x)
// ```
//
///Usage
///-----
// To use these macros, simply pass a 16-, 32-, or 64-bit value to the macros.
// To demonstrate the change in byte order effected by the macros, we first
// write a function to print, in hex, a character buffer of a specified size:
// ```
// void printHex(const char *c, int size)
//     // Print the specified character array 'c', having the specified 'size'
//     // (in bytes), to 'stdout' in hex.
// {
//     const char *hex = "0123456789abcdef";
//     for (int i = 0; i < size; ++i) {
//         std::cout << hex[(c[i] >> 4) & 0xf]
//                   << hex[ c[i]       & 0xf];
//     }
// }
//
// template <class T>
// void printHex(T x)
//     // Print the specified object 'x' of parameterized type 'T' in hex.
// {
//     printHex((const char*)&x, sizeof x);
// }
// ```
// For example, to use the little-endian/big-endian to host-endian macros:
// ```
// short              x = static_cast<short>(0xabcd);
// int                y = 0xabcdef12;
// bsls::Types::Int64 z = 0xabcdef1234567890LL;
//
// // Note the use of macros within the calls to 'printHex'.
//
// printf("\nLE to Host(x): ");
// printHex(BSLS_BYTEORDER_LE_U16_TO_HOST(x));
//
// printf("\nLE to Host(y): ");
// printHex(BSLS_BYTEORDER_LE_U32_TO_HOST(y));
//
// printf("\nLE to Host(z): ");
// printHex(BSLS_BYTEORDER_LE_U64_TO_HOST(z));
//
// printf("\nBE to Host(x): ");
// printHex(BSLS_BYTEORDER_BE_U16_TO_HOST(x));
//
// printf("\nBE to Host(y): ");
// printHex(BSLS_BYTEORDER_BE_U32_TO_HOST(y));
//
// printf("\nBE to Host(z): ");
// printHex(BSLS_BYTEORDER_BE_U64_TO_HOST(z));
// ```
// On little-endian machines (e.g., x86, IA64), this will print the following
// to `stdout`:
// ```
// LE to Host(x): abcd
// LE to Host(y): abcdef12
// LE to Host(z): abcdef1234567890
// BE to Host(x): cdab
// BE to Host(y): 12efcdab
// BE to Host(z): 9078563412efcdab
// ```
// On big-endian machines (e.g., sparc, powerpc), the following will be printed
// instead:
// ```
// LE to Host(x): cdab
// LE to Host(y): 12efcdab
// LE to Host(z): 9078563412efcdab
// BE to Host(x): abcd
// BE to Host(y): abcdef12
// BE to Host(z): abcdef1234567890
// ```
// The other macros can be used in a similar manner.

#include <bsls_byteorderutil.h>
#include <bsls_platform.h>

// ============================================================================
//                                  MACROS
// ======

// STANDARD NETWORK AND HOST CONVERSIONS

#if defined(BSLS_PLATFORM_IS_BIG_ENDIAN)

#define BSLS_BYTEORDER_NTOH(x)   (x)
#define BSLS_BYTEORDER_NTOHS(x)  (x)
#define BSLS_BYTEORDER_NTOHL(x)  (x)
#define BSLS_BYTEORDER_NTOHLL(x) (x)

#define BSLS_BYTEORDER_HTON(x)   (x)
#define BSLS_BYTEORDER_HTONS(x)  (x)
#define BSLS_BYTEORDER_HTONL(x)  (x)
#define BSLS_BYTEORDER_HTONLL(x) (x)

#define BSLS_BYTEORDER_NTOHS_CONSTANT(x)  (x)
#define BSLS_BYTEORDER_NTOHL_CONSTANT(x)  (x)
#define BSLS_BYTEORDER_NTOHLL_CONSTANT(x) (x)

#define BSLS_BYTEORDER_HTONS_CONSTANT(x)  (x)
#define BSLS_BYTEORDER_HTONL_CONSTANT(x)  (x)
#define BSLS_BYTEORDER_HTONLL_CONSTANT(x) (x)

#else  // BSLS_PLATFORM_IS_LITTLE_ENDIAN

#define BSLS_BYTEORDER_NTOH(x) BloombergLP::bsls::ByteOrderUtil::swapBytes(x)

#define BSLS_BYTEORDER_NTOHS(x)                                               \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes16(x)

#define BSLS_BYTEORDER_NTOHL(x)                                               \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes32(x)

#define BSLS_BYTEORDER_NTOHLL(x)                                              \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes64(x)

#define BSLS_BYTEORDER_HTON(x)   BSLS_BYTEORDER_NTOH(x)

#define BSLS_BYTEORDER_HTONS(x)  BSLS_BYTEORDER_NTOHS(x)

#define BSLS_BYTEORDER_HTONL(x)  BSLS_BYTEORDER_NTOHL(x)

#define BSLS_BYTEORDER_HTONLL(x) BSLS_BYTEORDER_NTOHLL(x)

#define BSLS_BYTEORDER_NTOHS_CONSTANT(x)                                      \
             static_cast<unsigned short>(                                     \
                            (static_cast<unsigned short>(x) >> 8) |           \
                            (static_cast<unsigned short>(x) << 8))

// The "NO_MSB" versions of the byte-swapping macros always move a 0 bit into
// the most significant bit of the result, in order to avoid undefined behavior
// caused by left shifting a 1 into the sign bit of a signed positive value.
// These versions are invoked by the user versions of the macros, which first
// test whether that bit is 1, and if so, perform the operation on the
// complement of the value and complement the result.  The "NO_MSB" macros are
// intended to be private to the implementation.
#define BSLS_BYTEORDER_NTOHL_CONSTANT_NO_MSB(x)                               \
                    ((((x) >> 24) & 0x000000FF) | (((x) & 0x00FF0000) >>  8)  \
 /* note 0x7F */   | (((x) & 0x0000FF00) <<  8) | (((x) & 0x0000007F) << 24))
#define BSLS_BYTEORDER_NTOHL_CONSTANT(x)                                      \
        ((x) & 0x80 ? ~BSLS_BYTEORDER_NTOHL_CONSTANT_NO_MSB(~(x))             \
                    :  BSLS_BYTEORDER_NTOHL_CONSTANT_NO_MSB(x))

#define BSLS_BYTEORDER_NTOHLL_CONSTANT_NO_MSB(x)                              \
 /* note 0x7F */                        ((((x) & 0x000000000000007FLL) << 56) \
                                       | (((x) & 0x000000000000FF00LL) << 40) \
                                       | (((x) & 0x0000000000FF0000LL) << 24) \
                                       | (((x) & 0x00000000FF000000LL) <<  8) \
                                       | (((x) & 0x000000FF00000000LL) >>  8) \
                                       | (((x) & 0x0000FF0000000000LL) >> 24) \
                                       | (((x) & 0x00FF000000000000LL) >> 40) \
                                       | (((x) >> 56) & 0x00000000000000FFLL))
#define BSLS_BYTEORDER_NTOHLL_CONSTANT(x)                                     \
        ((x) & 0x80 ? ~BSLS_BYTEORDER_NTOHLL_CONSTANT_NO_MSB(~(x))            \
                    :  BSLS_BYTEORDER_NTOHLL_CONSTANT_NO_MSB(x))

#define BSLS_BYTEORDER_HTONS_CONSTANT(x)  BSLS_BYTEORDER_NTOHS_CONSTANT(x)

#define BSLS_BYTEORDER_HTONL_CONSTANT(x)  BSLS_BYTEORDER_NTOHL_CONSTANT(x)

#define BSLS_BYTEORDER_HTONLL_CONSTANT(x) BSLS_BYTEORDER_NTOHLL_CONSTANT(x)

#endif  // BSLS_PLATFORM_IS_BIG_ENDIAN

// ----------------------------------------------------------------------------

// ENDIAN CONVERSION MACROS

#if defined(BSLS_PLATFORM_IS_LITTLE_ENDIAN)

#define BSLS_BYTEORDER_LE_U16_TO_HOST(x) (x)
#define BSLS_BYTEORDER_LE_U32_TO_HOST(x) (x)
#define BSLS_BYTEORDER_LE_U64_TO_HOST(x) (x)

#define BSLS_BYTEORDER_HOST_U16_TO_LE(x) (x)
#define BSLS_BYTEORDER_HOST_U32_TO_LE(x) (x)
#define BSLS_BYTEORDER_HOST_U64_TO_LE(x) (x)

#define BSLS_BYTEORDER_BE_U16_TO_HOST(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes16(x)
#define BSLS_BYTEORDER_BE_U32_TO_HOST(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes32(x)
#define BSLS_BYTEORDER_BE_U64_TO_HOST(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes64(x)

#define BSLS_BYTEORDER_HOST_U16_TO_BE(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes16(x)
#define BSLS_BYTEORDER_HOST_U32_TO_BE(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes32(x)
#define BSLS_BYTEORDER_HOST_U64_TO_BE(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes64(x)

#define BSLS_BYTEORDER_LE_TO_HOST(x) (x)
#define BSLS_BYTEORDER_HOST_TO_LE(x) (x)
#define BSLS_BYTEORDER_BE_TO_HOST(x)                                          \
                                 BloombergLP::bsls::ByteOrderUtil::swapBytes(x)
#define BSLS_BYTEORDER_HOST_TO_BE(x)                                          \
                                 BloombergLP::bsls::ByteOrderUtil::swapBytes(x)

#else  // BSLS_PLATFORM_IS_BIG_ENDIAN

#define BSLS_BYTEORDER_LE_U16_TO_HOST(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes16(x)
#define BSLS_BYTEORDER_LE_U32_TO_HOST(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes32(x)
#define BSLS_BYTEORDER_LE_U64_TO_HOST(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes64(x)

#define BSLS_BYTEORDER_HOST_U16_TO_LE(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes16(x)
#define BSLS_BYTEORDER_HOST_U32_TO_LE(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes32(x)
#define BSLS_BYTEORDER_HOST_U64_TO_LE(x)                                      \
                               BloombergLP::bsls::ByteOrderUtil::swapBytes64(x)

#define BSLS_BYTEORDER_BE_U16_TO_HOST(x) (x)
#define BSLS_BYTEORDER_BE_U32_TO_HOST(x) (x)
#define BSLS_BYTEORDER_BE_U64_TO_HOST(x) (x)

#define BSLS_BYTEORDER_HOST_U16_TO_BE(x) (x)
#define BSLS_BYTEORDER_HOST_U32_TO_BE(x) (x)
#define BSLS_BYTEORDER_HOST_U64_TO_BE(x) (x)

#define BSLS_BYTEORDER_LE_TO_HOST(x)                                          \
                                 BloombergLP::bsls::ByteOrderUtil::swapBytes(x)
#define BSLS_BYTEORDER_HOST_TO_LE(x)                                          \
                                 BloombergLP::bsls::ByteOrderUtil::swapBytes(x)
#define BSLS_BYTEORDER_BE_TO_HOST(x) (x)
#define BSLS_BYTEORDER_HOST_TO_BE(x) (x)

#endif  // BSLS_PLATFORM_IS_LITTLE_ENDIAN

#endif

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
