Commit a247c8d3 authored by Jordan DeLong's avatar Jordan DeLong

Remove some files that should have been deleted in earlier commits

Summary: Our script wasn't picking up removed files.
parent 8336eb31
/*
* Copyright 2013 Facebook, Inc.
*
* 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.
*/
#ifndef FOLLY_HISTOGRAM_INL_H_
#define FOLLY_HISTOGRAM_INL_H_
#include "folly/Conv.h"
#include <glog/logging.h>
namespace folly {
namespace detail {
template <typename T, typename BucketT>
HistogramBuckets<T, BucketT>::HistogramBuckets(ValueType bucketSize,
ValueType min,
ValueType max,
const BucketType& defaultBucket)
: bucketSize_(bucketSize),
min_(min),
max_(max) {
CHECK_GT(bucketSize_, ValueType(0));
CHECK_LT(min_, max_);
unsigned int numBuckets = (max - min) / bucketSize;
// Round up if the bucket size does not fit evenly
if (numBuckets * bucketSize < max - min) {
++numBuckets;
}
// Add 2 for the extra 'below min' and 'above max' buckets
numBuckets += 2;
buckets_.assign(numBuckets, defaultBucket);
}
template <typename T, typename BucketType>
unsigned int HistogramBuckets<T, BucketType>::getBucketIdx(
ValueType value) const {
if (value < min_) {
return 0;
} else if (value >= max_) {
return buckets_.size() - 1;
} else {
// the 1 is the below_min bucket
return ((value - min_) / bucketSize_) + 1;
}
}
template <typename T, typename BucketType>
template <typename CountFn>
unsigned int HistogramBuckets<T, BucketType>::getPercentileBucketIdx(
double pct,
CountFn countFromBucket,
double* lowPct, double* highPct) const {
CHECK_GE(pct, 0.0);
CHECK_LE(pct, 1.0);
unsigned int numBuckets = buckets_.size();
// Compute the counts in each bucket
std::vector<uint64_t> counts(numBuckets);
uint64_t totalCount = 0;
for (unsigned int n = 0; n < numBuckets; ++n) {
uint64_t bucketCount =
countFromBucket(const_cast<const BucketType&>(buckets_[n]));
counts[n] = bucketCount;
totalCount += bucketCount;
}
// If there are no elements, just return the lowest bucket.
// Note that we return bucket 1, which is the first bucket in the
// histogram range; bucket 0 is for all values below min_.
if (totalCount == 0) {
// Set lowPct and highPct both to 0.
// getPercentileEstimate() will recognize this to mean that the histogram
// is empty.
if (lowPct) {
*lowPct = 0.0;
}
if (highPct) {
*highPct = 0.0;
}
return 1;
}
// Loop through all the buckets, keeping track of each bucket's
// percentile range: [0,10], [10,17], [17,45], etc. When we find a range
// that includes our desired percentile, we return that bucket index.
double prevPct = 0.0;
double curPct = 0.0;
uint64_t curCount = 0;
unsigned int idx;
for (idx = 0; idx < numBuckets; ++idx) {
if (counts[idx] == 0) {
// skip empty buckets
continue;
}
prevPct = curPct;
curCount += counts[idx];
curPct = static_cast<double>(curCount) / totalCount;
if (pct <= curPct) {
// This is the desired bucket
break;
}
}
if (lowPct) {
*lowPct = prevPct;
}
if (highPct) {
*highPct = curPct;
}
return idx;
}
template <typename T, typename BucketType>
template <typename CountFn, typename AvgFn>
T HistogramBuckets<T, BucketType>::getPercentileEstimate(
double pct,
CountFn countFromBucket,
AvgFn avgFromBucket) const {
// Find the bucket where this percentile falls
double lowPct;
double highPct;
unsigned int bucketIdx = getPercentileBucketIdx(pct, countFromBucket,
&lowPct, &highPct);
if (lowPct == 0.0 && highPct == 0.0) {
// Invalid range -- the buckets must all be empty
// Return the default value for ValueType.
return ValueType();
}
if (lowPct == highPct) {
// Unlikely to have exact equality,
// but just return the bucket average in this case.
// We handle this here to avoid division by 0 below.
return avgFromBucket(buckets_[bucketIdx]);
}
CHECK_GE(pct, lowPct);
CHECK_LE(pct, highPct);
CHECK_LT(lowPct, highPct);
// Compute information about this bucket
ValueType avg = avgFromBucket(buckets_[bucketIdx]);
ValueType low;
ValueType high;
if (bucketIdx == 0) {
if (avg > min_) {
// This normally shouldn't happen. This bucket is only supposed to track
// values less than min_. Most likely this means that integer overflow
// occurred, and the code in avgFromBucket() returned a huge value
// instead of a small one. Just return the minimum possible value for
// now.
//
// (Note that if the counter keeps being decremented, eventually it will
// wrap and become small enough that we won't detect this any more, and
// we will return bogus information.)
LOG(ERROR) << "invalid average value in histogram minimum bucket: " <<
avg << " > " << min_ << ": possible integer overflow?";
return getBucketMin(bucketIdx);
}
// For the below-min bucket, just assume the lowest value ever seen is
// twice as far away from min_ as avg.
high = min_;
low = high - (2 * (high - avg));
// Adjust low in case it wrapped
if (low > avg) {
low = std::numeric_limits<ValueType>::min();
}
} else if (bucketIdx == buckets_.size() - 1) {
if (avg < max_) {
// Most likely this means integer overflow occurred. See the comments
// above in the minimum case.
LOG(ERROR) << "invalid average value in histogram maximum bucket: " <<
avg << " < " << max_ << ": possible integer overflow?";
return getBucketMax(bucketIdx);
}
// Similarly for the above-max bucket, assume the highest value ever seen
// is twice as far away from max_ as avg.
low = max_;
high = low + (2 * (avg - low));
// Adjust high in case it wrapped
if (high < avg) {
high = std::numeric_limits<ValueType>::max();
}
} else {
low = getBucketMin(bucketIdx);
high = getBucketMax(bucketIdx);
if (avg < low || avg > high) {
// Most likely this means an integer overflow occurred.
// See the comments above. Return the midpoint between low and high
// as a best guess, since avg is meaningless.
LOG(ERROR) << "invalid average value in histogram bucket: " <<
avg << " not in range [" << low << ", " << high <<
"]: possible integer overflow?";
return (low + high) / 2;
}
}
// Since we know the average value in this bucket, we can do slightly better
// than just assuming the data points in this bucket are uniformly
// distributed between low and high.
//
// Assume that the median value in this bucket is the same as the average
// value.
double medianPct = (lowPct + highPct) / 2.0;
if (pct < medianPct) {
// Assume that the data points lower than the median of this bucket
// are uniformly distributed between low and avg
double pctThroughSection = (pct - lowPct) / (medianPct - lowPct);
return low + ((avg - low) * pctThroughSection);
} else {
// Assume that the data points greater than the median of this bucket
// are uniformly distributed between avg and high
double pctThroughSection = (pct - medianPct) / (highPct - medianPct);
return avg + ((high - avg) * pctThroughSection);
}
}
} // detail
template <typename T>
std::string Histogram<T>::debugString() const {
std::string ret = folly::to<std::string>(
"num buckets: ", buckets_.getNumBuckets(),
", bucketSize: ", buckets_.getBucketSize(),
", min: ", buckets_.getMin(), ", max: ", buckets_.getMax(), "\n");
for (unsigned int i = 0; i < buckets_.getNumBuckets(); ++i) {
folly::toAppend(" ", buckets_.getBucketMin(i), ": ",
buckets_.getByIndex(i).count, "\n",
&ret);
}
return ret;
}
template <typename T>
void Histogram<T>::toTSV(std::ostream& out, bool skipEmptyBuckets) const {
for (unsigned int i = 0; i < buckets_.getNumBuckets(); ++i) {
// Do not output empty buckets in order to reduce data file size.
if (skipEmptyBuckets && getBucketByIndex(i).count == 0) {
continue;
}
const auto& bucket = getBucketByIndex(i);
out << getBucketMin(i) << '\t' << getBucketMax(i) << '\t'
<< bucket.count << '\t' << bucket.sum << '\n';
}
}
} // folly
#endif // FOLLY_HISTOGRAM_INL_H_
This diff is collapsed.
This diff is collapsed.
Folly: Facebook Open-source LibrarY
-----------------------------------
Folly is an open-source C++ library developed and used at Facebook.
Dependencies
------------
- double-conversion (http://code.google.com/p/double-conversion/)
By default, the build tooling for double-conversion does not build
any libraries, which folly requires. To build the necessary libraries
copy folly/SConstruct.double-conversion to your double-conversion
source directory before building:
[double-conversion/] scons -f SConstruct.double-conversion
Then set CPPFLAGS/LDFLAGS so that folly can find your double-conversion
build:
[folly/] LDFLAGS=-L<double-conversion>/ CPPFLAGS=-I<double-conversion>/src/
configure ...
- googletest (Google C++ Testing Framework)
Grab gtest 1.6.0 from:
http://googletest.googlecode.com/files/gtest-1.6.0.zip
Unzip it inside of the test/ subdirectory.
- additional platform specific dependencies:
Ubuntu 12.04 64-bit
- g++
- automake
- autoconf
- libtool
- libboost1.46-all-dev
- libgoogle-glog-dev
This package has been removed from 12.04 -- use the one from 11.10
- gflags (packages need to be downloaded from below)
http://gflags.googlecode.com/files/libgflags-dev_2.0-1_amd64.deb
http://gflags.googlecode.com/files/libgflags0_2.0-1_amd64.deb
- scons (for double-conversion)
Fedora 17 64-bit
- gcc
- gcc-c++
- autoconf
- automake
- boost-devel
- libtool
- glog-devel
- gflags-devel
- scons (for double-conversion)
/*
* Copyright 2012 Facebook, Inc.
*
* 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.
*/
// Spooky Hash
// A 128-bit noncryptographic hash, for checksums and table lookup
// By Bob Jenkins. Public domain.
// Oct 31 2010: published framework, disclaimer ShortHash isn't right
// Nov 7 2010: disabled ShortHash
// Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
// April 10 2012: buffer overflow on platforms without unaligned reads
// July 12 2012: was passing out variables in final to in/out in short
// July 30 2012: I reintroduced the buffer overflow
#include "folly/SpookyHash.h"
#include <cstring>
#define ALLOW_UNALIGNED_READS 1
namespace folly {
namespace hash {
//
// short hash ... it could be used on any message,
// but it's used by Spooky just for short messages.
//
void SpookyHash::Short(
const void *message,
size_t length,
uint64_t *hash1,
uint64_t *hash2)
{
uint64_t buf[2*sc_numVars];
union
{
const uint8_t *p8;
uint32_t *p32;
uint64_t *p64;
size_t i;
} u;
u.p8 = (const uint8_t *)message;
if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
{
memcpy(buf, message, length);
u.p64 = buf;
}
size_t remainder = length%32;
uint64_t a=*hash1;
uint64_t b=*hash2;
uint64_t c=sc_const;
uint64_t d=sc_const;
if (length > 15)
{
const uint64_t *end = u.p64 + (length/32)*4;
// handle all complete sets of 32 bytes
for (; u.p64 < end; u.p64 += 4)
{
c += u.p64[0];
d += u.p64[1];
ShortMix(a,b,c,d);
a += u.p64[2];
b += u.p64[3];
}
//Handle the case of 16+ remaining bytes.
if (remainder >= 16)
{
c += u.p64[0];
d += u.p64[1];
ShortMix(a,b,c,d);
u.p64 += 2;
remainder -= 16;
}
}
// Handle the last 0..15 bytes, and its length
d = ((uint64_t)length) << 56;
switch (remainder)
{
case 15:
d += ((uint64_t)u.p8[14]) << 48;
case 14:
d += ((uint64_t)u.p8[13]) << 40;
case 13:
d += ((uint64_t)u.p8[12]) << 32;
case 12:
d += u.p32[2];
c += u.p64[0];
break;
case 11:
d += ((uint64_t)u.p8[10]) << 16;
case 10:
d += ((uint64_t)u.p8[9]) << 8;
case 9:
d += (uint64_t)u.p8[8];
case 8:
c += u.p64[0];
break;
case 7:
c += ((uint64_t)u.p8[6]) << 48;
case 6:
c += ((uint64_t)u.p8[5]) << 40;
case 5:
c += ((uint64_t)u.p8[4]) << 32;
case 4:
c += u.p32[0];
break;
case 3:
c += ((uint64_t)u.p8[2]) << 16;
case 2:
c += ((uint64_t)u.p8[1]) << 8;
case 1:
c += (uint64_t)u.p8[0];
break;
case 0:
c += sc_const;
d += sc_const;
}
ShortEnd(a,b,c,d);
*hash1 = a;
*hash2 = b;
}
// do the whole hash in one call
void SpookyHash::Hash128(
const void *message,
size_t length,
uint64_t *hash1,
uint64_t *hash2)
{
if (length < sc_bufSize)
{
Short(message, length, hash1, hash2);
return;
}
uint64_t h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
uint64_t buf[sc_numVars];
uint64_t *end;
union
{
const uint8_t *p8;
uint64_t *p64;
size_t i;
} u;
size_t remainder;
h0=h3=h6=h9 = *hash1;
h1=h4=h7=h10 = *hash2;
h2=h5=h8=h11 = sc_const;
u.p8 = (const uint8_t *)message;
end = u.p64 + (length/sc_blockSize)*sc_numVars;
// handle all whole sc_blockSize blocks of bytes
if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
{
while (u.p64 < end)
{
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p64 += sc_numVars;
}
}
else
{
while (u.p64 < end)
{
memcpy(buf, u.p64, sc_blockSize);
Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p64 += sc_numVars;
}
}
// handle the last partial block of sc_blockSize bytes
remainder = (length - ((const uint8_t *)end-(const uint8_t *)message));
memcpy(buf, end, remainder);
memset(((uint8_t *)buf)+remainder, 0, sc_blockSize-remainder);
((uint8_t *)buf)[sc_blockSize-1] = remainder;
Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
// do some final mixing
End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
*hash1 = h0;
*hash2 = h1;
}
// init spooky state
void SpookyHash::Init(uint64_t seed1, uint64_t seed2)
{
m_length = 0;
m_remainder = 0;
m_state[0] = seed1;
m_state[1] = seed2;
}
// add a message fragment to the state
void SpookyHash::Update(const void *message, size_t length)
{
uint64_t h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
size_t newLength = length + m_remainder;
uint8_t remainder;
union
{
const uint8_t *p8;
uint64_t *p64;
size_t i;
} u;
const uint64_t *end;
// Is this message fragment too short? If it is, stuff it away.
if (newLength < sc_bufSize)
{
memcpy(&((uint8_t *)m_data)[m_remainder], message, length);
m_length = length + m_length;
m_remainder = (uint8_t)newLength;
return;
}
// init the variables
if (m_length < sc_bufSize)
{
h0=h3=h6=h9 = m_state[0];
h1=h4=h7=h10 = m_state[1];
h2=h5=h8=h11 = sc_const;
}
else
{
h0 = m_state[0];
h1 = m_state[1];
h2 = m_state[2];
h3 = m_state[3];
h4 = m_state[4];
h5 = m_state[5];
h6 = m_state[6];
h7 = m_state[7];
h8 = m_state[8];
h9 = m_state[9];
h10 = m_state[10];
h11 = m_state[11];
}
m_length = length + m_length;
// if we've got anything stuffed away, use it now
if (m_remainder)
{
uint8_t prefix = sc_bufSize-m_remainder;
memcpy(&(((uint8_t *)m_data)[m_remainder]), message, prefix);
u.p64 = m_data;
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p8 = ((const uint8_t *)message) + prefix;
length -= prefix;
}
else
{
u.p8 = (const uint8_t *)message;
}
// handle all whole blocks of sc_blockSize bytes
end = u.p64 + (length/sc_blockSize)*sc_numVars;
remainder = (uint8_t)(length-((const uint8_t *)end-u.p8));
if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
{
while (u.p64 < end)
{
Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p64 += sc_numVars;
}
}
else
{
while (u.p64 < end)
{
memcpy(m_data, u.p8, sc_blockSize);
Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
u.p64 += sc_numVars;
}
}
// stuff away the last few bytes
m_remainder = remainder;
memcpy(m_data, end, remainder);
// stuff away the variables
m_state[0] = h0;
m_state[1] = h1;
m_state[2] = h2;
m_state[3] = h3;
m_state[4] = h4;
m_state[5] = h5;
m_state[6] = h6;
m_state[7] = h7;
m_state[8] = h8;
m_state[9] = h9;
m_state[10] = h10;
m_state[11] = h11;
}
// report the hash for the concatenation of all message fragments so far
void SpookyHash::Final(uint64_t *hash1, uint64_t *hash2)
{
// init the variables
if (m_length < sc_bufSize)
{
*hash1 = m_state[0];
*hash2 = m_state[1];
Short( m_data, m_length, hash1, hash2);
return;
}
const uint64_t *data = (const uint64_t *)m_data;
uint8_t remainder = m_remainder;
uint64_t h0 = m_state[0];
uint64_t h1 = m_state[1];
uint64_t h2 = m_state[2];
uint64_t h3 = m_state[3];
uint64_t h4 = m_state[4];
uint64_t h5 = m_state[5];
uint64_t h6 = m_state[6];
uint64_t h7 = m_state[7];
uint64_t h8 = m_state[8];
uint64_t h9 = m_state[9];
uint64_t h10 = m_state[10];
uint64_t h11 = m_state[11];
if (remainder >= sc_blockSize)
{
// m_data can contain two blocks; handle any whole first block
Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
data += sc_numVars;
remainder -= sc_blockSize;
}
// mix in the last partial block, and the length mod sc_blockSize
memset(&((uint8_t *)data)[remainder], 0, (sc_blockSize-remainder));
((uint8_t *)data)[sc_blockSize-1] = remainder;
Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
// do some final mixing
End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
*hash1 = h0;
*hash2 = h1;
}
} // namespace hash
} // namespace folly
This diff is collapsed.
/*
* Copyright 2013 Facebook, Inc.
*
* 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.
*/
#ifndef FOLLY_STLALLOCATOR_H_
#define FOLLY_STLALLOCATOR_H_
#include "folly/Traits.h"
#include <memory>
#include <limits>
#include <utility>
#include <exception>
#include <stdexcept>
#include <cstddef>
namespace folly {
/**
* Wrap a SimpleAllocator into a STL-compliant allocator.
*
* The SimpleAllocator must provide two methods:
* void* allocate(size_t size);
* void deallocate(void* ptr);
* which, respectively, allocate a block of size bytes (aligned to the maximum
* alignment required on your system), throwing std::bad_alloc if the
* allocation can't be satisfied, and free a previously allocated block.
*
* Note that the following allocator resembles the standard allocator
* quite well:
*
* class MallocAllocator {
* public:
* void* allocate(size_t size) {
* void* p = malloc(size);
* if (!p) throw std::bad_alloc();
* return p;
* }
* void deallocate(void* p) {
* free(p);
* }
* };
*
* author: Tudor Bosman <tudorb@fb.com>
*/
// This would be so much simpler with std::allocator_traits, but gcc 4.6.2
// doesn't support it
template <class Alloc, class T> class StlAllocator;
template <class Alloc> class StlAllocator<Alloc, void> {
public:
typedef void value_type;
typedef void* pointer;
typedef const void* const_pointer;
template <class U> struct rebind {
typedef StlAllocator<Alloc, U> other;
};
};
template <class Alloc, class T>
class StlAllocator {
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef ptrdiff_t difference_type;
typedef size_t size_type;
StlAllocator() : alloc_(nullptr) { }
explicit StlAllocator(Alloc* alloc) : alloc_(alloc) { }
template <class U> StlAllocator(const StlAllocator<Alloc, U>& other)
: alloc_(other.alloc()) { }
T* allocate(size_t n, const void* hint = nullptr) {
return static_cast<T*>(alloc_->allocate(n * sizeof(T)));
}
void deallocate(T* p, size_t n) {
alloc_->deallocate(p);
}
size_t max_size() const {
return std::numeric_limits<size_t>::max();
}
T* address(T& x) const {
return std::addressof(x);
}
const T* address(const T& x) const {
return std::addressof(x);
}
template <class... Args>
void construct(T* p, Args&&... args) {
new (p) T(std::forward<Args>(args)...);
}
void destroy(T* p) {
p->~T();
}
Alloc* alloc() const {
return alloc_;
}
template <class U> struct rebind {
typedef StlAllocator<Alloc, U> other;
};
bool operator!=(const StlAllocator<Alloc, T>& other) const {
return alloc_ != other.alloc_;
}
bool operator==(const StlAllocator<Alloc, T>& other) const {
return alloc_ == other.alloc_;
}
private:
Alloc* alloc_;
};
/*
* Helper classes/functions for creating a unique_ptr using a custom allocator
*
* @author: Marcelo Juchem <marcelo@fb.com>
*/
// A deleter implementation based on std::default_delete,
// which uses a custom allocator to free memory
template <typename Allocator>
class allocator_delete {
typedef typename std::remove_reference<Allocator>::type allocator_type;
public:
allocator_delete() = default;
explicit allocator_delete(const allocator_type& allocator):
allocator_(allocator)
{}
explicit allocator_delete(allocator_type&& allocator):
allocator_(std::move(allocator))
{}
template <typename U>
allocator_delete(const allocator_delete<U>& other):
allocator_(other.get_allocator())
{}
allocator_type& get_allocator() const {
return allocator_;
}
void operator()(typename allocator_type::pointer p) const {
if (!p) {
return;
}
allocator_.destroy(p);
allocator_.deallocate(p, 1);
}
private:
mutable allocator_type allocator_;
};
template <typename T, typename Allocator>
class is_simple_allocator {
FOLLY_CREATE_HAS_MEMBER_FN_TRAITS(has_destroy, destroy);
typedef typename std::remove_const<
typename std::remove_reference<Allocator>::type
>::type allocator;
typedef typename std::remove_reference<T>::type value_type;
typedef value_type* pointer;
public:
constexpr static bool value = !has_destroy<allocator, void(pointer)>::value
&& !has_destroy<allocator, void(void*)>::value;
};
template <typename T, typename Allocator>
typename std::enable_if<
is_simple_allocator<T, Allocator>::value,
folly::StlAllocator<
typename std::remove_reference<Allocator>::type,
typename std::remove_reference<T>::type
>
>::type make_stl_allocator(Allocator&& allocator) {
return folly::StlAllocator<
typename std::remove_reference<Allocator>::type,
typename std::remove_reference<T>::type
>(&allocator);
}
template <typename T, typename Allocator>
typename std::enable_if<
!is_simple_allocator<T, Allocator>::value,
typename std::remove_reference<Allocator>::type
>::type make_stl_allocator(Allocator&& allocator) {
return std::move(allocator);
}
template <typename T, typename Allocator>
struct AllocatorUniquePtr {
typedef std::unique_ptr<T,
folly::allocator_delete<
typename std::conditional<
is_simple_allocator<T, Allocator>::value,
folly::StlAllocator<typename std::remove_reference<Allocator>::type, T>,
typename std::remove_reference<Allocator>::type
>::type
>
> type;
};
template <typename T, typename Allocator, typename ...Args>
typename AllocatorUniquePtr<T, Allocator>::type allocate_unique(
Allocator&& allocator, Args&&... args
) {
auto stlAllocator = folly::make_stl_allocator<T>(
std::forward<Allocator>(allocator)
);
auto p = stlAllocator.allocate(1);
try {
stlAllocator.construct(p, std::forward<Args>(args)...);
return {p,
folly::allocator_delete<decltype(stlAllocator)>(std::move(stlAllocator))
};
} catch (...) {
stlAllocator.deallocate(p, 1);
throw;
}
}
template <typename T, typename Allocator, typename ...Args>
std::shared_ptr<T> allocate_shared(Allocator&& allocator, Args&&... args) {
return std::allocate_shared<T>(
folly::make_stl_allocator<T>(std::forward<Allocator>(allocator)),
std::forward<Args>(args)...
);
}
} // namespace folly
#endif /* FOLLY_STLALLOCATOR_H_ */
/*
* Copyright 2013 Facebook, Inc.
*
* 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.
*/
/**
* Wrapper around the eventfd system call, as defined in <sys/eventfd.h>
* in glibc 2.9+.
*
* @author Tudor Bosman (tudorb@fb.com)
*/
#ifndef FOLLY_BASE_EVENTFD_H_
#define FOLLY_BASE_EVENTFD_H_
#ifndef __linux__
#error This file may be compiled on Linux only.
#endif
#include <sys/syscall.h>
#include <unistd.h>
#include <fcntl.h>
// Use existing __NR_eventfd2 if already defined
// Values from the Linux kernel source:
// arch/x86/include/asm/unistd_{32,64}.h
#ifndef __NR_eventfd2
#if defined(__x86_64__)
#define __NR_eventfd2 290
#elif defined(__i386__)
#define __NR_eventfd2 328
#else
#error "Can't define __NR_eventfd2 for your architecture."
#endif
#endif
#ifndef EFD_SEMAPHORE
#define EFD_SEMAPHORE 1
#endif
/* from linux/fcntl.h - this conflicts with fcntl.h so include just the #define
* we need
*/
#ifndef O_CLOEXEC
#define O_CLOEXEC 02000000 /* set close_on_exec */
#endif
#ifndef EFD_CLOEXEC
#define EFD_CLOEXEC O_CLOEXEC
#endif
#ifndef EFD_NONBLOCK
#define EFD_NONBLOCK O_NONBLOCK
#endif
namespace folly {
// http://www.kernel.org/doc/man-pages/online/pages/man2/eventfd.2.html
inline int eventfd(unsigned int initval, int flags) {
// Use the eventfd2 system call, as in glibc 2.9+
// (requires kernel 2.6.30+)
return syscall(__NR_eventfd2, initval, flags);
}
} // namespace folly
#endif /* FOLLY_BASE_EVENTFD_H_ */
/*
* Copyright 2012 Facebook, Inc.
*
* 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.
*/
#ifndef FOLLY_FILE_H_
#error This file may only be included from folly/experimental/File.h
#endif
#include <algorithm>
namespace folly {
inline File::File(int fd, bool ownsFd) : fd_(fd), ownsFd_(ownsFd) { }
inline File::~File() {
closeNoThrow(); // ignore error
}
inline void File::release() {
fd_ = -1;
ownsFd_ = false;
}
inline void File::swap(File& other) {
using std::swap;
swap(fd_, other.fd_);
swap(ownsFd_, other.ownsFd_);
}
inline File::File(File&& other) : fd_(other.fd_), ownsFd_(other.ownsFd_) {
other.release();
}
inline File& File::operator=(File&& other) {
File(std::move(other)).swap(*this);
return *this;
}
inline void swap(File& a, File& b) {
a.swap(b);
}
} // namespace folly
/*
* Copyright 2012 Facebook, Inc.
*
* 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.
*/
#include "folly/experimental/File.h"
#include <system_error>
#include <glog/logging.h>
namespace folly {
File::File(const char* name, int flags, mode_t mode)
: fd_(::open(name, flags, mode)), ownsFd_(false) {
if (fd_ == -1) {
throw std::system_error(errno, std::system_category(), "open() failed");
}
ownsFd_ = true;
}
void File::close() {
if (!closeNoThrow()) {
throw std::system_error(errno, std::system_category(), "close() failed");
}
}
bool File::closeNoThrow() {
int r = ownsFd_ ? ::close(fd_) : 0;
release();
return r == 0;
}
} // namespace folly
/*
* Copyright 2012 Facebook, Inc.
*
* 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.
*/
#ifndef FOLLY_FILE_H_
#define FOLLY_FILE_H_
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
namespace folly {
/**
* A File represents an open file.
*/
class File {
public:
/**
* Create a File object from an existing file descriptor.
* Takes ownership of the file descriptor if ownsFd is true.
*/
/* implicit */ File(int fd, bool ownsFd=false);
/**
* Open and create a file object. Throws on error.
*/
/* implicit */ File(const char* name, int flags=O_RDONLY, mode_t mode=0644);
~File();
/**
* Return the file descriptor, or -1 if the file was closed.
*/
int fd() const { return fd_; }
/**
* If we own the file descriptor, close the file and throw on error.
* Otherwise, do nothing.
*/
void close();
/**
* Closes the file (if owned). Returns true on success, false (and sets
* errno) on error.
*/
bool closeNoThrow();
/**
* Releases the file descriptor; no longer owned by this File.
*/
void release();
/**
* Swap this File with another.
*/
void swap(File& other);
// movable
File(File&&);
File& operator=(File&&);
private:
// not copyable
File(const File&) = delete;
File& operator=(const File&) = delete;
int fd_;
bool ownsFd_;
};
void swap(File& a, File& b);
} // namespace folly
#include "folly/experimental/File-inl.h"
#endif /* FOLLY_FILE_H_ */
/*
* Copyright 2013 Facebook, Inc.
*
* 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.
*/
#include "folly/experimental/exception_tracer/StackTrace.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#define UNW_LOCAL_ONLY 1
#include <libunwind.h>
struct Context {
StackTrace* trace;
size_t skip;
size_t capacity;
};
static int checkError(const char* name, int err) {
if (err < 0) {
fprintf(stderr, "libunwind error: %s %d\n", name, err);
return -EINVAL;
}
return 0;
}
static int addIP(struct Context* ctx, unw_cursor_t* cursor) {
if (ctx->skip) {
--ctx->skip;
return 0;
}
unw_word_t ip;
int r = unw_get_reg(cursor, UNW_REG_IP, &ip);
int err = checkError("unw_get_reg", r);
if (err) return err;
if (ctx->trace->frameCount == ctx->capacity) {
size_t newCapacity = (ctx->capacity < 8 ? 8 : ctx->capacity * 1.5);
uintptr_t* newBlock =
realloc(ctx->trace->frameIPs, newCapacity * sizeof(uintptr_t));
if (!newBlock) {
return -ENOMEM;
}
ctx->trace->frameIPs = newBlock;
ctx->capacity = newCapacity;
}
ctx->trace->frameIPs[ctx->trace->frameCount++] = ip;
return 0; /* success */
}
int getCurrentStackTrace(size_t skip, StackTrace* trace) {
trace->frameIPs = NULL;
trace->frameCount = 0;
struct Context ctx;
ctx.trace = trace;
ctx.skip = skip;
ctx.capacity = 0;
unw_context_t uctx;
int r = unw_getcontext(&uctx);
int err = checkError("unw_get_context", r);
if (err) return err;
unw_cursor_t cursor;
r = unw_init_local(&cursor, &uctx);
err = checkError("unw_init_local", r);
if (err) return err;
while ((r = unw_step(&cursor)) > 0) {
if ((err = addIP(&ctx, &cursor)) != 0) {
destroyStackTrace(trace);
return err;
}
}
err = checkError("unw_step", r);
if (err) return err;
return 0;
}
void destroyStackTrace(StackTrace* trace) {
free(trace->frameIPs);
trace->frameIPs = NULL;
trace->frameCount = 0;
}
int pushCurrentStackTrace(size_t skip, StackTraceStack** head) {
StackTraceStack* newHead = malloc(sizeof(StackTraceStack));
if (!newHead) {
return -ENOMEM;
}
int err;
if ((err = getCurrentStackTrace(skip, &newHead->trace)) != 0) {
free(newHead);
return -ENOMEM;
}
newHead->next = *head;
*head = newHead;
return 0;
}
void popStackTrace(StackTraceStack** head) {
StackTraceStack* oldHead = *head;
*head = oldHead->next;
destroyStackTrace(&oldHead->trace);
free(oldHead);
}
void clearStack(StackTraceStack** head) {
while (*head) {
popStackTrace(head);
}
}
int moveTop(StackTraceStack** from, StackTraceStack** to) {
StackTraceStack* top = *from;
if (!top) {
return -EINVAL;
}
*from = top->next;
top->next = *to;
*to = top;
return 0;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Copyright 2012 Facebook, Inc.
*
* 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.
*/
#include "folly/experimental/io/IOBufQueue.h"
#include <string.h>
#include <stdexcept>
using std::make_pair;
using std::pair;
using std::unique_ptr;
namespace {
using folly::IOBuf;
const size_t MIN_ALLOC_SIZE = 2000;
const size_t MAX_ALLOC_SIZE = 8000; // Must fit within a uint32_t
/**
* Convenience function to append chain src to chain dst.
*/
void
appendToChain(unique_ptr<IOBuf>& dst, unique_ptr<IOBuf>&& src) {
if (dst == NULL) {
dst = std::move(src);
} else {
dst->prev()->appendChain(std::move(src));
}
}
} // anonymous namespace
namespace folly {
IOBufQueue::IOBufQueue(const Options& options)
: options_(options),
chainLength_(0) {
}
IOBufQueue::IOBufQueue(IOBufQueue&& other)
: options_(other.options_),
chainLength_(other.chainLength_),
head_(std::move(other.head_)) {
other.chainLength_ = 0;
}
IOBufQueue& IOBufQueue::operator=(IOBufQueue&& other) {
if (&other != this) {
options_ = other.options_;
chainLength_ = other.chainLength_;
head_ = std::move(other.head_);
other.chainLength_ = 0;
}
return *this;
}
std::pair<void*, uint32_t>
IOBufQueue::headroom() {
if (head_) {
return std::make_pair(head_->writableBuffer(), head_->headroom());
} else {
return std::make_pair(nullptr, 0);
}
}
void
IOBufQueue::markPrepended(uint32_t n) {
if (n == 0) {
return;
}
assert(head_);
head_->prepend(n);
if (options_.cacheChainLength) {
chainLength_ += n;
}
}
void
IOBufQueue::prepend(const void* buf, uint32_t n) {
auto p = headroom();
if (n > p.second) {
throw std::overflow_error("Not enough room to prepend");
}
memcpy(static_cast<char*>(p.first) + p.second - n, buf, n);
markPrepended(n);
}
void
IOBufQueue::append(unique_ptr<IOBuf>&& buf) {
if (!buf) {
return;
}
if (options_.cacheChainLength) {
chainLength_ += buf->computeChainDataLength();
}
appendToChain(head_, std::move(buf));
}
void
IOBufQueue::append(IOBufQueue& other) {
if (!other.head_) {
return;
}
if (options_.cacheChainLength) {
if (other.options_.cacheChainLength) {
chainLength_ += other.chainLength_;
} else {
chainLength_ += other.head_->computeChainDataLength();
}
}
appendToChain(head_, std::move(other.head_));
other.chainLength_ = 0;
}
void
IOBufQueue::append(const void* buf, size_t len) {
auto src = static_cast<const uint8_t*>(buf);
while (len != 0) {
if ((head_ == NULL) || head_->prev()->isSharedOne() ||
(head_->prev()->tailroom() == 0)) {
appendToChain(head_, std::move(
IOBuf::create(std::max(MIN_ALLOC_SIZE,
std::min(len, MAX_ALLOC_SIZE)))));
}
IOBuf* last = head_->prev();
uint32_t copyLen = std::min(len, (size_t)last->tailroom());
memcpy(last->writableTail(), src, copyLen);
src += copyLen;
last->append(copyLen);
if (options_.cacheChainLength) {
chainLength_ += copyLen;
}
len -= copyLen;
}
}
void
IOBufQueue::wrapBuffer(const void* buf, size_t len, uint32_t blockSize) {
auto src = static_cast<const uint8_t*>(buf);
while (len != 0) {
size_t n = std::min(len, size_t(blockSize));
append(IOBuf::wrapBuffer(src, n));
src += n;
len -= n;
}
}
pair<void*,uint32_t>
IOBufQueue::preallocate(uint32_t min, uint32_t newAllocationSize,
uint32_t max) {
if (head_ != NULL) {
// If there's enough space left over at the end of the queue, use that.
IOBuf* last = head_->prev();
if (!last->isSharedOne()) {
uint32_t avail = last->tailroom();
if (avail >= min) {
return make_pair(last->writableTail(), std::min(max, avail));
}
}
}
// Allocate a new buffer of the requested max size.
unique_ptr<IOBuf> newBuf(IOBuf::create(std::max(min, newAllocationSize)));
appendToChain(head_, std::move(newBuf));
IOBuf* last = head_->prev();
return make_pair(last->writableTail(),
std::min(max, last->tailroom()));
}
void
IOBufQueue::postallocate(uint32_t n) {
head_->prev()->append(n);
if (options_.cacheChainLength) {
chainLength_ += n;
}
}
unique_ptr<IOBuf>
IOBufQueue::split(size_t n) {
unique_ptr<IOBuf> result;
while (n != 0) {
if (head_ == NULL) {
throw std::underflow_error(
"Attempt to remove more bytes than are present in IOBufQueue");
} else if (head_->length() <= n) {
n -= head_->length();
if (options_.cacheChainLength) {
chainLength_ -= head_->length();
}
unique_ptr<IOBuf> remainder = head_->pop();
appendToChain(result, std::move(head_));
head_ = std::move(remainder);
} else {
unique_ptr<IOBuf> clone = head_->cloneOne();
clone->trimEnd(clone->length() - n);
appendToChain(result, std::move(clone));
head_->trimStart(n);
if (options_.cacheChainLength) {
chainLength_ -= n;
}
break;
}
}
return std::move(result);
}
void IOBufQueue::trimStart(size_t amount) {
while (amount > 0) {
if (!head_) {
throw std::underflow_error(
"Attempt to trim more bytes than are present in IOBufQueue");
}
if (head_->length() > amount) {
head_->trimStart(amount);
if (options_.cacheChainLength) {
chainLength_ -= amount;
}
break;
}
amount -= head_->length();
if (options_.cacheChainLength) {
chainLength_ -= head_->length();
}
head_ = head_->pop();
}
}
void IOBufQueue::trimEnd(size_t amount) {
while (amount > 0) {
if (!head_) {
throw std::underflow_error(
"Attempt to trim more bytes than are present in IOBufQueue");
}
if (head_->prev()->length() > amount) {
head_->prev()->trimEnd(amount);
if (options_.cacheChainLength) {
chainLength_ -= amount;
}
break;
}
amount -= head_->prev()->length();
if (options_.cacheChainLength) {
chainLength_ -= head_->prev()->length();
}
unique_ptr<IOBuf> b = head_->prev()->unlink();
// Null queue if we unlinked the head.
if (b.get() == head_.get()) {
head_.reset();
}
}
}
} // folly
This diff is collapsed.
/*
* Copyright 2012 Facebook, Inc.
*
* 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.
*/
#ifndef FOLLY_IO_STREAM_H_
#error This file may only be included from Stream.h
#endif
#include <string.h>
#include <glog/logging.h>
namespace folly {
template <class Stream>
InputByteStreamSplitter<Stream>::InputByteStreamSplitter(
char delimiter, Stream stream)
: done_(false),
delimiter_(delimiter),
stream_(std::move(stream)) {
}
template <class Stream>
bool InputByteStreamSplitter<Stream>::operator()(ByteRange& chunk) {
DCHECK(!buffer_ || buffer_->length() == 0);
chunk.clear();
if (rest_.empty()) {
if (done_) {
return false;
} else if (!stream_(rest_)) {
done_ = true;
return false;
}
}
auto p = static_cast<const unsigned char*>(memchr(rest_.data(), delimiter_,
rest_.size()));
if (p) {
chunk.assign(rest_.data(), p);
rest_.assign(p + 1, rest_.end());
return true;
}
// Incomplete line read, copy to buffer
if (!buffer_) {
static const size_t kDefaultLineSize = 256;
// Arbitrarily assume that we have half of a line in rest_, and
// get enough room for twice that.
buffer_ = IOBuf::create(std::max(kDefaultLineSize, 2 * rest_.size()));
} else {
buffer_->reserve(0, rest_.size());
}
memcpy(buffer_->writableTail(), rest_.data(), rest_.size());
buffer_->append(rest_.size());
while (stream_(rest_)) {
auto p = static_cast<const unsigned char*>(
memchr(rest_.data(), delimiter_, rest_.size()));
if (p) {
// Copy everything up to the delimiter and return it
size_t n = p - rest_.data();
buffer_->reserve(0, n);
memcpy(buffer_->writableTail(), rest_.data(), n);
buffer_->append(n);
chunk.reset(buffer_->data(), buffer_->length());
buffer_->trimStart(buffer_->length());
rest_.assign(p + 1, rest_.end());
return true;
}
// Nope, copy the entire chunk that we read
buffer_->reserve(0, rest_.size());
memcpy(buffer_->writableTail(), rest_.data(), rest_.size());
buffer_->append(rest_.size());
}
// Incomplete last line
done_ = true;
rest_.clear();
chunk.reset(buffer_->data(), buffer_->length());
buffer_->trimStart(buffer_->length());
return true;
}
} // namespace folly
/*
* Copyright 2012 Facebook, Inc.
*
* 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.
*/
#include "folly/experimental/io/Stream.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdexcept>
#include <system_error>
#include "folly/String.h"
namespace folly {
FileInputByteStream::FileInputByteStream(int fd, bool ownsFd, size_t bufferSize)
: fd_(fd),
ownsFd_(ownsFd),
buffer_(IOBuf::create(bufferSize)) {
}
FileInputByteStream::FileInputByteStream(int fd, bool ownsFd,
std::unique_ptr<IOBuf>&& buffer)
: fd_(fd),
ownsFd_(ownsFd),
buffer_(std::move(buffer)) {
buffer_->clear();
}
bool FileInputByteStream::operator()(ByteRange& chunk) {
ssize_t n = ::read(fd_, buffer_->writableTail(), buffer_->capacity());
if (n == -1) {
throw std::system_error(errno, std::system_category(), "read failed");
}
chunk.reset(buffer_->tail(), n);
return (n != 0);
}
FileInputByteStream::FileInputByteStream(FileInputByteStream&& other)
: fd_(other.fd_),
ownsFd_(other.ownsFd_),
buffer_(std::move(other.buffer_)) {
other.fd_ = -1;
other.ownsFd_ = false;
}
FileInputByteStream& FileInputByteStream::operator=(
FileInputByteStream&& other) {
if (&other != this) {
closeNoThrow();
fd_ = other.fd_;
ownsFd_ = other.ownsFd_;
buffer_ = std::move(other.buffer_);
other.fd_ = -1;
other.ownsFd_ = false;
}
return *this;
}
FileInputByteStream::~FileInputByteStream() {
closeNoThrow();
}
void FileInputByteStream::closeNoThrow() {
if (!ownsFd_) {
return;
}
ownsFd_ = false;
if (::close(fd_) == -1) {
PLOG(ERROR) << "close failed";
}
}
InputByteStreamSplitter<FileInputByteStream> byLine(
const char* fileName, char delim) {
int fd = ::open(fileName, O_RDONLY);
if (fd == -1) {
throw std::system_error(errno, std::system_category(), "open failed");
}
return makeInputByteStreamSplitter(delim, FileInputByteStream(fd, true));
}
} // namespace folly
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Copyright 2013 Facebook, Inc.
*
* 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.
*/
#include "folly/FBString.h"
#ifdef _GLIBCXX_STDEXCEPT
#error Cannot include <stdexcept> in FBString.h\
(use std::__throw_* from funcexcept.h instead)
#endif
int main(){}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment