/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <vector>
extern "C" {
+#ifndef _MSC_VER
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+// missing in socket headers
+#define sa_family_t ADDRESS_FAMILY
+#endif
+
#include <sys/types.h>
+#include <netdb.h>
}
-#include "folly/Conv.h"
-#include "folly/Format.h"
+#include <folly/Conv.h>
+#include <folly/Format.h>
+
+// BSDish platforms don't provide standard access to s6_addr16
+#ifndef s6_addr16
+# if defined(__APPLE__) || defined(__FreeBSD__) || \
+ defined(__NetBSD__) || defined(__OpenBSD__)
+# define s6_addr16 __u6_addr.__u6_addr16
+# endif
+#endif
namespace folly { namespace detail {
struct Bytes : private boost::noncopyable {
// return true if all values of src are zero
static bool isZero(const uint8_t* src, std::size_t len) {
- for (auto i = 0; i < len; i++) {
+ for (std::size_t i = 0; i < len; i++) {
if (src[i] != 0x00) {
return false;
}
static_assert(N > 0, "Can't mask an empty ByteArray");
std::size_t asize = a.size();
std::array<uint8_t, N> ba{{0}};
- for (int i = 0; i < asize; i++) {
+ for (std::size_t i = 0; i < asize; i++) {
ba[i] = a[i] & b[i];
}
return ba;
static std::string toHex(const uint8_t* src, std::size_t len) {
static const char* const lut = "0123456789abcdef";
std::stringstream ss;
- for (int i = 0; i < len; i++) {
+ for (std::size_t i = 0; i < len; i++) {
const unsigned char c = src[i];
ss << lut[c >> 4] << lut[c & 15];
}
~Bytes() = delete;
};
+//
+// Write a maximum amount of base-converted character digits, of a
+// given base, from an unsigned integral type into a byte buffer of
+// sufficient size.
+//
+// This function does not append null terminators.
+//
+// Output buffer size must be guaranteed by caller (indirectly
+// controlled by DigitCount template parameter).
+//
+// Having these parameters at compile time allows compiler to
+// precompute several of the values, use smaller instructions, and
+// better optimize surrounding code.
+//
+// IntegralType:
+// - Something like uint8_t, uint16_t, etc
+//
+// DigitCount is the maximum number of digits to be printed
+// - This is tied to IntegralType and Base. For example:
+// - uint8_t in base 10 will print at most 3 digits ("255")
+// - uint16_t in base 16 will print at most 4 hex digits ("FFFF")
+//
+// Base is the desired output base of the string
+// - Base 10 will print [0-9], base 16 will print [0-9a-f]
+//
+// PrintAllDigits:
+// - Whether or not leading zeros should be printed
+//
+template<class IntegralType,
+ IntegralType DigitCount,
+ IntegralType Base = 10,
+ bool PrintAllDigits = false,
+ class = typename std::enable_if<
+ std::is_integral<IntegralType>::value &&
+ std::is_unsigned<IntegralType>::value,
+ bool>::type>
+ inline void writeIntegerString(
+ IntegralType val,
+ char** buffer) {
+ char* buf = *buffer;
+
+ if (!PrintAllDigits && val == 0) {
+ *(buf++) = '0';
+ *buffer = buf;
+ return;
+ }
+
+ IntegralType powerToPrint = 1;
+ for (int i = 1; i < DigitCount; ++i) {
+ powerToPrint *= Base;
+ }
+
+ bool found = PrintAllDigits;
+ while (powerToPrint) {
+
+ if (found || powerToPrint <= val) {
+ IntegralType value = val/powerToPrint;
+ if (Base == 10 || value < 10) {
+ value += '0';
+ } else {
+ value += ('a'-10);
+ }
+ *(buf++) = value;
+ val %= powerToPrint;
+ found = true;
+ }
+
+ powerToPrint /= Base;
+ }
+
+ *buffer = buf;
+}
+
+inline std::string fastIpv4ToString(
+ const in_addr& inAddr) {
+ const uint8_t* octets = reinterpret_cast<const uint8_t*>(&inAddr.s_addr);
+ char str[sizeof("255.255.255.255")];
+ char* buf = str;
+
+ writeIntegerString<uint8_t, 3>(octets[0], &buf);
+ *(buf++) = '.';
+ writeIntegerString<uint8_t, 3>(octets[1], &buf);
+ *(buf++) = '.';
+ writeIntegerString<uint8_t, 3>(octets[2], &buf);
+ *(buf++) = '.';
+ writeIntegerString<uint8_t, 3>(octets[3], &buf);
+
+ return std::string(str, buf-str);
+}
+
+inline std::string fastIpv6ToString(const in6_addr& in6Addr) {
+#ifdef _MSC_VER
+ const uint16_t* bytes = reinterpret_cast<const uint16_t*>(&in6Addr.u.Word);
+#else
+ const uint16_t* bytes = reinterpret_cast<const uint16_t*>(&in6Addr.s6_addr16);
+#endif
+ char str[sizeof("2001:0db8:0000:0000:0000:ff00:0042:8329")];
+ char* buf = str;
+
+ for (int i = 0; i < 8; ++i) {
+ writeIntegerString<uint16_t,
+ 4, // at most 4 hex digits per ushort
+ 16, // base 16 (hex)
+ true>(htons(bytes[i]), &buf);
+
+ if(i != 7) {
+ *(buf++) = ':';
+ }
+ }
+
+ return std::string(str, buf-str);
+}
+
}} // folly::detail