<commit_before>#ifndef CAFFE_UTIL_CUDNN_H_
#define CAFFE_UTIL_CUDNN_H_
#ifdef USE_CUDNN

#include <cudnn.h>

#include "caffe/proto/caffe.pb.h"

#define CUDNN_CHECK(condition) \
  do { \
    cudnnStatus_t status = condition; \
    CHECK_EQ(status, CUDNN_STATUS_SUCCESS) << " "\
      << cudnnGetErrorString(status); \
  } while (0)

inline const char* cudnnGetErrorString(cudnnStatus_t status) {
  switch (status) {
    case CUDNN_STATUS_SUCCESS:
      return "CUDNN_STATUS_SUCCESS";
    case CUDNN_STATUS_NOT_INITIALIZED:
      return "CUDNN_STATUS_NOT_INITIALIZED";
    case CUDNN_STATUS_ALLOC_FAILED:
      return "CUDNN_STATUS_ALLOC_FAILED";
    case CUDNN_STATUS_BAD_PARAM:
      return "CUDNN_STATUS_BAD_PARAM";
    case CUDNN_STATUS_INTERNAL_ERROR:
      return "CUDNN_STATUS_INTERNAL_ERROR";
    case CUDNN_STATUS_INVALID_VALUE:
      return "CUDNN_STATUS_INVALID_VALUE";
    case CUDNN_STATUS_ARCH_MISMATCH:
      return "CUDNN_STATUS_ARCH_MISMATCH";
    case CUDNN_STATUS_MAPPING_ERROR:
      return "CUDNN_STATUS_MAPPING_ERROR";
    case CUDNN_STATUS_EXECUTION_FAILED:
      return "CUDNN_STATUS_EXECUTION_FAILED";
    case CUDNN_STATUS_NOT_SUPPORTED:
      return "CUDNN_STATUS_NOT_SUPPORTED";
    case CUDNN_STATUS_LICENSE_ERROR:
      return "CUDNN_STATUS_LICENSE_ERROR";
  }
  return "Unknown cudnn status";
}

namespace caffe {

namespace cudnn {

template <typename Dtype> class dataType;
template<> class dataType<float>  {
 public:
  static const cudnnDataType_t type = CUDNN_DATA_FLOAT;
};
template<> class dataType<double> {
 public:
  static const cudnnDataType_t type = CUDNN_DATA_DOUBLE;
};

template <typename Dtype>
inline void createTensor4dDesc(cudnnTensor4dDescriptor_t* desc) {
  CUDNN_CHECK(cudnnCreateTensor4dDescriptor(desc));
}

template <typename Dtype>
inline void setTensor4dDesc(cudnnTensor4dDescriptor_t* desc,
    int n, int c, int h, int w,
    int stride_n, int stride_c, int stride_h, int stride_w) {
  CUDNN_CHECK(cudnnSetTensor4dDescriptorEx(*desc, dataType<Dtype>::type,
      n, c, h, w, stride_n, stride_c, stride_h, stride_w));
}

template <typename Dtype>
inline void setTensor4dDesc(cudnnTensor4dDescriptor_t* desc,
    int n, int c, int h, int w) {
  const int stride_w = 1;
  const int stride_h = w * stride_w;
  const int stride_c = h * stride_h;
  const int stride_n = c * stride_c;
  setTensor4dDesc<Dtype>(desc, n, c, h, w,
      stride_n, stride_c, stride_h, stride_w);
}

template <typename Dtype>
inline void createFilterDesc(cudnnFilterDescriptor_t* desc,
    int n, int c, int h, int w) {
  CUDNN_CHECK(cudnnCreateFilterDescriptor(desc));
  CUDNN_CHECK(cudnnSetFilterDescriptor(*desc, dataType<Dtype>::type,
      n, c, h, w));
}

template <typename Dtype>
inline void createConvolutionDesc(cudnnConvolutionDescriptor_t* conv,
    cudnnTensor4dDescriptor_t bottom, cudnnFilterDescriptor_t filter,
    int pad_h, int pad_w, int stride_h, int stride_w) {
  CUDNN_CHECK(cudnnCreateConvolutionDescriptor(conv));
  CUDNN_CHECK(cudnnSetConvolutionDescriptor(*conv, bottom, filter,
      pad_h, pad_w, stride_h, stride_w, 1, 1, CUDNN_CROSS_CORRELATION));
}

template <typename Dtype>
inline void createPoolingDesc(cudnnPoolingDescriptor_t* conv,
    PoolingParameter_PoolMethod poolmethod, cudnnPoolingMode_t* mode,
    int h, int w, int stride_h, int stride_w) {
  switch (poolmethod) {
  case PoolingParameter_PoolMethod_MAX:
    *mode = CUDNN_POOLING_MAX;
    break;
  case PoolingParameter_PoolMethod_AVE:
    *mode = CUDNN_POOLING_AVERAGE;
    break;
  default:
    LOG(FATAL) << "Unknown pooling method.";
  }
  CUDNN_CHECK(cudnnCreatePoolingDescriptor(conv));
  CUDNN_CHECK(cudnnSetPoolingDescriptor(*conv, *mode, h, w,
        stride_h, stride_w));
}

}  // namespace cudnn

}  // namespace caffe

#endif  // USE_CUDNN
#endif  // CAFFE_UTIL_CUDNN_H_
<commit_msg>separate setConvolutionDesc from createConvolutionDesc<commit_after>#ifndef CAFFE_UTIL_CUDNN_H_
#define CAFFE_UTIL_CUDNN_H_
#ifdef USE_CUDNN

#include <cudnn.h>

#include "caffe/proto/caffe.pb.h"

#define CUDNN_CHECK(condition) \
  do { \
    cudnnStatus_t status = condition; \
    CHECK_EQ(status, CUDNN_STATUS_SUCCESS) << " "\
      << cudnnGetErrorString(status); \
  } while (0)

inline const char* cudnnGetErrorString(cudnnStatus_t status) {
  switch (status) {
    case CUDNN_STATUS_SUCCESS:
      return "CUDNN_STATUS_SUCCESS";
    case CUDNN_STATUS_NOT_INITIALIZED:
      return "CUDNN_STATUS_NOT_INITIALIZED";
    case CUDNN_STATUS_ALLOC_FAILED:
      return "CUDNN_STATUS_ALLOC_FAILED";
    case CUDNN_STATUS_BAD_PARAM:
      return "CUDNN_STATUS_BAD_PARAM";
    case CUDNN_STATUS_INTERNAL_ERROR:
      return "CUDNN_STATUS_INTERNAL_ERROR";
    case CUDNN_STATUS_INVALID_VALUE:
      return "CUDNN_STATUS_INVALID_VALUE";
    case CUDNN_STATUS_ARCH_MISMATCH:
      return "CUDNN_STATUS_ARCH_MISMATCH";
    case CUDNN_STATUS_MAPPING_ERROR:
      return "CUDNN_STATUS_MAPPING_ERROR";
    case CUDNN_STATUS_EXECUTION_FAILED:
      return "CUDNN_STATUS_EXECUTION_FAILED";
    case CUDNN_STATUS_NOT_SUPPORTED:
      return "CUDNN_STATUS_NOT_SUPPORTED";
    case CUDNN_STATUS_LICENSE_ERROR:
      return "CUDNN_STATUS_LICENSE_ERROR";
  }
  return "Unknown cudnn status";
}

namespace caffe {

namespace cudnn {

template <typename Dtype> class dataType;
template<> class dataType<float>  {
 public:
  static const cudnnDataType_t type = CUDNN_DATA_FLOAT;
};
template<> class dataType<double> {
 public:
  static const cudnnDataType_t type = CUDNN_DATA_DOUBLE;
};

template <typename Dtype>
inline void createTensor4dDesc(cudnnTensor4dDescriptor_t* desc) {
  CUDNN_CHECK(cudnnCreateTensor4dDescriptor(desc));
}

template <typename Dtype>
inline void setTensor4dDesc(cudnnTensor4dDescriptor_t* desc,
    int n, int c, int h, int w,
    int stride_n, int stride_c, int stride_h, int stride_w) {
  CUDNN_CHECK(cudnnSetTensor4dDescriptorEx(*desc, dataType<Dtype>::type,
      n, c, h, w, stride_n, stride_c, stride_h, stride_w));
}

template <typename Dtype>
inline void setTensor4dDesc(cudnnTensor4dDescriptor_t* desc,
    int n, int c, int h, int w) {
  const int stride_w = 1;
  const int stride_h = w * stride_w;
  const int stride_c = h * stride_h;
  const int stride_n = c * stride_c;
  setTensor4dDesc<Dtype>(desc, n, c, h, w,
      stride_n, stride_c, stride_h, stride_w);
}

template <typename Dtype>
inline void createFilterDesc(cudnnFilterDescriptor_t* desc,
    int n, int c, int h, int w) {
  CUDNN_CHECK(cudnnCreateFilterDescriptor(desc));
  CUDNN_CHECK(cudnnSetFilterDescriptor(*desc, dataType<Dtype>::type,
      n, c, h, w));
}

template <typename Dtype>
inline void createConvolutionDesc(cudnnConvolutionDescriptor_t* conv) {
  CUDNN_CHECK(cudnnCreateConvolutionDescriptor(conv));
}

template <typename Dtype>
inline void setConvolutionDesc(cudnnConvolutionDescriptor_t* conv,
    cudnnTensor4dDescriptor_t bottom, cudnnFilterDescriptor_t filter,
    int pad_h, int pad_w, int stride_h, int stride_w) {
  CUDNN_CHECK(cudnnSetConvolutionDescriptor(*conv, bottom, filter,
      pad_h, pad_w, stride_h, stride_w, 1, 1, CUDNN_CROSS_CORRELATION));
}

template <typename Dtype>
inline void createPoolingDesc(cudnnPoolingDescriptor_t* conv,
    PoolingParameter_PoolMethod poolmethod, cudnnPoolingMode_t* mode,
    int h, int w, int stride_h, int stride_w) {
  switch (poolmethod) {
  case PoolingParameter_PoolMethod_MAX:
    *mode = CUDNN_POOLING_MAX;
    break;
  case PoolingParameter_PoolMethod_AVE:
    *mode = CUDNN_POOLING_AVERAGE;
    break;
  default:
    LOG(FATAL) << "Unknown pooling method.";
  }
  CUDNN_CHECK(cudnnCreatePoolingDescriptor(conv));
  CUDNN_CHECK(cudnnSetPoolingDescriptor(*conv, *mode, h, w,
        stride_h, stride_w));
}

}  // namespace cudnn

}  // namespace caffe

#endif  // USE_CUDNN
#endif  // CAFFE_UTIL_CUDNN_H_
<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief measure exec time of function
	@author MITSUNARI Shigeo
*/
#if defined(_MSC_VER) && (MSC_VER <= 1500)
	#include <cybozu/inttype.hpp>
#else
	#include <stdint.h>
#endif
#include <stdio.h>

#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
	#define CYBOZU_BENCH_USE_RDTSC
#endif
#ifdef CYBOZU_BENCH_USE_RDTSC
#ifdef _MSC_VER
	#include <intrin.h>
#endif
#else
	#include <cybozu/time.hpp>
#endif

namespace cybozu {

#ifdef CYBOZU_BENCH_USE_RDTSC
class CpuClock {
public:
	static inline uint64_t getRdtsc()
	{
#ifdef _MSC_VER
		return __rdtsc();
#else
		unsigned int eax, edx;
		__asm__ volatile("rdtsc" : "=a"(eax), "=d"(edx));
		return ((uint64_t)edx << 32) | eax;
#endif
	}
	CpuClock()
		: clock_(0)
		, count_(0)
	{
	}
	void begin()
	{
		clock_ -= getRdtsc();
	}
	void end()
	{
		clock_ += getRdtsc();
		count_++;
	}
	int getCount() const { return count_; }
	uint64_t getClock() const { return clock_; }
	void clear() { count_ = 0; clock_ = 0; }
	void put(const char *msg = 0, int N = 1) const
	{
		double t = getClock() / double(getCount()) / N;
		if (msg && *msg) printf("%s ", msg);
		if (t > 1e6) {
			printf("%7.3fMclk", t * 1e-6);
		} else if (t > 1e3) {
			printf("%7.3fKclk", t * 1e-3);
		} else {
			printf("%6.2f clk", t);
		}
		if (msg && *msg) printf("\n");
	}
	// adhoc constatns for CYBOZU_BENCH
	static const int loopN1 = 1000;
	static const int loopN2 = 1000000;
	static const uint64_t maxClk = (uint64_t)3e8;
private:
	uint64_t clock_;
	int count_;
};
#else
class CpuClock {
	cybozu::Time t_;
	uint64_t clock_;
	int count_;
public:
	CpuClock() : clock_(0), count_(0) { t_.setTime(0, 0); }
	void begin()
	{
		if (count_ == 0) t_.setCurrentTime(); // start
	}
	/*
		@note QQQ ; this is not same api as rdtsc version
	*/
	void end()
	{
		cybozu::Time cur(true);
		int diffSec = (int)(cur.getTime() - t_.getTime());
		int diffMsec = cur.getMsec() - t_.getMsec();
		const int diff = diffSec * 1000 + diffMsec;
		clock_ = diff;
		count_++;
	}
	int getCount() const { return count_; }
	uint64_t getClock() const { return clock_; }
	void clear() { t_.setTime(0, 0); clock_ = 0; count_ = 0; }
	void put(const char *msg = 0, int N = 1) const
	{
		double t = getClock() / double(getCount()) / N;
		if (msg && *msg) printf("%s ", msg);
		if (t > 1) {
			printf("%6.2fmsec", t);
		} else if (t > 1e-3) {
			printf("%6.2fusec", t * 1e3);
		} else {
			printf("%6.2fnsec", t * 1e6);
		}
		if (msg && *msg) printf("\n");
	}
	// adhoc constatns for CYBOZU_BENCH
	static const int loopN1 = 1000000;
	static const int loopN2 = 1000;
	static const uint64_t maxClk = (uint64_t)500;
};
#endif

namespace bench {

static CpuClock g_clk;
#ifdef __GNUC__
	#define CYBOZU_UNUSED __attribute__((unused))
#else
	#define CYBOZU_UNUSED
#endif
static int CYBOZU_UNUSED g_loopNum;

} // cybozu::bench
/*
	loop counter is automatically determined
	CYBOZU_BENCH(<msg>, <func>, <param1>, <param2>, ...);
	if msg == "" then only set g_clk, g_loopNum
*/
#define CYBOZU_BENCH(msg, func, ...) \
{ \
	const uint64_t _cybozu_maxClk = cybozu::CpuClock::maxClk; \
	cybozu::CpuClock _cybozu_clk; \
	for (int _cybozu_i = 0; _cybozu_i < cybozu::CpuClock::loopN2; _cybozu_i++) { \
		_cybozu_clk.begin(); \
		for (int _cybozu_j = 0; _cybozu_j < cybozu::CpuClock::loopN1; _cybozu_j++) { func(__VA_ARGS__); } \
		_cybozu_clk.end(); \
		if (_cybozu_clk.getClock() > _cybozu_maxClk) break; \
	} \
	if (msg && *msg) _cybozu_clk.put(msg, cybozu::CpuClock::loopN1); \
	cybozu::bench::g_clk = _cybozu_clk; cybozu::bench::g_loopNum = cybozu::CpuClock::loopN1; \
}

/*
	loop counter N is given
	CYBOZU_BENCH_C(<msg>, <counter>, <func>, <param1>, <param2>, ...);
	if msg == "" then only set g_clk, g_loopNum
*/
#define CYBOZU_BENCH_C(msg, _N, func, ...) \
{ \
	cybozu::CpuClock _cybozu_clk; \
	_cybozu_clk.begin(); \
	for (int _cybozu_j = 0; _cybozu_j < _N; _cybozu_j++) { func(__VA_ARGS__); } \
	_cybozu_clk.end(); \
	if (msg && *msg) _cybozu_clk.put(msg, _N); \
	cybozu::bench::g_clk = _cybozu_clk; cybozu::bench::g_loopNum = _N; \
}

} // cybozu
<commit_msg>use clock_time<commit_after>#pragma once
/**
	@file
	@brief measure exec time of function
	@author MITSUNARI Shigeo
*/
#if defined(_MSC_VER) && (MSC_VER <= 1500)
	#include <cybozu/inttype.hpp>
#else
	#include <stdint.h>
#endif
#include <stdio.h>

#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
	#define CYBOZU_BENCH_USE_RDTSC
#endif
#ifdef CYBOZU_BENCH_USE_RDTSC
#ifdef _MSC_VER
	#include <intrin.h>
#endif
#else
	#include <time.h>
	#include <assert.h>
#endif

namespace cybozu {

#ifdef CYBOZU_BENCH_USE_RDTSC
class CpuClock {
public:
	static inline uint64_t getRdtsc()
	{
#ifdef _MSC_VER
		return __rdtsc();
#else
		unsigned int eax, edx;
		__asm__ volatile("rdtsc" : "=a"(eax), "=d"(edx));
		return ((uint64_t)edx << 32) | eax;
#endif
	}
	CpuClock()
		: clock_(0)
		, count_(0)
	{
	}
	void begin()
	{
		clock_ -= getRdtsc();
	}
	void end()
	{
		clock_ += getRdtsc();
		count_++;
	}
	int getCount() const { return count_; }
	uint64_t getClock() const { return clock_; }
	void clear() { count_ = 0; clock_ = 0; }
	void put(const char *msg = 0, int N = 1) const
	{
		double t = getClock() / double(getCount()) / N;
		if (msg && *msg) printf("%s ", msg);
		if (t > 1e6) {
			printf("%7.3fMclk", t * 1e-6);
		} else if (t > 1e3) {
			printf("%7.3fKclk", t * 1e-3);
		} else {
			printf("%6.2f clk", t);
		}
		if (msg && *msg) printf("\n");
	}
	// adhoc constatns for CYBOZU_BENCH
	static const int loopN1 = 1000;
	static const int loopN2 = 1000000;
	static const uint64_t maxClk = (uint64_t)3e8;
private:
	uint64_t clock_;
	int count_;
};
#else
class CpuClock {
	uint64_t startNsec_;
	uint64_t clock_;
	int count_;
	uint64_t getTimeNsec() const
	{
		struct timespec tp;
		int ret __attribute__((unused)) = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp);
		assert(ret == 0);
		return tp.tv_sec * 1000000000 + tp.tv_nsec;
	}
public:
	CpuClock() : startNsec_(0), clock_(0), count_(0) { }
	void begin()
	{
		startNsec_ = getTimeNsec();
	}
	/*
		@note QQQ ; this is not same api as rdtsc version
	*/
	void end()
	{
		uint64_t cur = getTimeNsec();
		clock_ += cur - startNsec_;
		startNsec_ = cur;
		count_++;
	}
	int getCount() const { return count_; }
	uint64_t getClock() const { return clock_; }
	void clear() { startNsec_ = 0; clock_ = 0; count_ = 0; }
	void put(const char *msg = 0, int N = 1) const
	{
		double t = getClock() / double(getCount()) / N;
		if (msg && *msg) printf("%s ", msg);
		if (t > 1e6) {
			printf("%7.3fmsec", t * 1e-6);
		} else if (t > 1e3) {
			printf("%7.3fusec", t * 1e-3);
		} else {
			printf("%6.2fnsec", t);
		}
		if (msg && *msg) printf("\n");
	}
	// adhoc constatns for CYBOZU_BENCH
	static const int loopN1 = 1000;
	static const int loopN2 = 1000000;
	static const uint64_t maxClk = (uint64_t)3e8;
};
#endif

namespace bench {

static CpuClock g_clk;
#ifdef __GNUC__
	#define CYBOZU_UNUSED __attribute__((unused))
#else
	#define CYBOZU_UNUSED
#endif
static int CYBOZU_UNUSED g_loopNum;

} // cybozu::bench
/*
	loop counter is automatically determined
	CYBOZU_BENCH(<msg>, <func>, <param1>, <param2>, ...);
	if msg == "" then only set g_clk, g_loopNum
*/
#define CYBOZU_BENCH(msg, func, ...) \
{ \
	const uint64_t _cybozu_maxClk = cybozu::CpuClock::maxClk; \
	cybozu::CpuClock _cybozu_clk; \
	for (int _cybozu_i = 0; _cybozu_i < cybozu::CpuClock::loopN2; _cybozu_i++) { \
		_cybozu_clk.begin(); \
		for (int _cybozu_j = 0; _cybozu_j < cybozu::CpuClock::loopN1; _cybozu_j++) { func(__VA_ARGS__); } \
		_cybozu_clk.end(); \
		if (_cybozu_clk.getClock() > _cybozu_maxClk) break; \
	} \
	if (msg && *msg) _cybozu_clk.put(msg, cybozu::CpuClock::loopN1); \
	cybozu::bench::g_clk = _cybozu_clk; cybozu::bench::g_loopNum = cybozu::CpuClock::loopN1; \
}

/*
	loop counter N is given
	CYBOZU_BENCH_C(<msg>, <counter>, <func>, <param1>, <param2>, ...);
	if msg == "" then only set g_clk, g_loopNum
*/
#define CYBOZU_BENCH_C(msg, _N, func, ...) \
{ \
	cybozu::CpuClock _cybozu_clk; \
	_cybozu_clk.begin(); \
	for (int _cybozu_j = 0; _cybozu_j < _N; _cybozu_j++) { func(__VA_ARGS__); } \
	_cybozu_clk.end(); \
	if (msg && *msg) _cybozu_clk.put(msg, _N); \
	cybozu::bench::g_clk = _cybozu_clk; cybozu::bench::g_loopNum = _N; \
}

} // cybozu
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "util/tmp.hpp"
#include "base_traits.hpp"
#include "layer_fwd.hpp"
#include "base_conf.hpp"

namespace dll {

/*!
 * \brief Type Traits to get information on layer type
 */
template <typename Layer>
struct layer_traits {
    using layer_t     = Layer;                      ///< The layer type being inspected
    using base_traits = layer_base_traits<layer_t>; ///< The base traits for the layer

    /*!
     * \brief Indicates if the layer is neural (dense or conv)
     */
    static constexpr bool is_neural_layer() {
        return base_traits::is_neural;
    }

    /*!
     * \brief Indicates if the layer is dense
     */
    static constexpr bool is_dense_layer() {
        return base_traits::is_dense;
    }

    /*!
     * \brief Indicates if the layer is convolutional
     */
    static constexpr bool is_convolutional_layer() {
        return base_traits::is_conv;
    }

    /*!
     * \brief Indicates if the layer is convolutional
     */
    static constexpr bool is_deconvolutional_layer() {
        return base_traits::is_deconv;
    }

    /*!
     * \brief Indicates if the layer is a standard (non-rbm) layer.
     */
    static constexpr bool is_standard_layer() {
        return base_traits::is_standard;
    }

    /*!
     * \brief Indicates if the layer is a standard (non-rbm) dense layer.
     */
    static constexpr bool is_standard_dense_layer() {
        return is_standard_layer() && is_dense_layer();
    }

    /*!
     * \brief Indicates if the layer is a standard (non-rbm) convolutionl layer.
     */
    static constexpr bool is_standard_convolutional_layer() {
        return is_standard_layer() && is_convolutional_layer();
    }

    /*!
     * \brief Indicates if the layer is a standard (non-rbm) deconvolutionl layer.
     */
    static constexpr bool is_standard_deconvolutional_layer() {
        return is_standard_layer() && is_deconvolutional_layer();
    }

    /*!
     * \brief Indicates if this layer is a RBM layer.
     */
    static constexpr bool is_rbm_layer() {
        return base_traits::is_rbm;
    }

    /*!
     * \brief Indicates if this layer is a dense RBM layer.
     */
    static constexpr bool is_dense_rbm_layer() {
        return is_rbm_layer() && is_dense_layer();
    }

    /*!
     * \brief Indicates if the layer is convolutional
     */
    static constexpr bool is_convolutional_rbm_layer() {
        return is_rbm_layer() && is_convolutional_layer();
    }

    /*!
     * \brief Indicates if this layer is a pooling layer.
     */
    static constexpr bool is_pooling_layer() {
        return base_traits::is_pooling;
    }

    /*!
     * \brief Indicates if this layer is a pooling layer.
     */
    static constexpr bool is_unpooling_layer() {
        return base_traits::is_unpooling;
    }

    /*!
     * \brief Indicates if this layer is a transformation layer.
     */
    static constexpr bool is_transform_layer() {
        return base_traits::is_transform;
    }

    /*!
     * \brief Indicates if this layer keeps the same type
     */
    static constexpr bool has_same_type() {
        return is_transform_layer();
    }

    /*!
     * \brief Indicates if this layer is trained or not.
     */
    static constexpr bool is_trained() {
        return is_neural_layer();
    }

    /*!
     * \brief Indicates if this layer is pretrained or not.
     */
    static constexpr bool is_pretrained() {
        return is_rbm_layer();
    }

    /*!
     * \brief Indicates if the layer is dynamic
     */
    static constexpr bool is_dynamic() {
        return base_traits::is_dynamic;
    }

    static constexpr bool pretrain_last() {
        return base_traits::pretrain_last;
    }
};

/*!
 * \brief Type Traits to get information on layer type
 */
template <typename Layer>
struct rbm_layer_traits {
    using layer_t     = Layer;                          ///< The layer type being inspected
    using base_traits = rbm_layer_base_traits<layer_t>; ///< The base traits for the layer

    /*!
     * \brief Indicates if the RBM must be trained with momentum or not
     */
    static constexpr bool has_momentum() {
        return base_traits::has_momentum;
    }

    static constexpr bool has_clip_gradients() {
        return base_traits::has_clip_gradients;
    }

    /*!
     * \brief Indicates if the RBM must be trained in parallel mode instead of batch mode
     */
    static constexpr bool is_parallel_mode() {
        return base_traits::is_parallel_mode;
    }

    /*!
     * \brief Indicates if the RBM cannot use threads.
     */
    static constexpr bool is_serial() {
        return base_traits::is_serial;
    }

    /*!
     * \brief Indicates if the RBM training is made verbose.
     */
    static constexpr bool is_verbose() {
        return base_traits::is_verbose;
    }

    /*!
     * \brief Indicates if the RBM must be trained with shuffle or not
     */
    static constexpr bool has_shuffle() {
        return base_traits::has_shuffle;
    }

    /*!
     * \brief Indicates if the RBM is only to be used inside a DBN.
     *
     * This can save some memory
     */
    static constexpr bool is_dbn_only() {
        return base_traits::is_dbn_only;
    }

    /*!
     * \brief Indicates if the RBM must be trained with sparsity or not
     */
    static constexpr bool has_sparsity() {
        return base_traits::has_sparsity;
    }

    static constexpr dll::sparsity_method sparsity_method() {
        return base_traits::sparsity_method;
    }

    /*
     * \brief Return the bias mode t be used for the LEE sparsity regularization
     */
    static constexpr enum dll::bias_mode bias_mode() {
        return base_traits::bias_mode;
    }

    /*
     * \brief Return the type of weight decay
     */
    static constexpr decay_type decay() {
        return base_traits::decay;
    }

    /*!
     * \brief Indicates if the weights of the RBM should be initialized using
     * the inputs according to Hinton
     */
    static constexpr bool init_weights() {
        return base_traits::has_init_weights;
    }

    /*!
     * \brief Indicates if the RBM's free energy is displayed while training.
     */
    static constexpr bool free_energy() {
        return base_traits::has_free_energy;
    }
};

template <typename T>
using decay_layer_traits = layer_traits<std::decay_t<T>>;

/*!
 * \brief Return the batch size of the given RBM
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_batch_size(const RBM& rbm) {
    return rbm.batch_size;
}

/*!
 * \brief Return the batch size of the given RBM
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_batch_size(const RBM&) {
    return RBM::batch_size;
}

/*!
 * \brief Return the number of input channels of the given CRBM
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nc(const RBM& rbm) {
    return rbm.nc;
}

/*!
 * \brief Return the number of input channels of the given CRBM
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nc(const RBM&) {
    return RBM::NC;
}

/*!
 * \brief Return the number of filters of the given CRBM
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_k(const RBM& rbm) {
    return rbm.k;
}

/*!
 * \brief Return the number of filters of the given CRBM
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_k(const RBM&) {
    return RBM::K;
}

/*!
 * \brief Return the first dimension of the inputs
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nv1(const RBM& rbm) {
    return rbm.nv1;
}

/*!
 * \brief Return the first dimension of the inputs
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nv1(const RBM&) {
    return RBM::NV1;
}

/*!
 * \brief Return the second dimension of the inputs
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nv2(const RBM& rbm) {
    return rbm.nv2;
}

/*!
 * \brief Return the second dimension of the inputs
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nv2(const RBM&) {
    return RBM::NV2;
}

/*!
 * \brief Return the first dimension of the filters
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nw1(const RBM& rbm) {
    return rbm.nw1;
}

/*!
 * \brief Return the first dimension of the filters
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nw1(const RBM&) {
    return RBM::NW1;
}

/*!
 * \brief Return the second dimension of the filters
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nw2(const RBM& rbm) {
    return rbm.nw2;
}

/*!
 * \brief Return the second dimension of the filters
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nw2(const RBM&) {
    return RBM::NW2;
}

/*!
 * \brief Return the number of visible units of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t num_visible(const RBM& rbm) {
    return rbm.num_visible;
}

/*!
 * \brief Return the number of visible units of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t num_visible(const RBM&) {
    return RBM::desc::num_visible;
}

/*!
 * \brief Return the number of hidden units of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t num_hidden(const RBM& rbm) {
    return rbm.num_hidden;
}

/*!
 * \brief Return the number of hidden units of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t num_hidden(const RBM&) {
    return RBM::desc::num_hidden;
}

/*!
 * \brief Return the output size of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t output_size(const RBM&) {
    return RBM::output_size();
}

/*!
 * \brief Return the output size of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t output_size(const RBM& rbm) {
    return rbm.output_size();
}

/*!
 * \brief Return the input size of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t input_size(const RBM& rbm) {
    return rbm.input_size();
}

/*!
 * \brief Return the input size of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t input_size(const RBM&) {
    return RBM::input_size();
}

} //end of dll namespace
<commit_msg>Fix the doc comments<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include "util/tmp.hpp"
#include "base_traits.hpp"
#include "layer_fwd.hpp"
#include "base_conf.hpp"

namespace dll {

/*!
 * \brief Type Traits to get information on layer type
 */
template <typename Layer>
struct layer_traits {
    using layer_t     = Layer;                      ///< The layer type being inspected
    using base_traits = layer_base_traits<layer_t>; ///< The base traits for the layer

    /*!
     * \brief Indicates if the layer is neural (dense or conv)
     */
    static constexpr bool is_neural_layer() {
        return base_traits::is_neural;
    }

    /*!
     * \brief Indicates if the layer is dense
     */
    static constexpr bool is_dense_layer() {
        return base_traits::is_dense;
    }

    /*!
     * \brief Indicates if the layer is convolutional
     */
    static constexpr bool is_convolutional_layer() {
        return base_traits::is_conv;
    }

    /*!
     * \brief Indicates if the layer is convolutional
     */
    static constexpr bool is_deconvolutional_layer() {
        return base_traits::is_deconv;
    }

    /*!
     * \brief Indicates if the layer is a standard (non-rbm) layer.
     */
    static constexpr bool is_standard_layer() {
        return base_traits::is_standard;
    }

    /*!
     * \brief Indicates if the layer is a standard (non-rbm) dense layer.
     */
    static constexpr bool is_standard_dense_layer() {
        return is_standard_layer() && is_dense_layer();
    }

    /*!
     * \brief Indicates if the layer is a standard (non-rbm) convolutionl layer.
     */
    static constexpr bool is_standard_convolutional_layer() {
        return is_standard_layer() && is_convolutional_layer();
    }

    /*!
     * \brief Indicates if the layer is a standard (non-rbm) deconvolutionl layer.
     */
    static constexpr bool is_standard_deconvolutional_layer() {
        return is_standard_layer() && is_deconvolutional_layer();
    }

    /*!
     * \brief Indicates if this layer is a RBM layer.
     */
    static constexpr bool is_rbm_layer() {
        return base_traits::is_rbm;
    }

    /*!
     * \brief Indicates if this layer is a dense RBM layer.
     */
    static constexpr bool is_dense_rbm_layer() {
        return is_rbm_layer() && is_dense_layer();
    }

    /*!
     * \brief Indicates if the layer is convolutional
     */
    static constexpr bool is_convolutional_rbm_layer() {
        return is_rbm_layer() && is_convolutional_layer();
    }

    /*!
     * \brief Indicates if this layer is a pooling layer.
     */
    static constexpr bool is_pooling_layer() {
        return base_traits::is_pooling;
    }

    /*!
     * \brief Indicates if this layer is a pooling layer.
     */
    static constexpr bool is_unpooling_layer() {
        return base_traits::is_unpooling;
    }

    /*!
     * \brief Indicates if this layer is a transformation layer.
     */
    static constexpr bool is_transform_layer() {
        return base_traits::is_transform;
    }

    /*!
     * \brief Indicates if this layer keeps the same type
     */
    static constexpr bool has_same_type() {
        return is_transform_layer();
    }

    /*!
     * \brief Indicates if this layer is trained or not.
     */
    static constexpr bool is_trained() {
        return is_neural_layer();
    }

    /*!
     * \brief Indicates if this layer is pretrained or not.
     */
    static constexpr bool is_pretrained() {
        return is_rbm_layer();
    }

    /*!
     * \brief Indicates if the layer is dynamic
     */
    static constexpr bool is_dynamic() {
        return base_traits::is_dynamic;
    }

    static constexpr bool pretrain_last() {
        return base_traits::pretrain_last;
    }
};

/*!
 * \brief Type Traits to get information on layer type
 */
template <typename Layer>
struct rbm_layer_traits {
    using layer_t     = Layer;                          ///< The layer type being inspected
    using base_traits = rbm_layer_base_traits<layer_t>; ///< The base traits for the layer

    /*!
     * \brief Indicates if the RBM must be trained with momentum or not
     */
    static constexpr bool has_momentum() {
        return base_traits::has_momentum;
    }

    static constexpr bool has_clip_gradients() {
        return base_traits::has_clip_gradients;
    }

    /*!
     * \brief Indicates if the RBM must be trained in parallel mode instead of batch mode
     */
    static constexpr bool is_parallel_mode() {
        return base_traits::is_parallel_mode;
    }

    /*!
     * \brief Indicates if the RBM cannot use threads.
     */
    static constexpr bool is_serial() {
        return base_traits::is_serial;
    }

    /*!
     * \brief Indicates if the RBM training is made verbose.
     */
    static constexpr bool is_verbose() {
        return base_traits::is_verbose;
    }

    /*!
     * \brief Indicates if the RBM must be trained with shuffle or not
     */
    static constexpr bool has_shuffle() {
        return base_traits::has_shuffle;
    }

    /*!
     * \brief Indicates if the RBM is only to be used inside a DBN.
     *
     * This can save some memory
     */
    static constexpr bool is_dbn_only() {
        return base_traits::is_dbn_only;
    }

    /*!
     * \brief Indicates if the RBM must be trained with sparsity or not
     */
    static constexpr bool has_sparsity() {
        return base_traits::has_sparsity;
    }

    static constexpr dll::sparsity_method sparsity_method() {
        return base_traits::sparsity_method;
    }

    /*!
     * \brief Return the bias mode t be used for the LEE sparsity regularization
     */
    static constexpr enum dll::bias_mode bias_mode() {
        return base_traits::bias_mode;
    }

    /*!
     * \brief Return the type of weight decay
     */
    static constexpr decay_type decay() {
        return base_traits::decay;
    }

    /*!
     * \brief Indicates if the weights of the RBM should be initialized using
     * the inputs according to Hinton
     */
    static constexpr bool init_weights() {
        return base_traits::has_init_weights;
    }

    /*!
     * \brief Indicates if the RBM's free energy is displayed while training.
     */
    static constexpr bool free_energy() {
        return base_traits::has_free_energy;
    }
};

template <typename T>
using decay_layer_traits = layer_traits<std::decay_t<T>>;

/*!
 * \brief Return the batch size of the given RBM
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_batch_size(const RBM& rbm) {
    return rbm.batch_size;
}

/*!
 * \brief Return the batch size of the given RBM
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_batch_size(const RBM&) {
    return RBM::batch_size;
}

/*!
 * \brief Return the number of input channels of the given CRBM
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nc(const RBM& rbm) {
    return rbm.nc;
}

/*!
 * \brief Return the number of input channels of the given CRBM
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nc(const RBM&) {
    return RBM::NC;
}

/*!
 * \brief Return the number of filters of the given CRBM
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_k(const RBM& rbm) {
    return rbm.k;
}

/*!
 * \brief Return the number of filters of the given CRBM
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_k(const RBM&) {
    return RBM::K;
}

/*!
 * \brief Return the first dimension of the inputs
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nv1(const RBM& rbm) {
    return rbm.nv1;
}

/*!
 * \brief Return the first dimension of the inputs
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nv1(const RBM&) {
    return RBM::NV1;
}

/*!
 * \brief Return the second dimension of the inputs
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nv2(const RBM& rbm) {
    return rbm.nv2;
}

/*!
 * \brief Return the second dimension of the inputs
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nv2(const RBM&) {
    return RBM::NV2;
}

/*!
 * \brief Return the first dimension of the filters
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nw1(const RBM& rbm) {
    return rbm.nw1;
}

/*!
 * \brief Return the first dimension of the filters
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nw1(const RBM&) {
    return RBM::NW1;
}

/*!
 * \brief Return the second dimension of the filters
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t get_nw2(const RBM& rbm) {
    return rbm.nw2;
}

/*!
 * \brief Return the second dimension of the filters
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t get_nw2(const RBM&) {
    return RBM::NW2;
}

/*!
 * \brief Return the number of visible units of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t num_visible(const RBM& rbm) {
    return rbm.num_visible;
}

/*!
 * \brief Return the number of visible units of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t num_visible(const RBM&) {
    return RBM::desc::num_visible;
}

/*!
 * \brief Return the number of hidden units of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t num_hidden(const RBM& rbm) {
    return rbm.num_hidden;
}

/*!
 * \brief Return the number of hidden units of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t num_hidden(const RBM&) {
    return RBM::desc::num_hidden;
}

/*!
 * \brief Return the output size of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t output_size(const RBM&) {
    return RBM::output_size();
}

/*!
 * \brief Return the output size of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t output_size(const RBM& rbm) {
    return rbm.output_size();
}

/*!
 * \brief Return the input size of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_enable_if(layer_traits<RBM>::is_dynamic())>
size_t input_size(const RBM& rbm) {
    return rbm.input_size();
}

/*!
 * \brief Return the input size of the given RBM
 * \param rbm The RBM to get the information from
 */
template <typename RBM, cpp_disable_if(layer_traits<RBM>::is_dynamic())>
constexpr size_t input_size(const RBM&) {
    return RBM::input_size();
}

} //end of dll namespace
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

namespace etl {

/*!
 * \brief Unary operation that clips all values between two scalars
 * \tparam T the type of value
 * \tparam S the type of scalar
 */
template <typename T, typename S>
struct clip_scalar_op {
    /*!
     * The vectorization type for V
     */
    template <typename V = default_vec>
    using vec_type       = typename V::template vec_type<T>;

    static constexpr bool linear = true; ///< Indicates if the operator is linear or not
    static constexpr bool thread_safe = true;  ///< Indicates if the operator is thread safe or not

    /*!
     * \brief Indicates if the expression is vectorizable using the
     * given vector mode
     * \tparam V The vector mode
     */
    template <vector_mode_t V>
    static constexpr bool vectorizable = intel_compiler && !is_complex_t<T>;

    /*!
     * \brief Indicates if the operator can be computed on GPU
     */
    template <typename E>
    static constexpr bool gpu_computable = false;

    S min; ///< The minimum for clipping
    S max; ///< The maximum for clipping

    /*!
     * \brief Builds a new operator
     * \param min The minimum for clipping
     * \param max The maximum for clipping
     */
    clip_scalar_op(S min, S max)
            : min(min), max(max) {}

    /*!
     * \brief Apply the unary operator on x
     * \param x The value on which to apply the operator
     * \return The result of applying the unary operator on x
     */
    constexpr T apply(const T& x) const noexcept {
        return std::min(std::max(x, min), max);
    }

#ifdef __INTEL_COMPILER
    /*!
     * \brief Compute several applications of the operator at a time
     * \param x The vector on which to operate
     * \tparam V The vectorization mode
     * \return a vector containing several results of the operator
     */
    template <typename V = default_vec>
    vec_type<V> load(const vec_type<V>& lhs) const noexcept {
        return V::min(V::max(lhs, V::set(min)), V::set(max));
    }
#endif

    /*!
     * \brief Returns a textual representation of the operator
     * \return a string representing the operator
     */
    static std::string desc() noexcept {
        return "clip";
    }
};

} //end of namespace etl
<commit_msg>Restore max unary op<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

namespace etl {

/*!
 * \brief Unary operation applying the max between the value and a scalar
 * \tparam T the type of value
 * \tparam S the type of scalar
 */
template <typename T, typename S>
struct max_scalar_op {
    /*!
     * The vectorization type for V
     */
    template <typename V = default_vec>
    using vec_type       = typename V::template vec_type<T>;

    static constexpr bool linear      = true; ///< Indicates if the operator is linear or not
    static constexpr bool thread_safe = true; ///< Indicates if the operator is thread safe or not

    /*!
     * \brief Indicates if the expression is vectorizable using the
     * given vector mode
     * \tparam V The vector mode
     */
    template <vector_mode_t V>
    static constexpr bool vectorizable = !is_complex_t<T>;

    /*!
     * \brief Indicates if the operator can be computed on GPU
     */
    template <typename E>
    static constexpr bool gpu_computable = false;

    S s; ///< The scalar value

    /*!
     * \brief Construct a new max_scalar_op with the given value
     * \param s The scalar value
     */
    explicit max_scalar_op(S s)
            : s(s) {}

    /*!
     * \brief Apply the unary operator on x
     * \param x The value on which to apply the operator
     * \return The result of applying the unary operator on x
     */
    constexpr T apply(const T& x) const noexcept {
        return std::max(x, s);
    }

    /*!
     * \brief Compute several applications of the operator at a time
     * \param lhs The vector on which to operate
     * \tparam V The vectorization mode
     * \return a vector containing several results of the operator
     */
    template <typename V = default_vec>
    vec_type<V> load(const vec_type<V>& lhs) const noexcept {
        return V::max(lhs, V::set(s));
    }

    /*!
     * \brief Returns a textual representation of the operator
     * \return a string representing the operator
     */
    static std::string desc() noexcept {
        return "max";
    }
};

} //end of namespace etl
<|endoftext|>


<commit_before>#ifndef GHULBUS_LIBRARY_INCLUDE_GUARD_BASE_FIXED_RING_HPP
#define GHULBUS_LIBRARY_INCLUDE_GUARD_BASE_FIXED_RING_HPP

/** @file
*
* @brief Fixed-size ring buffer.
* @author Andreas Weis (der_ghulbus@ghulbus-inc.de)
*/

#include <gbBase/config.hpp>
#include <gbBase/Assert.hpp>

#include <memory>
#include <vector>

namespace GHULBUS_BASE_NAMESPACE
{

template<typename T, class Allocator = std::allocator<T>>
class FixedRing {
public:
    using value_type = T;
    using allocator_type = Allocator;
    using size_type = typename std::vector<T>::size_type;
    using reference = value_type&;
    using const_reference = value_type const&;
private:
    std::vector<T, Allocator> m_ring;
    size_type m_push_idx;
    size_type m_n_elements;

    size_type front_index() const
    {
        size_type const end_idx = (m_push_idx < m_n_elements) ? (m_push_idx + m_ring.capacity()) : m_push_idx;
        return end_idx - m_n_elements;
    }

    size_type nth_index(size_type n) const
    {
        auto const offs = m_n_elements - n;
        return (m_push_idx < offs) ? (m_push_idx + m_ring.capacity() - offs) : (m_push_idx - offs);
    }
public:
    explicit FixedRing(size_type capacity, Allocator const& alloc = Allocator())
        :m_ring(alloc), m_push_idx(0), m_n_elements(0)
    {
        GHULBUS_PRECONDITION(capacity > 0);
        m_ring.reserve(capacity);
    }

    ~FixedRing() = default;
    FixedRing(FixedRing const&) = default;
    FixedRing& operator=(FixedRing const&) = default;
    FixedRing(FixedRing&&) = default;
    FixedRing& operator=(FixedRing&&) = default;

    /** Push an element to the back of the ring buffer.
     * \pre !full()
     */
    void push_back(T const& v)
    {
        GHULBUS_PRECONDITION(!full());
        if (m_ring.size() < m_ring.capacity()) {
            m_ring.push_back(v);
            ++m_push_idx;
            ++m_n_elements;
            return;
        }
        if (m_push_idx == m_ring.capacity()) { m_push_idx = 0; }
        m_ring[m_push_idx++] = v;
        ++m_n_elements;
    }

    /** Retrieve an element from the front of the ring buffer.
     * \pre !empty()
     */
    value_type pop_front()
    {
        GHULBUS_PRECONDITION(!empty());
        auto const front_idx = front_index();
        --m_n_elements;
        return std::move(m_ring[front_idx]);
    }

    /** Maximum number of elements that the ring buffer can hold at once.
     */
    size_type capacity() const noexcept
    {
        return m_ring.capacity();
    }

    /** Number of elements currently stored in the ring buffer.
     */
    size_type available() const noexcept
    {
        return m_n_elements;
    }

    /** Number of free slots available for storing additional elements in the ring buffer.
     */
    size_type free() const noexcept
    {
        return m_ring.capacity() - m_n_elements;
    }

    bool empty() const noexcept
    {
        return available() == 0;
    }

    bool full() const noexcept
    {
        return free() == 0;
    }

    reference operator[](size_type index) noexcept
    {
        GHULBUS_PRECONDITION((index >= 0) && (index < m_n_elements));
        return m_ring[nth_index(index)];
    }

    const_reference operator[](size_type index) const noexcept
    {
        GHULBUS_PRECONDITION((index >= 0) && (index < m_n_elements));
        return m_ring[nth_index(index)];
    }

    reference front() noexcept
    {
        return m_ring[front_index()];
    }

    const_reference front() const noexcept
    {
        return m_ring[front_index()];
    }

    reference back() noexcept
    {
        return m_ring[m_push_idx - 1];
    }

    const_reference back() const noexcept
    {
        return m_ring[m_push_idx - 1];
    }

    inline friend bool operator==(FixedRing const& lhs, FixedRing const& rhs) noexcept
    {
        size_type const l_n = lhs.available();
        size_type const r_n = rhs.available();
        if (l_n != r_n) { return false; }
        for (size_type i = 0; i < l_n; ++i) {
            if (lhs.m_ring[lhs.nth_index(i)] != rhs.m_ring[rhs.nth_index(i)]) { return false; }
        }
        return true;
    }

    inline friend bool operator!=(FixedRing const& lhs, FixedRing const& rhs) noexcept
    {
        return !(lhs == rhs);
    }
};

}

#endif
<commit_msg>FixedRing now supports move insertion<commit_after>#ifndef GHULBUS_LIBRARY_INCLUDE_GUARD_BASE_FIXED_RING_HPP
#define GHULBUS_LIBRARY_INCLUDE_GUARD_BASE_FIXED_RING_HPP

/** @file
*
* @brief Fixed-size ring buffer.
* @author Andreas Weis (der_ghulbus@ghulbus-inc.de)
*/

#include <gbBase/config.hpp>
#include <gbBase/Assert.hpp>

#include <memory>
#include <vector>

namespace GHULBUS_BASE_NAMESPACE
{

template<typename T, class Allocator = std::allocator<T>>
class FixedRing {
public:
    using value_type = T;
    using allocator_type = Allocator;
    using size_type = typename std::vector<T>::size_type;
    using reference = value_type&;
    using const_reference = value_type const&;
private:
    std::vector<T, Allocator> m_ring;
    size_type m_push_idx;
    size_type m_n_elements;

    size_type front_index() const
    {
        size_type const end_idx = (m_push_idx < m_n_elements) ? (m_push_idx + m_ring.capacity()) : m_push_idx;
        return end_idx - m_n_elements;
    }

    size_type nth_index(size_type n) const
    {
        auto const offs = m_n_elements - n;
        return (m_push_idx < offs) ? (m_push_idx + m_ring.capacity() - offs) : (m_push_idx - offs);
    }
public:
    explicit FixedRing(size_type capacity, Allocator const& alloc = Allocator())
        :m_ring(alloc), m_push_idx(0), m_n_elements(0)
    {
        GHULBUS_PRECONDITION(capacity > 0);
        m_ring.reserve(capacity);
    }

    ~FixedRing() = default;
    FixedRing(FixedRing const&) = default;
    FixedRing& operator=(FixedRing const&) = default;
    FixedRing(FixedRing&&) = default;
    FixedRing& operator=(FixedRing&&) = default;

    /** Push an element to the back of the ring buffer.
     * \pre !full()
     */
    template<typename TT>
    void push_back(TT&& v)
    {
        GHULBUS_PRECONDITION(!full());
        if (m_ring.size() < m_ring.capacity()) {
            m_ring.push_back(std::forward<TT>(v));
            ++m_push_idx;
            ++m_n_elements;
            return;
        }
        if (m_push_idx == m_ring.capacity()) { m_push_idx = 0; }
        m_ring[m_push_idx++] = std::forward<TT>(v);
        ++m_n_elements;
    }

    /** Retrieve an element from the front of the ring buffer.
     * \pre !empty()
     */
    value_type pop_front()
    {
        GHULBUS_PRECONDITION(!empty());
        auto const front_idx = front_index();
        --m_n_elements;
        return std::move(m_ring[front_idx]);
    }

    /** Maximum number of elements that the ring buffer can hold at once.
     */
    size_type capacity() const noexcept
    {
        return m_ring.capacity();
    }

    /** Number of elements currently stored in the ring buffer.
     */
    size_type available() const noexcept
    {
        return m_n_elements;
    }

    /** Number of free slots available for storing additional elements in the ring buffer.
     */
    size_type free() const noexcept
    {
        return m_ring.capacity() - m_n_elements;
    }

    bool empty() const noexcept
    {
        return available() == 0;
    }

    bool full() const noexcept
    {
        return free() == 0;
    }

    reference operator[](size_type index) noexcept
    {
        GHULBUS_PRECONDITION((index >= 0) && (index < m_n_elements));
        return m_ring[nth_index(index)];
    }

    const_reference operator[](size_type index) const noexcept
    {
        GHULBUS_PRECONDITION((index >= 0) && (index < m_n_elements));
        return m_ring[nth_index(index)];
    }

    reference front() noexcept
    {
        return m_ring[front_index()];
    }

    const_reference front() const noexcept
    {
        return m_ring[front_index()];
    }

    reference back() noexcept
    {
        return m_ring[m_push_idx - 1];
    }

    const_reference back() const noexcept
    {
        return m_ring[m_push_idx - 1];
    }

    inline friend bool operator==(FixedRing const& lhs, FixedRing const& rhs) noexcept
    {
        size_type const l_n = lhs.available();
        size_type const r_n = rhs.available();
        if (l_n != r_n) { return false; }
        for (size_type i = 0; i < l_n; ++i) {
            if (lhs.m_ring[lhs.nth_index(i)] != rhs.m_ring[rhs.nth_index(i)]) { return false; }
        }
        return true;
    }

    inline friend bool operator!=(FixedRing const& lhs, FixedRing const& rhs) noexcept
    {
        return !(lhs == rhs);
    }
};

}

#endif
<|endoftext|>


<commit_before>#ifndef ARABICA_SOCKET_STREAM_H
#define ARABICA_SOCKET_STREAM_H
///////////////////////////////////////////////////////////////////////
//
// socket_stream.h
//
// Written by Jez Higgins <jez@jezuk.co.uk>
// Copyright 1999-2003 Jez UK Ltd, http://www.jezuk.co.uk/
//
///////////////////////////////////////////////////////////////////////
// $Id$
///////////////////////////////////////////////////////////////////////

#include <SAX/ArabicaConfig.hpp>
#ifndef ARABICA_USE_WINSOCK
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#else
#include <winsock.h>
#endif
#include <streambuf>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cstring>

#ifndef INADDR_NONE
#  define INADDR_NONE             ((in_addr_t) -1)
#endif

namespace Arabica
{
namespace io
{

///////////////////////////////////////////////////////////
// basic_socketbuf declaration
template<class charT, class traitsT>
class basic_socketbuf : public std::basic_streambuf<charT, traitsT>
{
  public:
    typedef typename traitsT::int_type int_type;

    using std::basic_streambuf<charT, traitsT>::setp;
    using std::basic_streambuf<charT, traitsT>::setg;
    using std::basic_streambuf<charT, traitsT>::underflow;
    using std::basic_streambuf<charT, traitsT>::gptr;
    using std::basic_streambuf<charT, traitsT>::gbump;
    using std::basic_streambuf<charT, traitsT>::egptr;
    using std::basic_streambuf<charT, traitsT>::eback;
    using std::basic_streambuf<charT, traitsT>::pptr;
    using std::basic_streambuf<charT, traitsT>::sputc;

    basic_socketbuf();
    virtual ~basic_socketbuf();

    bool is_open() const;

    basic_socketbuf<charT, traitsT>* open(const char* hostname, unsigned short port);
    basic_socketbuf<charT, traitsT>* close();

  protected:
    virtual int_type overflow(int_type c = traitsT::eof());
    virtual int sync();
    virtual int_type underflow();
    virtual int_type pbackfail(int_type c);

  private:
    typedef typename traitsT::state_type state_t;

    int sock_;
    std::vector<charT> outBuffer_;
    state_t outState_;
    std::vector<charT> inBuffer_;
    state_t inState_;

    void growOutBuffer();
    bool writeSocket();
    void growInBuffer();
    int readSocket();
    int closeSocket(int sock) const;

    static const size_t bufferSize_;
    static const size_t pbSize_;

#ifndef ARABICA_USE_WINSOCK
    static const int INVALID_SOCKET;
    static const int SOCKET_ERROR;
#endif
}; // class basic_socketbuf

template<class charT, class traitsT>
const size_t basic_socketbuf<charT, traitsT>::bufferSize_ = 1024;
template<class charT, class traitsT>
const size_t basic_socketbuf<charT, traitsT>::pbSize_ = 4;
  // why 4? both Josuttis and Langer&Kreft use 4.
#ifndef ARABICA_USE_WINSOCK
template<class charT, class traitsT>
const int basic_socketbuf<charT, traitsT>::INVALID_SOCKET = -1;
template<class charT, class traitsT>
const int basic_socketbuf<charT, traitsT>::SOCKET_ERROR = -1;
#endif

///////////////////////////////////////////////////////////
// basic_socketbuf definition
template<class charT, class traitsT>
basic_socketbuf<charT, traitsT>::basic_socketbuf()
     : std::basic_streambuf<charT, traitsT>(),
       sock_(INVALID_SOCKET),
       outBuffer_(0),
       inBuffer_(0)
{
//  outState_ = 0;
//  inState_ = 0;

  setp(0, 0);
  setg(0, 0, 0);
} // basic_socketbuf

template<class charT, class traitsT>
basic_socketbuf<charT,traitsT>::~basic_socketbuf()
{
  if(is_open())
  {
    sync();
    closeSocket(sock_);
  } // if(is_open())
} // ~basic_socketbuf

template<class charT, class traitsT>
bool basic_socketbuf<charT ,traitsT>::is_open() const
{
  return (sock_ != INVALID_SOCKET);
} // is_open

template<class charT, class traitsT>
basic_socketbuf<charT, traitsT>* basic_socketbuf<charT, traitsT>::open(const char* hostname,
                                                  unsigned short port)
{
  // already open? and crappy data
  if((sock_ != INVALID_SOCKET) ||
     (hostname == 0) ||
     (strlen(hostname) == 0))
      return 0;

  // set up address
  sockaddr_in sockAddr;
  memset(&sockAddr, 0, sizeof(sockAddr));

  sockAddr.sin_family = AF_INET;
  sockAddr.sin_addr.s_addr = inet_addr(hostname);
  if(sockAddr.sin_addr.s_addr == INADDR_NONE)
  {
    hostent* host = gethostbyname(hostname);
    if(!host)
      return 0;

    sockAddr.sin_addr.s_addr =
                       reinterpret_cast<in_addr*>(host->h_addr)->s_addr;
  } // if(sockAddr.sin_addr.s_addr == INADDR_NONE)
  sockAddr.sin_port = htons(port);

  // connect
  int tmpsock = socket(AF_INET, SOCK_STREAM, 0);
  if(tmpsock == INVALID_SOCKET)
    return 0;
  if(connect(tmpsock, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockaddr_in)) != 0)
  {
    closeSocket(tmpsock);
    return 0;
  }

  // hurray, we've connected so initialise everything else we need to
  sock_ = tmpsock;

  return this;
} // open

template<class charT, class traitsT>
basic_socketbuf<charT, traitsT>* basic_socketbuf<charT, traitsT>::close()
{
  if(!is_open())
    return 0;

  if(closeSocket(sock_) == SOCKET_ERROR)
    return 0;

  sock_ = INVALID_SOCKET;
  setg(0,0,0);

  return this;
} // close;

template<class charT, class traitsT>
typename basic_socketbuf<charT, traitsT>::int_type basic_socketbuf<charT, traitsT>::overflow(typename basic_socketbuf<charT, traitsT>::int_type c)
{
  if(traitsT::eq_int_type(traitsT::eof(), c))
    return traitsT::not_eof(c);
  if(!is_open())
    return traitsT::eof();

  growOutBuffer();
  sputc(traitsT::to_char_type(c));

  return traitsT::not_eof(c);
} // overflow

template<class charT, class traitsT>
int basic_socketbuf<charT, traitsT>::sync()
{
  return writeSocket() ? 0 : -1;
} // sync

template<class charT, class traitsT>
typename basic_socketbuf<charT, traitsT>::int_type basic_socketbuf<charT, traitsT>::underflow()
{
  if(!is_open())
    return traitsT::eof();
	if(gptr() != 0 && gptr() < egptr())
	  return (traitsT::to_int_type(*gptr()));

  size_t length = readSocket();
  if(!length)
    return traitsT::eof();

  return traitsT::to_int_type(*gptr());
} // underflow

template<class charT, class traitsT>
typename basic_socketbuf<charT, traitsT>::int_type basic_socketbuf<charT, traitsT>::pbackfail(int_type c)
{
  if(gptr() == eback())
    return traitsT::eof();

  gbump(-1);
  if(!traitsT::eq_int_type(c, traitsT::eof()))
    *(gptr()) = traitsT::to_char_type(c);
  return traitsT::not_eof(c);
} // pbackfail

template<class charT, class traitsT>
void basic_socketbuf<charT, traitsT>::growOutBuffer()
{
  size_t oldsize = outBuffer_.capacity();
  size_t newsize = (oldsize ? oldsize*2 : bufferSize_);
  outBuffer_.resize(newsize);

  char* out_begin = &(outBuffer_[0]);
  setp(out_begin + oldsize, out_begin + newsize);
} // growOutBuffer

template<class charT, class traitsT>
bool basic_socketbuf<charT, traitsT>::writeSocket()
{
  // write to the socket
  charT* from_next = &(outBuffer_[0]);
  size_t length = pptr() - from_next;
  if(!length)
    return true;

  bool ok = (send(sock_, from_next, length, 0) != SOCKET_ERROR);

  if(ok)
    setp(from_next, from_next + outBuffer_.capacity());

  return ok;
} // writeSocket

template<class charT, class traitsT>
void basic_socketbuf<charT, traitsT>::growInBuffer()
{
  size_t oldsize = inBuffer_.capacity();
  size_t newsize = (oldsize ? oldsize*2 : bufferSize_+pbSize_);
  inBuffer_.resize(newsize);
} // growInBuffer

template <class charT, class traitsT>
int basic_socketbuf<charT, traitsT>::readSocket()
{
  if(!inBuffer_.capacity())
    growInBuffer();

  size_t pbCount = std::min<int>(gptr() - eback(), pbSize_);

  memcpy(&(inBuffer_[0]) + (pbSize_-pbCount)*sizeof(charT),
         gptr() - pbCount*sizeof(charT),
         pbCount*sizeof(charT));

  int res = recv(sock_, &(inBuffer_[0]) + pbSize_, inBuffer_.capacity() - pbSize_, 0);
  if(res == 0)
  {
    // server closed the socket
    close();
    return 0;
  } // if(res == 0)
  else if(res == SOCKET_ERROR)
  {
#ifdef ARABICA_USE_WINSOCK
    if(GetLastError() == WSAEMSGSIZE)
    {
      // buffer was too small, so make it bigger
      growInBuffer();
      return readSocket();
    } // if(GetLastError() != WSAEMSGSIZE)
#endif

    // unclever error handling
    close();
    return 0;
  } // if(res == SOCKET_ERROR)

  charT* to_begin = &(inBuffer_[0]) + pbSize_;
  setg(to_begin - pbCount, to_begin, to_begin + res);

  return res;
} // readSocket

template <class charT, class traitsT>
int basic_socketbuf<charT, traitsT>::closeSocket(int sock) const
{
#ifdef ARABICA_USE_WINSOCK
  return closesocket(sock);
#else
  return ::close(sock);
#endif
} // closeSocket

///////////////////////////////////////////////////////////
// basic_socketstream declaration
template<class charT, class traitsT>
class socketstreambuf_init
{
public:
  typedef basic_socketbuf<charT, traitsT> sockbuf;

  sockbuf* buf() const
  {
    return &buf_;
  } // buf()

private:
  mutable sockbuf buf_;
}; // class socketstreambuf_init

template<class charT, class traitsT>
class basic_socketstream :
  private virtual socketstreambuf_init<charT, traitsT>,
  public std::basic_iostream<charT, traitsT>
{
  public:
    using std::basic_iostream<charT, traitsT>::setstate;
    using std::basic_iostream<charT, traitsT>::badbit;

    basic_socketstream();
    explicit basic_socketstream(const char* hostname, int port);

    virtual ~basic_socketstream();

    basic_socketbuf<charT,traitsT>* rdbuf() const;
    bool is_open() const;
    void open(const char* hostname, unsigned short port);
    void close();
}; // class basic_socketstream

////////////////////////////////////////////////////////////////
// basic_socketstream definition
template<class charT, class traitsT>
basic_socketstream<charT, traitsT>::basic_socketstream() :
    socketstreambuf_init<charT, traitsT>(),
    std::basic_iostream<charT, traitsT>(socketstreambuf_init<charT, traitsT>::buf())
{
} // basic_socketstream

template<class charT, class traitsT>
basic_socketstream<charT, traitsT>::basic_socketstream(const char* hostname, int port) :
    socketstreambuf_init<charT, traitsT>(),
    std::basic_iostream<charT, traitsT>(socketstreambuf_init<charT, traitsT>::buf())
{
  open(hostname, port);
} // basic_socketstream

template<class charT, class traitsT>
basic_socketstream<charT, traitsT>::~basic_socketstream()
{
} // ~basic_socketstream

template<class charT, class traitsT>
basic_socketbuf<charT, traitsT>* basic_socketstream<charT, traitsT>::rdbuf() const
{
  return socketstreambuf_init<charT, traitsT>::buf();
} // rdbuf

template<class charT, class traitsT>
bool basic_socketstream<charT, traitsT>::is_open() const
{
  return socketstreambuf_init<charT, traitsT>::buf()->is_open();
} // is_open

template<class charT, class traitsT>
void basic_socketstream<charT, traitsT>::open(const char* hostname, unsigned short port)
{
  if(socketstreambuf_init<charT, traitsT>::buf()->open(hostname, port) == 0)
    setstate(badbit);
} // open

template<class charT, class traitsT>
void basic_socketstream<charT, traitsT>::close()
{
  if(!is_open())
    return;

  if(socketstreambuf_init<charT, traitsT>::buf()->close() == 0)
    setstate(badbit);
} // close

typedef basic_socketbuf<char, std::char_traits<char> > socketbuf;
typedef basic_socketstream<char, std::char_traits<char> > socketstream;
#ifndef ARABICA_NO_WSTRING_T
typedef basic_socketbuf<wchar_t, std::char_traits<wchar_t> > wsocketbuf;
typedef basic_socketstream<wchar_t, std::char_traits<wchar_t> > wsocketstream;
#endif

} // namespace io
} // namespace Arabica

#endif
//end of file
<commit_msg>Silence a new VS2012 warning<commit_after>#ifndef ARABICA_SOCKET_STREAM_H
#define ARABICA_SOCKET_STREAM_H
///////////////////////////////////////////////////////////////////////
//
// socket_stream.h
//
// Written by Jez Higgins <jez@jezuk.co.uk>
// Copyright 1999-2003 Jez UK Ltd, http://www.jezuk.co.uk/
//
///////////////////////////////////////////////////////////////////////
// $Id$
///////////////////////////////////////////////////////////////////////

#include <SAX/ArabicaConfig.hpp>
#ifndef ARABICA_USE_WINSOCK
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#else
#include <winsock.h>
#endif
#include <streambuf>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cstring>

#ifndef INADDR_NONE
#  define INADDR_NONE             ((in_addr_t) -1)
#endif

#ifdef _MSC_VER
#pragma warning(disable: 4250)
// See http://connect.microsoft.com/VisualStudio/feedback/details/733720/inheriting-from-std-fstream-produces-c4250-warning
#endif
namespace Arabica
{
namespace io
{

///////////////////////////////////////////////////////////
// basic_socketbuf declaration
template<class charT, class traitsT>
class basic_socketbuf : public std::basic_streambuf<charT, traitsT>
{
  public:
    typedef typename traitsT::int_type int_type;

    using std::basic_streambuf<charT, traitsT>::setp;
    using std::basic_streambuf<charT, traitsT>::setg;
    using std::basic_streambuf<charT, traitsT>::underflow;
    using std::basic_streambuf<charT, traitsT>::gptr;
    using std::basic_streambuf<charT, traitsT>::gbump;
    using std::basic_streambuf<charT, traitsT>::egptr;
    using std::basic_streambuf<charT, traitsT>::eback;
    using std::basic_streambuf<charT, traitsT>::pptr;
    using std::basic_streambuf<charT, traitsT>::sputc;

    basic_socketbuf();
    virtual ~basic_socketbuf();

    bool is_open() const;

    basic_socketbuf<charT, traitsT>* open(const char* hostname, unsigned short port);
    basic_socketbuf<charT, traitsT>* close();

  protected:
    virtual int_type overflow(int_type c = traitsT::eof());
    virtual int sync();
    virtual int_type underflow();
    virtual int_type pbackfail(int_type c);

  private:
    typedef typename traitsT::state_type state_t;

    int sock_;
    std::vector<charT> outBuffer_;
    state_t outState_;
    std::vector<charT> inBuffer_;
    state_t inState_;

    void growOutBuffer();
    bool writeSocket();
    void growInBuffer();
    int readSocket();
    int closeSocket(int sock) const;

    static const size_t bufferSize_;
    static const size_t pbSize_;

#ifndef ARABICA_USE_WINSOCK
    static const int INVALID_SOCKET;
    static const int SOCKET_ERROR;
#endif
}; // class basic_socketbuf

template<class charT, class traitsT>
const size_t basic_socketbuf<charT, traitsT>::bufferSize_ = 1024;
template<class charT, class traitsT>
const size_t basic_socketbuf<charT, traitsT>::pbSize_ = 4;
  // why 4? both Josuttis and Langer&Kreft use 4.
#ifndef ARABICA_USE_WINSOCK
template<class charT, class traitsT>
const int basic_socketbuf<charT, traitsT>::INVALID_SOCKET = -1;
template<class charT, class traitsT>
const int basic_socketbuf<charT, traitsT>::SOCKET_ERROR = -1;
#endif

///////////////////////////////////////////////////////////
// basic_socketbuf definition
template<class charT, class traitsT>
basic_socketbuf<charT, traitsT>::basic_socketbuf()
     : std::basic_streambuf<charT, traitsT>(),
       sock_(INVALID_SOCKET),
       outBuffer_(0),
       inBuffer_(0)
{
//  outState_ = 0;
//  inState_ = 0;

  setp(0, 0);
  setg(0, 0, 0);
} // basic_socketbuf

template<class charT, class traitsT>
basic_socketbuf<charT,traitsT>::~basic_socketbuf()
{
  if(is_open())
  {
    sync();
    closeSocket(sock_);
  } // if(is_open())
} // ~basic_socketbuf

template<class charT, class traitsT>
bool basic_socketbuf<charT ,traitsT>::is_open() const
{
  return (sock_ != INVALID_SOCKET);
} // is_open

template<class charT, class traitsT>
basic_socketbuf<charT, traitsT>* basic_socketbuf<charT, traitsT>::open(const char* hostname,
                                                  unsigned short port)
{
  // already open? and crappy data
  if((sock_ != INVALID_SOCKET) ||
     (hostname == 0) ||
     (strlen(hostname) == 0))
      return 0;

  // set up address
  sockaddr_in sockAddr;
  memset(&sockAddr, 0, sizeof(sockAddr));

  sockAddr.sin_family = AF_INET;
  sockAddr.sin_addr.s_addr = inet_addr(hostname);
  if(sockAddr.sin_addr.s_addr == INADDR_NONE)
  {
    hostent* host = gethostbyname(hostname);
    if(!host)
      return 0;

    sockAddr.sin_addr.s_addr =
                       reinterpret_cast<in_addr*>(host->h_addr)->s_addr;
  } // if(sockAddr.sin_addr.s_addr == INADDR_NONE)
  sockAddr.sin_port = htons(port);

  // connect
  int tmpsock = socket(AF_INET, SOCK_STREAM, 0);
  if(tmpsock == INVALID_SOCKET)
    return 0;
  if(connect(tmpsock, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockaddr_in)) != 0)
  {
    closeSocket(tmpsock);
    return 0;
  }

  // hurray, we've connected so initialise everything else we need to
  sock_ = tmpsock;

  return this;
} // open

template<class charT, class traitsT>
basic_socketbuf<charT, traitsT>* basic_socketbuf<charT, traitsT>::close()
{
  if(!is_open())
    return 0;

  if(closeSocket(sock_) == SOCKET_ERROR)
    return 0;

  sock_ = INVALID_SOCKET;
  setg(0,0,0);

  return this;
} // close;

template<class charT, class traitsT>
typename basic_socketbuf<charT, traitsT>::int_type basic_socketbuf<charT, traitsT>::overflow(typename basic_socketbuf<charT, traitsT>::int_type c)
{
  if(traitsT::eq_int_type(traitsT::eof(), c))
    return traitsT::not_eof(c);
  if(!is_open())
    return traitsT::eof();

  growOutBuffer();
  sputc(traitsT::to_char_type(c));

  return traitsT::not_eof(c);
} // overflow

template<class charT, class traitsT>
int basic_socketbuf<charT, traitsT>::sync()
{
  return writeSocket() ? 0 : -1;
} // sync

template<class charT, class traitsT>
typename basic_socketbuf<charT, traitsT>::int_type basic_socketbuf<charT, traitsT>::underflow()
{
  if(!is_open())
    return traitsT::eof();
	if(gptr() != 0 && gptr() < egptr())
	  return (traitsT::to_int_type(*gptr()));

  size_t length = readSocket();
  if(!length)
    return traitsT::eof();

  return traitsT::to_int_type(*gptr());
} // underflow

template<class charT, class traitsT>
typename basic_socketbuf<charT, traitsT>::int_type basic_socketbuf<charT, traitsT>::pbackfail(int_type c)
{
  if(gptr() == eback())
    return traitsT::eof();

  gbump(-1);
  if(!traitsT::eq_int_type(c, traitsT::eof()))
    *(gptr()) = traitsT::to_char_type(c);
  return traitsT::not_eof(c);
} // pbackfail

template<class charT, class traitsT>
void basic_socketbuf<charT, traitsT>::growOutBuffer()
{
  size_t oldsize = outBuffer_.capacity();
  size_t newsize = (oldsize ? oldsize*2 : bufferSize_);
  outBuffer_.resize(newsize);

  char* out_begin = &(outBuffer_[0]);
  setp(out_begin + oldsize, out_begin + newsize);
} // growOutBuffer

template<class charT, class traitsT>
bool basic_socketbuf<charT, traitsT>::writeSocket()
{
  // write to the socket
  charT* from_next = &(outBuffer_[0]);
  size_t length = pptr() - from_next;
  if(!length)
    return true;

  bool ok = (send(sock_, from_next, length, 0) != SOCKET_ERROR);

  if(ok)
    setp(from_next, from_next + outBuffer_.capacity());

  return ok;
} // writeSocket

template<class charT, class traitsT>
void basic_socketbuf<charT, traitsT>::growInBuffer()
{
  size_t oldsize = inBuffer_.capacity();
  size_t newsize = (oldsize ? oldsize*2 : bufferSize_+pbSize_);
  inBuffer_.resize(newsize);
} // growInBuffer

template <class charT, class traitsT>
int basic_socketbuf<charT, traitsT>::readSocket()
{
  if(!inBuffer_.capacity())
    growInBuffer();

  size_t pbCount = std::min<int>(gptr() - eback(), pbSize_);

  memcpy(&(inBuffer_[0]) + (pbSize_-pbCount)*sizeof(charT),
         gptr() - pbCount*sizeof(charT),
         pbCount*sizeof(charT));

  int res = recv(sock_, &(inBuffer_[0]) + pbSize_, inBuffer_.capacity() - pbSize_, 0);
  if(res == 0)
  {
    // server closed the socket
    close();
    return 0;
  } // if(res == 0)
  else if(res == SOCKET_ERROR)
  {
#ifdef ARABICA_USE_WINSOCK
    if(GetLastError() == WSAEMSGSIZE)
    {
      // buffer was too small, so make it bigger
      growInBuffer();
      return readSocket();
    } // if(GetLastError() != WSAEMSGSIZE)
#endif

    // unclever error handling
    close();
    return 0;
  } // if(res == SOCKET_ERROR)

  charT* to_begin = &(inBuffer_[0]) + pbSize_;
  setg(to_begin - pbCount, to_begin, to_begin + res);

  return res;
} // readSocket

template <class charT, class traitsT>
int basic_socketbuf<charT, traitsT>::closeSocket(int sock) const
{
#ifdef ARABICA_USE_WINSOCK
  return closesocket(sock);
#else
  return ::close(sock);
#endif
} // closeSocket

///////////////////////////////////////////////////////////
// basic_socketstream declaration
template<class charT, class traitsT>
class socketstreambuf_init
{
public:
  typedef basic_socketbuf<charT, traitsT> sockbuf;

  sockbuf* buf() const
  {
    return &buf_;
  } // buf()

private:
  mutable sockbuf buf_;
}; // class socketstreambuf_init

template<class charT, class traitsT>
class basic_socketstream :
  private virtual socketstreambuf_init<charT, traitsT>,
  public std::basic_iostream<charT, traitsT>
{
  public:
    using std::basic_iostream<charT, traitsT>::setstate;
    using std::basic_iostream<charT, traitsT>::badbit;

    basic_socketstream();
    explicit basic_socketstream(const char* hostname, int port);

    virtual ~basic_socketstream();

    basic_socketbuf<charT,traitsT>* rdbuf() const;
    bool is_open() const;
    void open(const char* hostname, unsigned short port);
    void close();
}; // class basic_socketstream

////////////////////////////////////////////////////////////////
// basic_socketstream definition
template<class charT, class traitsT>
basic_socketstream<charT, traitsT>::basic_socketstream() :
    socketstreambuf_init<charT, traitsT>(),
    std::basic_iostream<charT, traitsT>(socketstreambuf_init<charT, traitsT>::buf())
{
} // basic_socketstream

template<class charT, class traitsT>
basic_socketstream<charT, traitsT>::basic_socketstream(const char* hostname, int port) :
    socketstreambuf_init<charT, traitsT>(),
    std::basic_iostream<charT, traitsT>(socketstreambuf_init<charT, traitsT>::buf())
{
  open(hostname, port);
} // basic_socketstream

template<class charT, class traitsT>
basic_socketstream<charT, traitsT>::~basic_socketstream()
{
} // ~basic_socketstream

template<class charT, class traitsT>
basic_socketbuf<charT, traitsT>* basic_socketstream<charT, traitsT>::rdbuf() const
{
  return socketstreambuf_init<charT, traitsT>::buf();
} // rdbuf

template<class charT, class traitsT>
bool basic_socketstream<charT, traitsT>::is_open() const
{
  return socketstreambuf_init<charT, traitsT>::buf()->is_open();
} // is_open

template<class charT, class traitsT>
void basic_socketstream<charT, traitsT>::open(const char* hostname, unsigned short port)
{
  if(socketstreambuf_init<charT, traitsT>::buf()->open(hostname, port) == 0)
    setstate(badbit);
} // open

template<class charT, class traitsT>
void basic_socketstream<charT, traitsT>::close()
{
  if(!is_open())
    return;

  if(socketstreambuf_init<charT, traitsT>::buf()->close() == 0)
    setstate(badbit);
} // close

typedef basic_socketbuf<char, std::char_traits<char> > socketbuf;
typedef basic_socketstream<char, std::char_traits<char> > socketstream;
#ifndef ARABICA_NO_WSTRING_T
typedef basic_socketbuf<wchar_t, std::char_traits<wchar_t> > wsocketbuf;
typedef basic_socketstream<wchar_t, std::char_traits<wchar_t> > wsocketstream;
#endif

} // namespace io
} // namespace Arabica

#endif
//end of file
<|endoftext|>