<commit_before>/*************************************************************************/
/*  lightmap_raycaster.cpp                                               */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#ifdef TOOLS_ENABLED

#include "lightmap_raycaster.h"

#include <pmmintrin.h>

LightmapRaycaster *LightmapRaycasterEmbree::create_embree_raycaster() {
	return memnew(LightmapRaycasterEmbree);
}

void LightmapRaycasterEmbree::make_default_raycaster() {
	create_function = create_embree_raycaster;
}

void LightmapRaycasterEmbree::filter_function(const struct RTCFilterFunctionNArguments *p_args) {
	RTCHit *hit = (RTCHit *)p_args->hit;

	unsigned int geomID = hit->geomID;
	float u = hit->u;
	float v = hit->v;

	LightmapRaycasterEmbree *scene = (LightmapRaycasterEmbree *)p_args->geometryUserPtr;
	RTCGeometry geom = rtcGetGeometry(scene->embree_scene, geomID);

	rtcInterpolate0(geom, hit->primID, hit->u, hit->v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, &hit->u, 2);

	if (scene->alpha_textures.has(geomID)) {
		const AlphaTextureData &alpha_texture = scene->alpha_textures[geomID];

		if (alpha_texture.sample(hit->u, hit->v) < 128) {
			p_args->valid[0] = 0;
			return;
		}
	}

	rtcInterpolate0(geom, hit->primID, u, v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, &hit->Ng_x, 3);
}

bool LightmapRaycasterEmbree::intersect(Ray &r_ray) {
	RTCIntersectContext context;

	rtcInitIntersectContext(&context);

	rtcIntersect1(embree_scene, &context, (RTCRayHit *)&r_ray);
	return r_ray.geomID != RTC_INVALID_GEOMETRY_ID;
}

void LightmapRaycasterEmbree::intersect(Vector<Ray> &r_rays) {
	Ray *rays = r_rays.ptrw();
	for (int i = 0; i < r_rays.size(); ++i) {
		intersect(rays[i]);
	}
}

void LightmapRaycasterEmbree::set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) {
	if (p_alpha_texture.is_valid() && p_alpha_texture->get_size() != Vector2i()) {
		AlphaTextureData tex;
		tex.size = p_alpha_texture->get_size();
		tex.data = p_alpha_texture->get_data();
		alpha_textures.insert(p_id, tex);
	}
}

float blerp(float c00, float c10, float c01, float c11, float tx, float ty) {
	return Math::lerp(Math::lerp(c00, c10, tx), Math::lerp(c01, c11, tx), ty);
}

uint8_t LightmapRaycasterEmbree::AlphaTextureData::sample(float u, float v) const {
	float x = u * size.x;
	float y = v * size.y;
	int xi = (int)x;
	int yi = (int)y;

	uint8_t texels[4];

	for (int i = 0; i < 4; ++i) {
		int sample_x = CLAMP(xi + i % 2, 0, size.x - 1);
		int sample_y = CLAMP(yi + i / 2, 0, size.y - 1);
		texels[i] = data[sample_y * size.x + sample_x];
	}

	return Math::round(blerp(texels[0], texels[1], texels[2], texels[3], x - xi, y - yi));
}

void LightmapRaycasterEmbree::add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) {
	RTCGeometry embree_mesh = rtcNewGeometry(embree_device, RTC_GEOMETRY_TYPE_TRIANGLE);

	rtcSetGeometryVertexAttributeCount(embree_mesh, 2);

	int vertex_count = p_vertices.size();

	ERR_FAIL_COND(vertex_count % 3 != 0);
	ERR_FAIL_COND(vertex_count != p_uv2s.size());
	ERR_FAIL_COND(!p_normals.is_empty() && vertex_count != p_normals.size());

	Vector3 *embree_vertices = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
	memcpy(embree_vertices, p_vertices.ptr(), sizeof(Vector3) * vertex_count);

	Vector2 *embree_light_uvs = (Vector2 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, RTC_FORMAT_FLOAT2, sizeof(Vector2), vertex_count);
	memcpy(embree_light_uvs, p_uv2s.ptr(), sizeof(Vector2) * vertex_count);

	uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, vertex_count / 3);
	for (int i = 0; i < vertex_count; i++) {
		embree_triangles[i] = i;
	}

	if (!p_normals.is_empty()) {
		Vector3 *embree_normals = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
		memcpy(embree_normals, p_normals.ptr(), sizeof(Vector3) * vertex_count);
	}

	rtcCommitGeometry(embree_mesh);
	rtcSetGeometryIntersectFilterFunction(embree_mesh, filter_function);
	rtcSetGeometryUserData(embree_mesh, this);
	rtcAttachGeometryByID(embree_scene, embree_mesh, p_id);
	rtcReleaseGeometry(embree_mesh);
}

void LightmapRaycasterEmbree::commit() {
	rtcCommitScene(embree_scene);
}

void LightmapRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) {
	for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
		rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
	}
	rtcCommitScene(embree_scene);
	filter_meshes = p_mesh_ids;
}

void LightmapRaycasterEmbree::clear_mesh_filter() {
	for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
		rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
	}
	rtcCommitScene(embree_scene);
	filter_meshes.clear();
}

void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str) {
	print_error("Embree error: " + String(p_str));
}

LightmapRaycasterEmbree::LightmapRaycasterEmbree() {
	_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
	_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);

	embree_device = rtcNewDevice(nullptr);
	rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr);
	embree_scene = rtcNewScene(embree_device);
}

LightmapRaycasterEmbree::~LightmapRaycasterEmbree() {
	_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
	_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);

	if (embree_scene != nullptr) {
		rtcReleaseScene(embree_scene);
	}

	if (embree_device != nullptr) {
		rtcReleaseDevice(embree_device);
	}
}

#endif
<commit_msg>Add checks for __SSE2__ in the lightmap raycaster<commit_after>/*************************************************************************/
/*  lightmap_raycaster.cpp                                               */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#ifdef TOOLS_ENABLED

#include "lightmap_raycaster.h"

#ifdef __SSE2__
#include <pmmintrin.h>
#endif

LightmapRaycaster *LightmapRaycasterEmbree::create_embree_raycaster() {
	return memnew(LightmapRaycasterEmbree);
}

void LightmapRaycasterEmbree::make_default_raycaster() {
	create_function = create_embree_raycaster;
}

void LightmapRaycasterEmbree::filter_function(const struct RTCFilterFunctionNArguments *p_args) {
	RTCHit *hit = (RTCHit *)p_args->hit;

	unsigned int geomID = hit->geomID;
	float u = hit->u;
	float v = hit->v;

	LightmapRaycasterEmbree *scene = (LightmapRaycasterEmbree *)p_args->geometryUserPtr;
	RTCGeometry geom = rtcGetGeometry(scene->embree_scene, geomID);

	rtcInterpolate0(geom, hit->primID, hit->u, hit->v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, &hit->u, 2);

	if (scene->alpha_textures.has(geomID)) {
		const AlphaTextureData &alpha_texture = scene->alpha_textures[geomID];

		if (alpha_texture.sample(hit->u, hit->v) < 128) {
			p_args->valid[0] = 0;
			return;
		}
	}

	rtcInterpolate0(geom, hit->primID, u, v, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, &hit->Ng_x, 3);
}

bool LightmapRaycasterEmbree::intersect(Ray &r_ray) {
	RTCIntersectContext context;

	rtcInitIntersectContext(&context);

	rtcIntersect1(embree_scene, &context, (RTCRayHit *)&r_ray);
	return r_ray.geomID != RTC_INVALID_GEOMETRY_ID;
}

void LightmapRaycasterEmbree::intersect(Vector<Ray> &r_rays) {
	Ray *rays = r_rays.ptrw();
	for (int i = 0; i < r_rays.size(); ++i) {
		intersect(rays[i]);
	}
}

void LightmapRaycasterEmbree::set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) {
	if (p_alpha_texture.is_valid() && p_alpha_texture->get_size() != Vector2i()) {
		AlphaTextureData tex;
		tex.size = p_alpha_texture->get_size();
		tex.data = p_alpha_texture->get_data();
		alpha_textures.insert(p_id, tex);
	}
}

float blerp(float c00, float c10, float c01, float c11, float tx, float ty) {
	return Math::lerp(Math::lerp(c00, c10, tx), Math::lerp(c01, c11, tx), ty);
}

uint8_t LightmapRaycasterEmbree::AlphaTextureData::sample(float u, float v) const {
	float x = u * size.x;
	float y = v * size.y;
	int xi = (int)x;
	int yi = (int)y;

	uint8_t texels[4];

	for (int i = 0; i < 4; ++i) {
		int sample_x = CLAMP(xi + i % 2, 0, size.x - 1);
		int sample_y = CLAMP(yi + i / 2, 0, size.y - 1);
		texels[i] = data[sample_y * size.x + sample_x];
	}

	return Math::round(blerp(texels[0], texels[1], texels[2], texels[3], x - xi, y - yi));
}

void LightmapRaycasterEmbree::add_mesh(const Vector<Vector3> &p_vertices, const Vector<Vector3> &p_normals, const Vector<Vector2> &p_uv2s, unsigned int p_id) {
	RTCGeometry embree_mesh = rtcNewGeometry(embree_device, RTC_GEOMETRY_TYPE_TRIANGLE);

	rtcSetGeometryVertexAttributeCount(embree_mesh, 2);

	int vertex_count = p_vertices.size();

	ERR_FAIL_COND(vertex_count % 3 != 0);
	ERR_FAIL_COND(vertex_count != p_uv2s.size());
	ERR_FAIL_COND(!p_normals.is_empty() && vertex_count != p_normals.size());

	Vector3 *embree_vertices = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
	memcpy(embree_vertices, p_vertices.ptr(), sizeof(Vector3) * vertex_count);

	Vector2 *embree_light_uvs = (Vector2 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, RTC_FORMAT_FLOAT2, sizeof(Vector2), vertex_count);
	memcpy(embree_light_uvs, p_uv2s.ptr(), sizeof(Vector2) * vertex_count);

	uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, vertex_count / 3);
	for (int i = 0; i < vertex_count; i++) {
		embree_triangles[i] = i;
	}

	if (!p_normals.is_empty()) {
		Vector3 *embree_normals = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
		memcpy(embree_normals, p_normals.ptr(), sizeof(Vector3) * vertex_count);
	}

	rtcCommitGeometry(embree_mesh);
	rtcSetGeometryIntersectFilterFunction(embree_mesh, filter_function);
	rtcSetGeometryUserData(embree_mesh, this);
	rtcAttachGeometryByID(embree_scene, embree_mesh, p_id);
	rtcReleaseGeometry(embree_mesh);
}

void LightmapRaycasterEmbree::commit() {
	rtcCommitScene(embree_scene);
}

void LightmapRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) {
	for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
		rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
	}
	rtcCommitScene(embree_scene);
	filter_meshes = p_mesh_ids;
}

void LightmapRaycasterEmbree::clear_mesh_filter() {
	for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
		rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
	}
	rtcCommitScene(embree_scene);
	filter_meshes.clear();
}

void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str) {
	print_error("Embree error: " + String(p_str));
}

LightmapRaycasterEmbree::LightmapRaycasterEmbree() {
#ifdef __SSE2__
	_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
	_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
#endif

	embree_device = rtcNewDevice(nullptr);
	rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr);
	embree_scene = rtcNewScene(embree_device);
}

LightmapRaycasterEmbree::~LightmapRaycasterEmbree() {
#ifdef __SSE2__
	_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
	_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
#endif

	if (embree_scene != nullptr) {
		rtcReleaseScene(embree_scene);
	}

	if (embree_device != nullptr) {
		rtcReleaseDevice(embree_device);
	}
}

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: randomwipe.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 20:57:04 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#if ! defined INCLUDED_SLIDESHOW_RANDOMWIPE_HXX
#define INCLUDED_SLIDESHOW_RANDOMWIPE_HXX

#include "parametricpolypolygon.hxx"
#include "transitiontools.hxx"
#include "basegfx/polygon/b2dpolygon.hxx"
#include "basegfx/point/b2dpoint.hxx"
#include "boost/scoped_array.hpp"

namespace presentation {
namespace internal {

class RandomWipe : public ParametricPolyPolygon
{
public:
    RandomWipe( sal_Int32 nElements,
                bool randomBars /* true: generates a horizontal random bar wipe,
                                   false: generates a dissolve wipe */ );
    virtual ::basegfx::B2DPolyPolygon operator () ( double t );
private:
    ::boost::scoped_array< ::basegfx::B2DPoint > m_positions;
    sal_Int32 m_nElements;
    ::basegfx::B2DPolygon m_rect;
};

}
}

#endif /* INCLUDED_SLIDESHOW_RANDOMWIPE_HXX */
<commit_msg>INTEGRATION: CWS presfixes09 (1.3.18); FILE MERGED 2006/04/24 13:25:33 thb 1.3.18.2: #i53194# Unified include statements (local headers always have double quotes; external headers angle brackets); reverted EventMultiplexer pause events to shared_ptr; removed EventMultiplexer::removeViewHandler(), since the handler is held weakly, anyway. 2006/03/24 18:23:25 thb 1.3.18.1: #i37778# Moved whole slideshow engine from namespace presentation (which conflicts with one of the UNO subnamespaces) to slideshow<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: randomwipe.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-13 15:44:49 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#if ! defined INCLUDED_SLIDESHOW_RANDOMWIPE_HXX
#define INCLUDED_SLIDESHOW_RANDOMWIPE_HXX

#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <boost/scoped_array.hpp>

#include "parametricpolypolygon.hxx"
#include "transitiontools.hxx"

namespace slideshow {
namespace internal {

class RandomWipe : public ParametricPolyPolygon
{
public:
    RandomWipe( sal_Int32 nElements,
                bool randomBars /* true: generates a horizontal random bar wipe,
                                   false: generates a dissolve wipe */ );
    virtual ::basegfx::B2DPolyPolygon operator () ( double t );
private:
    ::boost::scoped_array< ::basegfx::B2DPoint > m_positions;
    sal_Int32 m_nElements;
    ::basegfx::B2DPolygon m_rect;
};

}
}

#endif /* INCLUDED_SLIDESHOW_RANDOMWIPE_HXX */
<|endoftext|>


<commit_before><commit_msg>Update GeneralServerFeature.cpp<commit_after><|endoftext|>


<commit_before>
/**
 * 所有 #include <外部文件> 的头文件 都必须保证 本文件被首先#include
 * 以下项目可以由本文件保证包含：
 * 	<cstdint>
 * 	<cstddef>
 * 	并保证 全局名称空间包含所有stdint。
 * 	CS_DEBUG = 1 时保证 #include <iostream>
 */

#pragma once

/**
 * 平台兼容原则：以不大的代价换取一定的兼容性；以首要目标平台0-overhead为前提。
 */

#ifndef NDEBUG
#	ifndef CS_DEBUG
#   	define CS_DEBUG		2
#	endif
#	ifndef CS_LOG_ON
#		define CS_LOG_ON	1
#	endif
#else
#	undef CS_DEBUG
#	define CS_DEBUG			0
#	undef CS_LOG_ON
#	define CS_LOG_ON		0
#endif

#if ! CS_DEBUG
#ifndef NDEBUG
#	define NDEBUG
#endif
#	define BOOST_DISABLE_ASSERTS
#endif

#if defined(__cplusplus) && __cplusplus >= 201103L
#   define CS_CPP11 1
#else
#   define CS_CPP11 0

// Use wchar_t/wstring wcout/wcerr/wcin wfstream or not.
// It's just a standard, not make used in this file.
#ifndef CS_USE_WCS
#	define CS_USE_WCS	0
#endif
// Use wcout/wcerr/wcin or not. This will make use in this file.
#ifndef CS_USE_WIO
#	define CS_USE_WIO	0
#endif

#if defined(CS_USE_WCS) && CS_USE_WCS
#	define CS_STR_LITER(str_liter)		L##str_liter
#else
#	define CS_STR_LITER(str_liter)		#str_liter
#endif

#ifndef __GNUC__
#   define __attribute__(...)
#endif

#ifdef __cplusplus
// avoid from boost if possible.
#	if defined(__GNUC__)	\
		&& (!defined(__GXX_EXPERIMENTAL_CXX0X__) || !__GXX_EXPERIMENTAL_CXX0X__)
#		include <boost/cstdint.hpp>
#	else
#		include <cstdint>
#	endif
#	include <cstddef>
#else
#	include <stdint.h>
#	include <stddef.h>
#endif

#define CS_EXIT_STATUS_FAILED EXIT_FAILURE

#ifdef __cplusplus
#	define CS_PREF_STD(symbol)		::std::symbol
#else
#	define CS_PREF_STD(symbol)		symbol
#endif

#if CS_USE_WIO
#	define CS_STDIN		::std::wcin
#	define CS_STDOUT	::std::wcout
#	define CS_STDERR	::std::wcerr
#else
#	define CS_STDIN		::std::cin
#	define CS_STDOUT	::std::cout
#	define CS_STDERR	::std::cerr
#endif

#ifdef __linux__
#   define CS_OC_BLACK(...) "\033[32;30;5m" << __VA_ARGS__ << "\033[0m"
#   define CS_OC_BLUE(...)  "\033[32;34;5m" << __VA_ARGS__ << "\033[0m"
#   define CS_OC_RED(...)   "\033[32;31;5m" << __VA_ARGS__ << "\033[0m"
#   define CS_OC_GREEN(...) "\033[32;49;5m" << __VA_ARGS__ << "\033[0m"
#else
#   define CS_OC_BLACK(...) __VA_ARGS__
#   define CS_OC_BLUE(...)  __VA_ARGS__
#   define CS_OC_RED(...)   __VA_ARGS__
#   define CS_OC_GREEN(...) __VA_ARGS__
#endif

// line-seperator, should only use for IO..
#ifdef __linux__
#	define CS_LINESEP		'\n'
#	define CS_LINESEP_STR	"\n"
#else
#	ifdef(__WIN32__)
#		define CS_LINESEP		"\r\n"
#		define CS_LINESEP_STR	CS_LINESEP
#	else
#		define CS_LINESEP		::std::endl
#		define CS_LINESEP_STR	::std::endl()
#	endif
#endif

#if CS_DEBUG
#   define CS_DEBUG_OMIT(...)
#   include <iostream>
#   if CS_DEBUG > 1
#		if CS_USE_WCS
#			define CS_OUT(ostream, ...)											\
				do {															\
				ostream << __FILE__ << ":" << __LINE__							\
					<< ":" << __FUNCTION__ << "()" << ":\t"						\
					<< __VA_ARGS__												\
					<< ::std::endl;												\
				} while(false);
#		else
#       	define CS_OUT(ostream, ...)											\
				do {															\
				ostream << CS_OC_BLACK(__FILE__ << ":" << __LINE__)				\
					<< ":" << CS_OC_BLUE(__FUNCTION__ << "()") << ":\t"			\
					<< CS_OC_GREEN(__VA_ARGS__)									\
					<< ::std::endl;												\
				} while(false);
#		endif
#   else
#		define CS_OUT(ostream, ...)	do {ostream << __VA_ARGS__ << ::std::endl;} while(false);
#   endif
#else
#   define CS_DEBUG_OMIT(...)    __VA_ARGS__
#	define CS_OUT(ostream, ...)
#endif

#define CS_SAY(...)		CS_OUT(CS_STDOUT, __VA_ARGS__)

// NOTE: 要自行 #include <iostream>
#define CS_ECHO(...)	CS_STDOUT << __VA_ARGS__ << ::std::endl;
#define CS_ERR(...)		CS_STDERR << __VA_ARGS__ << ::std::endl;

// #define CS_DUMP(...)	CS_OUT(CS_STDOUT, GOL_OC_BLUE(#__VA_ARGS__) << ": " << GOL_OC_GREEN(__VA_ARGS__))

#define CS_DUMP(...)																	\
	CS_OUT(CS_STDOUT, CS_OC_RED(#__VA_ARGS__) << ":[" << CS_OC_GREEN(__VA_ARGS__) << "]")
#define CS_DUMP_N(...) 																	\
	CS_OUT(CS_STDOUT, CS_OC_RED(#__VA_ARGS__) << ":" << ::std::endl << CS_OC_GREEN(__VA_ARGS__))

// #define CS_ERR(msg)
//	CS_STDERR << msg << ::std::endl
// --- 要自行 #include <cstdlib>
#define CS_DIE(msg)																		\
	CS_ERR(msg); 																		\
    ::std::exit(CS_EXIT_STATUS_FAILED)

#ifndef CS_USED
#	ifdef __GNUC__
#		define CS_USED __attribute__((__used__))
#	else
#		define CS_USED
#	endif
#endif

#ifndef CS_ATTR_CONST
#	ifdef __GNUC__
#		define CS_ATTR_CONST __attribute__((const))
#	else
#		define CS_ATTR_CONST
#	endif
#endif

#ifndef CS_MUST_CHECK
#	ifdef __GNUC__
#		define CS_MUST_CHECK __attribute__((warn_unused_result))
#	else
#		define CS_MUST_CHECK
#	endif
#endif

#ifndef CS_DEPRECATED
#	ifdef __GNUC__
#		define CS_DEPRECATED __attribute__((deprecated))
#	else
#		define CS_DEPRECATED
#	endif
#endif

#ifndef CS_FORCE_INLINE
#   ifdef __GNUC__
#       define CS_FORCE_INLINE __attribute__((always_inline))
#   else
#       define CS_FORCE_INLINE inline
#   endif
#endif

#if !defined(CS_LIKELY) && !defined(CS_UNLIKELY)
#	ifdef __GNUC__
#		define CS_LIKELY(...)		__builtin_expect(!!(__VA_ARGS__), 1)
#		define CS_UNLIKELY(...)		__builtin_expect(!!(__VA_ARGS__), 0)
#		define CS_BLIKELY(...)		__builtin_expect((__VA_ARGS__), true)
#		define CS_BUNLIKELY(...)	__builtin_expect((__VA_ARGS__), false)
#	else
#		define CS_LIKELY(expr)		(expr)
#		define CS_UNLIKELY(expr)	(expr)
#		define CS_BLIKELY(expr)		(expr)
#		define CS_BUNLIKELY(expr)	(expr)
#	endif
#endif

#ifndef CS_PREFETCH
#	ifdef __GNUC__
#		define CS_PREFETCH(addr,rw,clean) __builtin_prefetch(addr,rw,clean)
#	else
#		define CS_PREFETCH(addr,rw,clean)
#	endif
#endif

#define CS_RETURN_IF_NORMAL(cond, ...)		\
if (cond)									\
{											\
	return __VA_ARGS__;						\
}
#define CS_RETURN_IF(cond, ...) CS_RETURN_IF_NORMAL(CS_BUNLIKELY(cond), __VA_ARGS__)

#define CS_ABORT_IF_NORMAL(cond)			\
if (cond)									\
{											\
	::std::exit(CS_EXIT_STATUS_FAILED);		\
}
#define CS_ABORT_IF(cond) CS_ABORT_IF_NORMAL(CS_BUNLIKELY(cond))

#define _CS_DIE_IF_NORMAL(cond, info, why)	\
if (cond)									\
{											\
	CS_DIE(__FILE__ << ":" << __LINE__ << "::" << __FUNCTION__ << "() die on " << info << ", results from {" << #why << "}.");  \
}
#define CS_DIE_IF_NORMAL(cond, info) CS_DIE_IF_NORMAL(cond, info, cond)
#define CS_DIE_IF(cond, info) _CS_DIE_IF_NORMAL(CS_BUNLIKELY(cond), info, cond)
<commit_msg>c++11 flag<commit_after>
/**
 * 所有 #include <外部文件> 的头文件 都必须保证 本文件被首先#include
 * 以下项目可以由本文件保证包含：
 * 	<cstdint>
 * 	<cstddef>
 * 	并保证 全局名称空间包含所有stdint。
 * 	CS_DEBUG = 1 时保证 #include <iostream>
 */

#pragma once

/**
 * 平台兼容原则：以不大的代价换取一定的兼容性；以首要目标平台0-overhead为前提。
 */

#ifndef NDEBUG
#	ifndef CS_DEBUG
#   	define CS_DEBUG		2
#	endif
#	ifndef CS_LOG_ON
#		define CS_LOG_ON	1
#	endif
#else
#	undef CS_DEBUG
#	define CS_DEBUG			0
#	undef CS_LOG_ON
#	define CS_LOG_ON		0
#endif

#if ! CS_DEBUG
#ifndef NDEBUG
#	define NDEBUG
#endif
#	define BOOST_DISABLE_ASSERTS
#endif

#if defined(__cplusplus) && __cplusplus >= 201103L
#   define CS_CPP11 1
#else
#   define CS_CPP11 0
#endif

// Use wchar_t/wstring wcout/wcerr/wcin wfstream or not.
// It's just a standard, not make used in this file.
#ifndef CS_USE_WCS
#	define CS_USE_WCS	0
#endif
// Use wcout/wcerr/wcin or not. This will make use in this file.
#ifndef CS_USE_WIO
#	define CS_USE_WIO	0
#endif

#if defined(CS_USE_WCS) && CS_USE_WCS
#	define CS_STR_LITER(str_liter)		L##str_liter
#else
#	define CS_STR_LITER(str_liter)		#str_liter
#endif

#ifndef __GNUC__
#   define __attribute__(...)
#endif

#ifdef __cplusplus
// avoid from boost if possible.
#	if defined(__GNUC__)	\
		&& (!defined(__GXX_EXPERIMENTAL_CXX0X__) || !__GXX_EXPERIMENTAL_CXX0X__)
#		include <boost/cstdint.hpp>
#	else
#		include <cstdint>
#	endif
#	include <cstddef>
#else
#	include <stdint.h>
#	include <stddef.h>
#endif

#define CS_EXIT_STATUS_FAILED EXIT_FAILURE

#ifdef __cplusplus
#	define CS_PREF_STD(symbol)		::std::symbol
#else
#	define CS_PREF_STD(symbol)		symbol
#endif

#if CS_USE_WIO
#	define CS_STDIN		::std::wcin
#	define CS_STDOUT	::std::wcout
#	define CS_STDERR	::std::wcerr
#else
#	define CS_STDIN		::std::cin
#	define CS_STDOUT	::std::cout
#	define CS_STDERR	::std::cerr
#endif

#ifdef __linux__
#   define CS_OC_BLACK(...) "\033[32;30;5m" << __VA_ARGS__ << "\033[0m"
#   define CS_OC_BLUE(...)  "\033[32;34;5m" << __VA_ARGS__ << "\033[0m"
#   define CS_OC_RED(...)   "\033[32;31;5m" << __VA_ARGS__ << "\033[0m"
#   define CS_OC_GREEN(...) "\033[32;49;5m" << __VA_ARGS__ << "\033[0m"
#else
#   define CS_OC_BLACK(...) __VA_ARGS__
#   define CS_OC_BLUE(...)  __VA_ARGS__
#   define CS_OC_RED(...)   __VA_ARGS__
#   define CS_OC_GREEN(...) __VA_ARGS__
#endif

// line-seperator, should only use for IO..
#ifdef __linux__
#	define CS_LINESEP		'\n'
#	define CS_LINESEP_STR	"\n"
#else
#	ifdef(__WIN32__)
#		define CS_LINESEP		"\r\n"
#		define CS_LINESEP_STR	CS_LINESEP
#	else
#		define CS_LINESEP		::std::endl
#		define CS_LINESEP_STR	::std::endl()
#	endif
#endif

#if CS_DEBUG
#   define CS_DEBUG_OMIT(...)
#   include <iostream>
#   if CS_DEBUG > 1
#		if CS_USE_WCS
#			define CS_OUT(ostream, ...)											\
				do {															\
				ostream << __FILE__ << ":" << __LINE__							\
					<< ":" << __FUNCTION__ << "()" << ":\t"						\
					<< __VA_ARGS__												\
					<< ::std::endl;												\
				} while(false);
#		else
#       	define CS_OUT(ostream, ...)											\
				do {															\
				ostream << CS_OC_BLACK(__FILE__ << ":" << __LINE__)				\
					<< ":" << CS_OC_BLUE(__FUNCTION__ << "()") << ":\t"			\
					<< CS_OC_GREEN(__VA_ARGS__)									\
					<< ::std::endl;												\
				} while(false);
#		endif
#   else
#		define CS_OUT(ostream, ...)	do {ostream << __VA_ARGS__ << ::std::endl;} while(false);
#   endif
#else
#   define CS_DEBUG_OMIT(...)    __VA_ARGS__
#	define CS_OUT(ostream, ...)
#endif

#define CS_SAY(...)		CS_OUT(CS_STDOUT, __VA_ARGS__)

// NOTE: 要自行 #include <iostream>
#define CS_ECHO(...)	CS_STDOUT << __VA_ARGS__ << ::std::endl;
#define CS_ERR(...)		CS_STDERR << __VA_ARGS__ << ::std::endl;

// #define CS_DUMP(...)	CS_OUT(CS_STDOUT, GOL_OC_BLUE(#__VA_ARGS__) << ": " << GOL_OC_GREEN(__VA_ARGS__))

#define CS_DUMP(...)																	\
	CS_OUT(CS_STDOUT, CS_OC_RED(#__VA_ARGS__) << ":[" << CS_OC_GREEN(__VA_ARGS__) << "]")
#define CS_DUMP_N(...) 																	\
	CS_OUT(CS_STDOUT, CS_OC_RED(#__VA_ARGS__) << ":" << ::std::endl << CS_OC_GREEN(__VA_ARGS__))

// #define CS_ERR(msg)
//	CS_STDERR << msg << ::std::endl
// --- 要自行 #include <cstdlib>
#define CS_DIE(msg)																		\
	CS_ERR(msg); 																		\
    ::std::exit(CS_EXIT_STATUS_FAILED)

#ifndef CS_USED
#	ifdef __GNUC__
#		define CS_USED __attribute__((__used__))
#	else
#		define CS_USED
#	endif
#endif

#ifndef CS_ATTR_CONST
#	ifdef __GNUC__
#		define CS_ATTR_CONST __attribute__((const))
#	else
#		define CS_ATTR_CONST
#	endif
#endif

#ifndef CS_MUST_CHECK
#	ifdef __GNUC__
#		define CS_MUST_CHECK __attribute__((warn_unused_result))
#	else
#		define CS_MUST_CHECK
#	endif
#endif

#ifndef CS_DEPRECATED
#	ifdef __GNUC__
#		define CS_DEPRECATED __attribute__((deprecated))
#	else
#		define CS_DEPRECATED
#	endif
#endif

#ifndef CS_FORCE_INLINE
#   ifdef __GNUC__
#       define CS_FORCE_INLINE __attribute__((always_inline))
#   else
#       define CS_FORCE_INLINE inline
#   endif
#endif

#if !defined(CS_LIKELY) && !defined(CS_UNLIKELY)
#	ifdef __GNUC__
#		define CS_LIKELY(...)		__builtin_expect(!!(__VA_ARGS__), 1)
#		define CS_UNLIKELY(...)		__builtin_expect(!!(__VA_ARGS__), 0)
#		define CS_BLIKELY(...)		__builtin_expect((__VA_ARGS__), true)
#		define CS_BUNLIKELY(...)	__builtin_expect((__VA_ARGS__), false)
#	else
#		define CS_LIKELY(expr)		(expr)
#		define CS_UNLIKELY(expr)	(expr)
#		define CS_BLIKELY(expr)		(expr)
#		define CS_BUNLIKELY(expr)	(expr)
#	endif
#endif

#ifndef CS_PREFETCH
#	ifdef __GNUC__
#		define CS_PREFETCH(addr,rw,clean) __builtin_prefetch(addr,rw,clean)
#	else
#		define CS_PREFETCH(addr,rw,clean)
#	endif
#endif

#define CS_RETURN_IF_NORMAL(cond, ...)		\
if (cond)									\
{											\
	return __VA_ARGS__;						\
}
#define CS_RETURN_IF(cond, ...) CS_RETURN_IF_NORMAL(CS_BUNLIKELY(cond), __VA_ARGS__)

#define CS_ABORT_IF_NORMAL(cond)			\
if (cond)									\
{											\
	::std::exit(CS_EXIT_STATUS_FAILED);		\
}
#define CS_ABORT_IF(cond) CS_ABORT_IF_NORMAL(CS_BUNLIKELY(cond))

#define _CS_DIE_IF_NORMAL(cond, info, why)	\
if (cond)									\
{											\
	CS_DIE(__FILE__ << ":" << __LINE__ << "::" << __FUNCTION__ << "() die on " << info << ", results from {" << #why << "}.");  \
}
#define CS_DIE_IF_NORMAL(cond, info) CS_DIE_IF_NORMAL(cond, info, cond)
#define CS_DIE_IF(cond, info) _CS_DIE_IF_NORMAL(CS_BUNLIKELY(cond), info, cond)
<|endoftext|>


<commit_before>/***********************************************************************
 dbdriver.cpp - Implements the DBDriver class.

 Copyright (c) 2005-2009 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#define MYSQLPP_NOT_HEADER
#include "dbdriver.h"

#include "exceptions.h"

#include <cstring>
#include <memory>
#include <sstream>

// An argument was added to mysql_shutdown() in MySQL 4.1.3 and 5.0.1.
#if ((MYSQL_VERSION_ID >= 40103) && (MYSQL_VERSION_ID <= 49999)) || (MYSQL_VERSION_ID >= 50001)
#	define SHUTDOWN_ARG ,SHUTDOWN_DEFAULT
#else
#	define SHUTDOWN_ARG
#endif

using namespace std;

namespace mysqlpp {

DBDriver::DBDriver() :
is_connected_(false)
{
	// We won't allow calls to mysql_*() functions that take a MYSQL
	// object until we get a connection up.  Such calls are nonsense.
	// MySQL++ coped with them before, but this masks bugs.
	memset(&mysql_, 0, sizeof(mysql_));
}

DBDriver::DBDriver(const DBDriver& other) :
is_connected_(false)
{
	copy(other);
}

DBDriver::~DBDriver()
{
	if (connected()) {
		disconnect();
	}

	OptionList::const_iterator it;
	for (it = applied_options_.begin(); it != applied_options_.end(); ++it) {
		delete *it;
	}
}

bool
DBDriver::connect(const char* host, const char* socket_name,
		unsigned int port, const char* db, const char* user,
		const char* password)
{
	return is_connected_ =
			connect_prepare() &&
			mysql_real_connect(&mysql_, host, user, password, db,
				port, socket_name, mysql_.client_flag);
}

bool
DBDriver::connect(const MYSQL& other)
{
	return is_connected_ =
			connect_prepare() &&
			mysql_real_connect(&mysql_, other.host, other.user,
				other.passwd, other.db, other.port, other.unix_socket,
				other.client_flag);
}

bool
DBDriver::connect_prepare()
{
	// Drop previous connection, if any, then prepare underlying C API
	// library to establish a new connection.
	if (connected()) {
		disconnect();
	}

	// Set up to call MySQL C API
	mysql_init(&mysql_);

    // Apply any pending options
	error_message_.clear();
	OptionListIt it = pending_options_.begin();
	while (it != pending_options_.end() && set_option_impl(*it)) {
		++it;
	}
	if (it == pending_options_.end()) {
		pending_options_.clear();
		return true;
	}
	else {
		return false;
	}
}

void
DBDriver::copy(const DBDriver& other)
{
	if (other.connected()) {
		connect(other.mysql_);
	}
	else {
		is_connected_ = false;
	}
}

void
DBDriver::disconnect()
{
	if (is_connected_) {
		mysql_close(&mysql_);
		memset(&mysql_, 0, sizeof(mysql_));
		is_connected_ = false;
		error_message_.clear();
	}
}

bool
DBDriver::enable_ssl(const char* key, const char* cert,
		const char* ca, const char* capath, const char* cipher)
{
	error_message_.clear();
#if defined(HAVE_MYSQL_SSL_SET)
	return mysql_ssl_set(&mysql_, key, cert, ca, capath, cipher) == 0;
#else
	(void)key;
	(void)cert;
	(void)ca;
	(void)capath;
	(void)cipher;
	return false;
#endif
}

size_t
DBDriver::escape_string(std::string* ps, const char* original,
		size_t length)
{
	error_message_.clear();

	if (ps == 0) {
		// Can't do any real work!
		return 0;
	}
	else if (original == 0) {
		// ps must point to the original data as well as to the
		// receiving string, so get the pointer and the length from it.
		original = ps->data();
		length = ps->length();
	}
	else if (length == 0) {
		// We got a pointer to a C++ string just for holding the result
		// and also a C string pointing to the original, so find the
		// length of the original.
		length = strlen(original);
	}

	char* escaped = new char[length * 2 + 1];
	length = escape_string(escaped, original, length);
	ps->assign(escaped, length);
	delete[] escaped;

	return length;
}

size_t
DBDriver::escape_string_no_conn(std::string* ps, const char* original,
		size_t length)
{
	if (ps == 0) {
		// Can't do any real work!
		return 0;
	}
	else if (original == 0) {
		// ps must point to the original data as well as to the
		// receiving string, so get the pointer and the length from it.
		original = ps->data();
		length = ps->length();
	}
	else if (length == 0) {
		// We got a pointer to a C++ string just for holding the result
		// and also a C string pointing to the original, so find the
		// length of the original.
		length = strlen(original);
	}

	char* escaped = new char[length * 2 + 1];
	length = DBDriver::escape_string_no_conn(escaped, original, length);
	ps->assign(escaped, length);
	delete[] escaped;

	return length;
}

DBDriver&
DBDriver::operator=(const DBDriver& rhs)
{
	copy(rhs);
	return *this;
}

string
DBDriver::query_info()
{
	error_message_.clear();
	const char* i = mysql_info(&mysql_);
	return i ? string(i) : string();
}

bool
DBDriver::set_option(unsigned int o, bool arg)
{
	// If we get through this loop and n is 1, only one bit is set in
	// the option value, which is as it should be.
	int n = o;
	while (n && ((n & 1) == 0)) {
		n >>= 1;
	}

	if ((n == 1) &&
			(o >= CLIENT_LONG_PASSWORD) &&
#if MYSQL_VERSION_ID > 40000	// highest flag value varies by version
			(o <= CLIENT_MULTI_RESULTS)
#else
			(o <= CLIENT_TRANSACTIONS)
#endif
			) {
		// Option value seems sane, so go ahead and set/clear the flag
		if (arg) {
			mysql_.client_flag |= o;
		}
		else {
			mysql_.client_flag &= ~o;
		}

		return true;
	}
	else {
		// Option value is outside the range we understand, or caller
		// erroneously passed a value with multiple bits set.
		return false;
	}
}

bool
DBDriver::set_option(Option* o)
{
	if (connected()) {
		return set_option_impl(o);
	}
	else {
		error_message_.clear();
        pending_options_.push_back(o);
		return true;  // we won't know if it fails until ::connect()
	}
}

bool
DBDriver::set_option_impl(Option* o)
{
	std::ostringstream os;
	std::auto_ptr<Option> cleanup(o);

	switch (o->set(this)) {
		case Option::err_NONE:
			applied_options_.push_back(o);
			cleanup.release();
			break;

		case Option::err_api_limit:
			os << "Option not supported by database driver v" <<
					client_version();
			throw BadOption(os.str(), typeid(*o)); // mandatory throw!

		case Option::err_api_reject:
			os << "Database driver failed to set option";
			break;

		case Option::err_connected:
			os << "Option can only be set before connection is established";
			break;

		case Option::err_disconnected:
			os << "Option can only be set while the connection is established";
			break;
	}

	error_message_ = os.str();
	return error_message_.empty();
}

bool
DBDriver::shutdown()
{
	error_message_.clear();
	return mysql_shutdown(&mysql_ SHUTDOWN_ARG);
}

bool
DBDriver::thread_aware()
{
#if defined(MYSQLPP_PLATFORM_WINDOWS) || defined(HAVE_PTHREAD) || defined(HAVE_SYNCH_H)
	// Okay, good, MySQL++ itself is thread-aware, but only return true
	// if the underlying C API library is also thread-aware.
	return mysql_thread_safe();
#else
	// MySQL++ itself isn't thread-aware, so we don't need to do any
	// further tests.  All pieces must be thread-aware to return true.
	return false;
#endif
}

} // end namespace mysqlpp

<commit_msg>The DBDriver::operator= would leak a live connection if you assigned a disconnected DBDriver to it.  Patch by Quentin Armitage <quentin@armitage.org.uk><commit_after>/***********************************************************************
 dbdriver.cpp - Implements the DBDriver class.

 Copyright (c) 2005-2009 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the
 CREDITS.txt file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published
 by the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.

 MySQL++ is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#define MYSQLPP_NOT_HEADER
#include "dbdriver.h"

#include "exceptions.h"

#include <cstring>
#include <memory>
#include <sstream>

// An argument was added to mysql_shutdown() in MySQL 4.1.3 and 5.0.1.
#if ((MYSQL_VERSION_ID >= 40103) && (MYSQL_VERSION_ID <= 49999)) || (MYSQL_VERSION_ID >= 50001)
#	define SHUTDOWN_ARG ,SHUTDOWN_DEFAULT
#else
#	define SHUTDOWN_ARG
#endif

using namespace std;

namespace mysqlpp {

DBDriver::DBDriver() :
is_connected_(false)
{
	// We won't allow calls to mysql_*() functions that take a MYSQL
	// object until we get a connection up.  Such calls are nonsense.
	// MySQL++ coped with them before, but this masks bugs.
	memset(&mysql_, 0, sizeof(mysql_));
}

DBDriver::DBDriver(const DBDriver& other) :
is_connected_(false)
{
	copy(other);
}

DBDriver::~DBDriver()
{
	if (connected()) {
		disconnect();
	}

	OptionList::const_iterator it;
	for (it = applied_options_.begin(); it != applied_options_.end(); ++it) {
		delete *it;
	}
}

bool
DBDriver::connect(const char* host, const char* socket_name,
		unsigned int port, const char* db, const char* user,
		const char* password)
{
	return is_connected_ =
			connect_prepare() &&
			mysql_real_connect(&mysql_, host, user, password, db,
				port, socket_name, mysql_.client_flag);
}

bool
DBDriver::connect(const MYSQL& other)
{
	return is_connected_ =
			connect_prepare() &&
			mysql_real_connect(&mysql_, other.host, other.user,
				other.passwd, other.db, other.port, other.unix_socket,
				other.client_flag);
}

bool
DBDriver::connect_prepare()
{
	// Drop previous connection, if any, then prepare underlying C API
	// library to establish a new connection.
	if (connected()) {
		disconnect();
	}

	// Set up to call MySQL C API
	mysql_init(&mysql_);

    // Apply any pending options
	error_message_.clear();
	OptionListIt it = pending_options_.begin();
	while (it != pending_options_.end() && set_option_impl(*it)) {
		++it;
	}
	if (it == pending_options_.end()) {
		pending_options_.clear();
		return true;
	}
	else {
		return false;
	}
}

void
DBDriver::copy(const DBDriver& other)
{
	if (connected()) {
		disconnect();
	}

	if (other.connected()) {
		connect(other.mysql_);
	}
}

void
DBDriver::disconnect()
{
	if (is_connected_) {
		mysql_close(&mysql_);
		memset(&mysql_, 0, sizeof(mysql_));
		is_connected_ = false;
		error_message_.clear();
	}
}

bool
DBDriver::enable_ssl(const char* key, const char* cert,
		const char* ca, const char* capath, const char* cipher)
{
	error_message_.clear();
#if defined(HAVE_MYSQL_SSL_SET)
	return mysql_ssl_set(&mysql_, key, cert, ca, capath, cipher) == 0;
#else
	(void)key;
	(void)cert;
	(void)ca;
	(void)capath;
	(void)cipher;
	return false;
#endif
}

size_t
DBDriver::escape_string(std::string* ps, const char* original,
		size_t length)
{
	error_message_.clear();

	if (ps == 0) {
		// Can't do any real work!
		return 0;
	}
	else if (original == 0) {
		// ps must point to the original data as well as to the
		// receiving string, so get the pointer and the length from it.
		original = ps->data();
		length = ps->length();
	}
	else if (length == 0) {
		// We got a pointer to a C++ string just for holding the result
		// and also a C string pointing to the original, so find the
		// length of the original.
		length = strlen(original);
	}

	char* escaped = new char[length * 2 + 1];
	length = escape_string(escaped, original, length);
	ps->assign(escaped, length);
	delete[] escaped;

	return length;
}

size_t
DBDriver::escape_string_no_conn(std::string* ps, const char* original,
		size_t length)
{
	if (ps == 0) {
		// Can't do any real work!
		return 0;
	}
	else if (original == 0) {
		// ps must point to the original data as well as to the
		// receiving string, so get the pointer and the length from it.
		original = ps->data();
		length = ps->length();
	}
	else if (length == 0) {
		// We got a pointer to a C++ string just for holding the result
		// and also a C string pointing to the original, so find the
		// length of the original.
		length = strlen(original);
	}

	char* escaped = new char[length * 2 + 1];
	length = DBDriver::escape_string_no_conn(escaped, original, length);
	ps->assign(escaped, length);
	delete[] escaped;

	return length;
}

DBDriver&
DBDriver::operator=(const DBDriver& rhs)
{
	copy(rhs);
	return *this;
}

string
DBDriver::query_info()
{
	error_message_.clear();
	const char* i = mysql_info(&mysql_);
	return i ? string(i) : string();
}

bool
DBDriver::set_option(unsigned int o, bool arg)
{
	// If we get through this loop and n is 1, only one bit is set in
	// the option value, which is as it should be.
	int n = o;
	while (n && ((n & 1) == 0)) {
		n >>= 1;
	}

	if ((n == 1) &&
			(o >= CLIENT_LONG_PASSWORD) &&
#if MYSQL_VERSION_ID > 40000	// highest flag value varies by version
			(o <= CLIENT_MULTI_RESULTS)
#else
			(o <= CLIENT_TRANSACTIONS)
#endif
			) {
		// Option value seems sane, so go ahead and set/clear the flag
		if (arg) {
			mysql_.client_flag |= o;
		}
		else {
			mysql_.client_flag &= ~o;
		}

		return true;
	}
	else {
		// Option value is outside the range we understand, or caller
		// erroneously passed a value with multiple bits set.
		return false;
	}
}

bool
DBDriver::set_option(Option* o)
{
	if (connected()) {
		return set_option_impl(o);
	}
	else {
		error_message_.clear();
        pending_options_.push_back(o);
		return true;  // we won't know if it fails until ::connect()
	}
}

bool
DBDriver::set_option_impl(Option* o)
{
	std::ostringstream os;
	std::auto_ptr<Option> cleanup(o);

	switch (o->set(this)) {
		case Option::err_NONE:
			applied_options_.push_back(o);
			cleanup.release();
			break;

		case Option::err_api_limit:
			os << "Option not supported by database driver v" <<
					client_version();
			throw BadOption(os.str(), typeid(*o)); // mandatory throw!

		case Option::err_api_reject:
			os << "Database driver failed to set option";
			break;

		case Option::err_connected:
			os << "Option can only be set before connection is established";
			break;

		case Option::err_disconnected:
			os << "Option can only be set while the connection is established";
			break;
	}

	error_message_ = os.str();
	return error_message_.empty();
}

bool
DBDriver::shutdown()
{
	error_message_.clear();
	return mysql_shutdown(&mysql_ SHUTDOWN_ARG);
}

bool
DBDriver::thread_aware()
{
#if defined(MYSQLPP_PLATFORM_WINDOWS) || defined(HAVE_PTHREAD) || defined(HAVE_SYNCH_H)
	// Okay, good, MySQL++ itself is thread-aware, but only return true
	// if the underlying C API library is also thread-aware.
	return mysql_thread_safe();
#else
	// MySQL++ itself isn't thread-aware, so we don't need to do any
	// further tests.  All pieces must be thread-aware to return true.
	return false;
#endif
}

} // end namespace mysqlpp

<|endoftext|>


<commit_before>#include <iostream>
#include "bmp.hh"

namespace DG {
namespace Image {

void BMP::open(const std::string& fname) {
  std::ifstream ifs(fname, std::ios::binary);
  ifs >> data;
}

void BMP::write(const std::string& fname) {
  std::ofstream ofs(fname, std::ios::binary);
  ofs << data;
}

void BMP::byte_set_mask(int index, unsigned mask) {
  unsigned byte = data.byte_array[index];
  byte |= mask;
  data.byte_array[index] = byte;
  return;
}

void BMP::byte_unset_mask(int index, unsigned mask) {
  unsigned byte = data.byte_array[index];
  byte &= ~mask;
  data.byte_array[index] = byte;
  return;
}

//// friend non-member operators
std::ostream& operator<<(std::ostream& os, const DG::Image::BMP& bmp) {
  return os;
}

std::istream& operator>>(std::istream& is, DG::Image::BMP& bmp) {
  return is;
}

}
}
<commit_msg>Fixed byte mask implementations so that tests now pass<commit_after>#include <iostream>
#include "bmp.hh"

namespace DG {
namespace Image {

void BMP::open(const std::string& fname) {
  std::ifstream ifs(fname, std::ios::binary);
  ifs >> data;
}

void BMP::write(const std::string& fname) {
  std::ofstream ofs(fname, std::ios::binary);
  ofs << data;
}

void BMP::byte_set_mask(int index, unsigned mask) {
  unsigned byte = data.byte_array[index + data.image_offset()];
  byte |= mask;
  data.byte_array[index + data.image_offset()] = byte;
  return;
}

void BMP::byte_unset_mask(int index, unsigned mask) {
  unsigned byte = data.byte_array[index + data.image_offset()];
  byte &= ~mask;
  data.byte_array[index + data.image_offset()] = byte;
  return;
}

//// friend non-member operators
std::ostream& operator<<(std::ostream& os, const DG::Image::BMP& bmp) {
  return os;
}

std::istream& operator>>(std::istream& is, DG::Image::BMP& bmp) {
  return is;
}

}
}
<|endoftext|>


<commit_before>//=============================================================================
//File Name: ButtonTracker.hpp
//Description: Helps user determine if joystick button was just pressed or just
//             released
//Author: FRC Team 3512, Spartatroniks
//=============================================================================

#ifndef BUTTON_TRACKER_HPP
#define BUTTON_TRACKER_HPP

/* This class allows you to check if a button was pressed or released without
 * having to wait in one spot of code until that happens.
 *
 * It is useful for situations in which you need to toggle a variable and just
 * checking for it with Joystick::GetRawButton(UINT32) would cause it to toggle
 * every loop.
 *
 * USAGE
 * 1) Call updateButtons() at beginning of OperatorControl loop to get new button
 *    statuses from the Driver Station
 * 2) Call pressedButton(UINT32) or releasedButton(UINT32) to poll for whether the
 *    button was pressed or released since last loop
 *
 * None of these functions block.
 */

class DriverStation;

class ButtonTracker {
public:
    ButtonTracker( UINT32 port );

    void updateButtons(); // gets new button statuses for joystick from Driver Station

    bool pressedButton( UINT32 button ); // returns true if button wasn't pressed but is now
    bool releasedButton( UINT32 button ); // returns true if button was pressed but isn't now

protected:
    UINT32 m_port;

private:
    static bool getButtonState( short& buttonStates , UINT32& button );

    static bool m_driverStationInit;
    static DriverStation* m_driverStation;

    short m_oldStates;
    short m_newStates;
};

#endif // BUTTON_TRACKER_H
<commit_msg>Edited ButtonTracker class description<commit_after>//=============================================================================
//File Name: ButtonTracker.hpp
//Description: Helps user determine if joystick button was just pressed or just
//             released
//Author: FRC Team 3512, Spartatroniks
//=============================================================================

#ifndef BUTTON_TRACKER_HPP
#define BUTTON_TRACKER_HPP

/* This class allows you to check if a button was pressed or released without
 * having to wait in one spot of code until that happens.
 *
 * It is useful for situations in which you need to toggle a variable and just
 * checking for it with Joystick::GetRawButton(UINT32) would cause it to toggle
 * in every iteration of a loop.
 *
 * USAGE
 * 1) Call updateButtons() at beginning of loop to get new button statuses from
 *    the Driver Station
 * 2) Call pressedButton(UINT32) or releasedButton(UINT32) to poll for whether
 *    the button was pressed or released since last loop iteration
 *
 * None of these functions block.
 */

class DriverStation;

class ButtonTracker {
public:
    ButtonTracker( UINT32 port );

    void updateButtons(); // gets new button statuses for joystick from Driver Station

    bool pressedButton( UINT32 button ); // returns true if button wasn't pressed but is now
    bool releasedButton( UINT32 button ); // returns true if button was pressed but isn't now

protected:
    UINT32 m_port;

private:
    static bool getButtonState( short& buttonStates , UINT32& button );

    static bool m_driverStationInit;
    static DriverStation* m_driverStation;

    short m_oldStates;
    short m_newStates;
};

#endif // BUTTON_TRACKER_H
<|endoftext|>


<commit_before>#include "cnn/training.h"

#include "cnn/gpu-ops.h"

namespace cnn {

using namespace std;

Trainer::~Trainer() {}

/**
@scale : proportional to the number of samples trained in parallel
*/
float Trainer::clip_gradients(float samples) {
  float gscale = 1;
  if (clipping_enabled) {
    float gg = model->gradient_l2_norm();
    if (gg > clip_threshold * samples) {
      ++clips;
      gscale = (clip_threshold * samples) / gg;
    }
  }
  return gscale;
}

void SimpleSGDTrainer::update(float nutt, real scale) {
    update(model->lookup_parameters_list(), model->parameters_list(), nutt, scale);
}

void SimpleSGDTrainer::update(const std::vector<LookupParameters*> &lookup_params, const std::vector<Parameters*> &params, float samples, real scale) {
  const float gscale = clip_gradients(samples);
  float nutt_scale = 1.0 / samples;
  for (auto p : params) {
#if HAVE_CUDA
    gpu::sgd_update(p->values.d.size(), p->g.v, p->values.v, eta * scale * gscale * nutt_scale, lambda);
#else
    auto reg = (*p->values) * lambda;
    *p->values -= nutt_scale * ((eta * scale * gscale) * *p->g + reg);
#endif
    p->clear();
  }
  for (auto p : lookup_params) {
    for (auto i : p->non_zero_grads) {
#if HAVE_CUDA
      gpu::sgd_update(p->values[i].d.size(), p->grads[i].v, p->values[i].v, eta * scale * gscale * nutt_scale, lambda);
#else
      auto reg = (*p->values[i]) * lambda;
      *p->values[i] -= (*p->grads[i] * (eta * scale * gscale * nutt_scale) + reg);
#endif
    }
    p->clear();
  }
  ++updates;
}

void MomentumSGDTrainer::update(real nutt, real scale) {
  // executed on the first iteration to create vectors to
  // store the velocity
  if (!velocity_allocated) {
    vp = AllocateShadowParameters(*model);
    vlp = AllocateShadowLookupParameters(*model);
    velocity_allocated = true;
  }

  const float gscale = clip_gradients(nutt);
  float nutt_scale = 1.0 / nutt;
  unsigned pi = 0;
  for (auto p : model->parameters_list()) {
    Tensor& v = vp[pi++].h;
    auto reg = *p->values * lambda;
    (*v) = momentum * (*v) - (eta * scale * gscale*nutt_scale) * (*p->g);
    *p->values += *v - reg;
    p->clear();
  }
  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<Tensor>& vx = vlp[pi++].h;
    for (auto i : p->non_zero_grads) {
      Tensor& v = vx[i];
      auto reg = (*p->values[i]) * lambda;
      (*v) = momentum * (*v) - (eta * scale * gscale*nutt_scale) * (*p->grads[i]);
      *p->values[i] += *v - reg;
    }
    p->clear();
  }
  ++updates;
}

void AdagradTrainer::update(real nsamples, real scale) {
  unsigned pi;
  if (!shadow_params_allocated) {
    vp = AllocateShadowParameters(*model);
    vlp = AllocateShadowLookupParameters(*model);
    shadow_params_allocated = true;
  }

  pi = 0;
  const float gscale = clip_gradients(nsamples);
  for (auto p : model->parameters_list()) {
    Tensor& v = vp[pi++].h;
    auto reg = (*p->values) * lambda;
    auto g2 = (*p->g).cwiseProduct(*p->g);
    (*v) += g2;
    auto delta = -(eta * scale * gscale) * (*p->g).cwiseQuotient(((*v).array() + epsilon).matrix().cwiseSqrt());
    *p->values += delta - reg;
    p->clear();
  }

  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<Tensor>& vx = vlp[pi++].h;
    for (auto i : p->non_zero_grads) {
      Tensor& v = vx[i];
      auto reg = (*p->values[i]) * lambda;
      auto g2 = (*p->grads[i]).cwiseProduct(*p->grads[i]);
      (*v) += g2;
      auto delta = -(eta * scale * gscale) * (*p->grads[i]).cwiseQuotient(((*v).array() + epsilon).matrix().cwiseSqrt());
      *p->values[i] += delta - reg;
    }
    p->clear();
  }

  ++updates;
}

void AdadeltaTrainer::update(real nutt, real scale) {
  unsigned pi;
  if (!shadow_params_allocated) {
    hg = AllocateShadowParameters(*model);
    hlg = AllocateShadowLookupParameters(*model);
    hd = AllocateShadowParameters(*model);
    hld = AllocateShadowLookupParameters(*model);

    /*pi = 0;
    for (auto p : model->parameters_list()) {
      TensorTools::Constant(hg[pi].h, epsilon);
      TensorTools::Constant(hd[pi].h, epsilon);
      ++pi;
    }

    pi = 0;
    for (auto p : model->lookup_parameters_list()) {
      vector<Tensor>& hgx = hlg[pi].h;
      vector<Tensor>& hdx = hld[pi].h;
      for (unsigned i = 0; i < hgx.size(); ++i) {
        TensorTools::Constant(hgx[i], epsilon);
        TensorTools::Constant(hdx[i], epsilon);
      }
      ++pi;
    }*/

    shadow_params_allocated = true;
  }

  const float gscale = clip_gradients(nutt);
  float nutt_scale = 1.0 / nutt;
  pi = 0;
  for (auto p : model->parameters_list()) {
    auto& g = (scale * gscale * nutt_scale) * *p->g;
    Tensor& hgv = hg[pi].h;
    Tensor& hdv = hd[pi].h;
    auto reg = (*p->values) * lambda;
    auto g2 = g.cwiseProduct(g);
    *hgv = rho * *hgv + (1.0 - rho) * g2;
    auto num = -g.cwiseProduct(((*hdv).array() + epsilon).matrix().cwiseSqrt());
    auto den = ((*hgv).array() + epsilon).matrix().cwiseSqrt();
    auto delta = num.cwiseQuotient(den);
    auto d2 = delta.cwiseProduct(delta);
    *hdv = rho * *hdv + (1.0 - rho) * d2;
    *p->values += delta - reg;
    p->clear();
    pi++;
  }

  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<Tensor>& hgvx = hlg[pi].h;
    vector<Tensor>& hdvx = hld[pi].h;
    for (auto i : p->non_zero_grads) {
      Tensor& hgv = hgvx[i];
      Tensor& hdv = hdvx[i];
      auto& g = scale * gscale * nutt_scale * *p->grads[i];
      auto reg = (*p->values[i]) * lambda;
      auto g2 = g.cwiseProduct(g);
      *hgv = rho * *hgv + (1.0 - rho) * g2;
      auto num = -g.cwiseProduct(((*hdv).array() + epsilon).matrix().cwiseSqrt());
      auto den = ((*hgv).array() + epsilon).matrix().cwiseSqrt();
      auto delta = num.cwiseQuotient(den);
      auto d2 = delta.cwiseProduct(delta);
      *hdv = rho * *hdv + (1.0 - rho) * d2;
      *p->values[i] += delta - reg;
    }
    p->clear();
    pi++;
  }
  ++updates;
}

void RmsPropTrainer::update(real nutt, real scale) {
  unsigned pi = 0;
  if (!shadow_params_allocated) {
    hg.resize(model->parameters_list().size());

    pi = 0;
    hlg.resize(model->lookup_parameters_list().size());
    for (auto p : model->lookup_parameters_list()) {
      hlg[pi++].resize(p->size());
    }

    shadow_params_allocated = true;
  }

  const float gscale = clip_gradients(nutt);
  float nutt_scale = 1.0 / nutt;
  pi = 0;
  for (auto p : model->parameters_list()) {
    real& d2 = hg[pi++];
    auto reg = (*p->values) * lambda;
    real g2 = (*p->g).squaredNorm();
    d2 = rho * d2 + (1.0 - rho) * g2;
    *p->values -= ((eta * scale * gscale * nutt_scale / sqrt(d2 + epsilon)) * *p->g + reg);
    p->clear();
  }

  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<real>& hlgx = hlg[pi++];
    for (auto i : p->non_zero_grads) {
      real& d2 = hlgx[i];
      auto reg = (*p->values[i]) * lambda;
      real g2 = (*p->grads[i]).squaredNorm();
      d2 = rho * d2 + (1.0 - rho) * g2;
      *p->values[i] -= ((eta * scale * gscale * nutt_scale / sqrt(d2 + epsilon)) * *p->grads[i] + reg);
    }
    p->clear();
  }
  ++updates;
}

void AdamTrainer::update(real nutt, real scale) {
  unsigned pi;
  if (!shadow_params_allocated) {
    m = AllocateShadowParameters(*model);
    lm = AllocateShadowLookupParameters(*model);
    v = AllocateShadowParameters(*model);
    lv = AllocateShadowLookupParameters(*model);
    shadow_params_allocated = true;
  }

  const float gscale = clip_gradients();
  float nutt_scale = 1.0 / nutt;
  pi = 0;
  static unsigned t = 0;
  for (auto p : model->parameters_list()) {
    ++t;
    auto g_t = (scale * gscale * nutt_scale) * *p->g;
    auto m_t = *m[pi].h;
    auto v_t = *v[pi].h;
    auto reg = (*p->values) * lambda;
    m_t = beta_1 * m_t + (1 - beta_1) * g_t;
    auto g2 = g_t.cwiseProduct(g_t);
    v_t = beta_2 * v_t + (1 - beta_2) * g2;
    float s1 = 1 - pow(beta_1, t);
    float s2 = 1 - pow(beta_2, t);
    auto mhat = m_t / s1;
    auto vhat = v_t / s2;
    auto delta = (-eta * mhat).cwiseQuotient((vhat.array().sqrt() + eps).matrix());
    *p->values += delta - reg;
    p->clear();
    pi++;
  }

  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<Tensor>& vm = lm[pi].h;
    vector<Tensor>& vv = lv[pi].h;
    for (auto i : p->non_zero_grads) {
      auto m_t = *vm[i];
      auto v_t = *vv[i];
      auto g_t = scale * gscale * nutt_scale * *p->grads[i];
      auto g2 = g_t.cwiseProduct(g_t);
      auto reg = (*p->values[i]) * lambda;
      m_t = beta_1 * m_t + (1 - beta_1) * g_t;
      v_t = beta_2 * v_t + (1 - beta_2) * g2;
      float s1 = 1 - pow(beta_1, t);
      float s2 = 1 - pow(beta_2, t);
      auto mhat = m_t / s1;
      auto vhat = v_t / s2;
      auto delta = (-eta * mhat).cwiseQuotient((vhat.array().sqrt() + eps).matrix());
      *p->values[i] += delta - reg;
    }
    p->clear();
    pi++;
  }
  ++updates;
}

} // namespace cnn
<commit_msg>print model parameter update info<commit_after>#include "cnn/training.h"

#include "cnn/gpu-ops.h"

extern int verbose;

namespace cnn {

using namespace std;

Trainer::~Trainer() {}

/**
@scale : proportional to the number of samples trained in parallel
*/
float Trainer::clip_gradients(float samples) {
  float gscale = 1;
  if (clipping_enabled) {
    float gg = model->gradient_l2_norm();
    if (gg > clip_threshold * samples) {
      ++clips;
      gscale = (clip_threshold * samples) / gg;
    }
  }
  return gscale;
}

void SimpleSGDTrainer::update(float nutt, real scale) {
    update(model->lookup_parameters_list(), model->parameters_list(), nutt, scale);
}

void SimpleSGDTrainer::update(const std::vector<LookupParameters*> &lookup_params, const std::vector<Parameters*> &params, float samples, real scale) {
  const float gscale = clip_gradients(samples);
  float nutt_scale = 1.0 / samples;
  for (auto p : params) {
#if HAVE_CUDA
    gpu::sgd_update(p->values.d.size(), p->g.v, p->values.v, eta * scale * gscale * nutt_scale, lambda);
#else
    auto reg = (*p->values) * lambda;
    *p->values -= nutt_scale * ((eta * scale * gscale) * *p->g + reg);
#endif
    p->clear();
  }
  for (auto p : lookup_params) {
    for (auto i : p->non_zero_grads) {
#if HAVE_CUDA
      gpu::sgd_update(p->values[i].d.size(), p->grads[i].v, p->values[i].v, eta * scale * gscale * nutt_scale, lambda);
#else
      auto reg = (*p->values[i]) * lambda;
      *p->values[i] -= (*p->grads[i] * (eta * scale * gscale * nutt_scale) + reg);
#endif
    }
    p->clear();
  }
  ++updates;
}

void MomentumSGDTrainer::update(real nutt, real scale) {
  // executed on the first iteration to create vectors to
  // store the velocity
  if (!velocity_allocated) {
    vp = AllocateShadowParameters(*model);
    vlp = AllocateShadowLookupParameters(*model);
    velocity_allocated = true;
  }

  const float gscale = clip_gradients(nutt);
  float nutt_scale = 1.0 / nutt;
  unsigned pi = 0;
  for (auto p : model->parameters_list()) {
    Tensor& v = vp[pi++].h;
    auto reg = *p->values * lambda;
    (*v) = momentum * (*v) - (eta * scale * gscale*nutt_scale) * (*p->g);
    if (verbose)
    {
        cout << "name= " << p->name << " v= " << p->values.v[0] << " g= " << p->g.v[0] << " dv=" << v.v[0] << endl;
    }
    *p->values += *v - reg;
    p->clear();
  }
  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<Tensor>& vx = vlp[pi++].h;
    for (auto i : p->non_zero_grads) {
      Tensor& v = vx[i];
      auto reg = (*p->values[i]) * lambda;
      (*v) = momentum * (*v) - (eta * scale * gscale*nutt_scale) * (*p->grads[i]);
      *p->values[i] += *v - reg;
    }
    p->clear();
  }
  ++updates;
}

void AdagradTrainer::update(real nsamples, real scale) {
  unsigned pi;
  if (!shadow_params_allocated) {
    vp = AllocateShadowParameters(*model);
    vlp = AllocateShadowLookupParameters(*model);
    shadow_params_allocated = true;
  }

  pi = 0;
  const float gscale = clip_gradients(nsamples);
  for (auto p : model->parameters_list()) {
    Tensor& v = vp[pi++].h;
    auto reg = (*p->values) * lambda;
    auto g2 = (*p->g).cwiseProduct(*p->g);
    (*v) += g2;
    auto delta = -(eta * scale * gscale) * (*p->g).cwiseQuotient(((*v).array() + epsilon).matrix().cwiseSqrt());
    *p->values += delta - reg;
    p->clear();
  }

  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<Tensor>& vx = vlp[pi++].h;
    for (auto i : p->non_zero_grads) {
      Tensor& v = vx[i];
      auto reg = (*p->values[i]) * lambda;
      auto g2 = (*p->grads[i]).cwiseProduct(*p->grads[i]);
      (*v) += g2;
      auto delta = -(eta * scale * gscale) * (*p->grads[i]).cwiseQuotient(((*v).array() + epsilon).matrix().cwiseSqrt());
      *p->values[i] += delta - reg;
    }
    p->clear();
  }

  ++updates;
}

void AdadeltaTrainer::update(real nutt, real scale) {
  unsigned pi;
  if (!shadow_params_allocated) {
    hg = AllocateShadowParameters(*model);
    hlg = AllocateShadowLookupParameters(*model);
    hd = AllocateShadowParameters(*model);
    hld = AllocateShadowLookupParameters(*model);

    /*pi = 0;
    for (auto p : model->parameters_list()) {
      TensorTools::Constant(hg[pi].h, epsilon);
      TensorTools::Constant(hd[pi].h, epsilon);
      ++pi;
    }

    pi = 0;
    for (auto p : model->lookup_parameters_list()) {
      vector<Tensor>& hgx = hlg[pi].h;
      vector<Tensor>& hdx = hld[pi].h;
      for (unsigned i = 0; i < hgx.size(); ++i) {
        TensorTools::Constant(hgx[i], epsilon);
        TensorTools::Constant(hdx[i], epsilon);
      }
      ++pi;
    }*/

    shadow_params_allocated = true;
  }

  const float gscale = clip_gradients(nutt);
  float nutt_scale = 1.0 / nutt;
  pi = 0;
  for (auto p : model->parameters_list()) {
    auto& g = (scale * gscale * nutt_scale) * *p->g;
    Tensor& hgv = hg[pi].h;
    Tensor& hdv = hd[pi].h;
    auto reg = (*p->values) * lambda;
    auto g2 = g.cwiseProduct(g);
    *hgv = rho * *hgv + (1.0 - rho) * g2;
    auto num = -g.cwiseProduct(((*hdv).array() + epsilon).matrix().cwiseSqrt());
    auto den = ((*hgv).array() + epsilon).matrix().cwiseSqrt();
    auto delta = num.cwiseQuotient(den);
    auto d2 = delta.cwiseProduct(delta);
    *hdv = rho * *hdv + (1.0 - rho) * d2;
    *p->values += delta - reg;
    p->clear();
    pi++;
  }

  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<Tensor>& hgvx = hlg[pi].h;
    vector<Tensor>& hdvx = hld[pi].h;
    for (auto i : p->non_zero_grads) {
      Tensor& hgv = hgvx[i];
      Tensor& hdv = hdvx[i];
      auto& g = scale * gscale * nutt_scale * *p->grads[i];
      auto reg = (*p->values[i]) * lambda;
      auto g2 = g.cwiseProduct(g);
      *hgv = rho * *hgv + (1.0 - rho) * g2;
      auto num = -g.cwiseProduct(((*hdv).array() + epsilon).matrix().cwiseSqrt());
      auto den = ((*hgv).array() + epsilon).matrix().cwiseSqrt();
      auto delta = num.cwiseQuotient(den);
      auto d2 = delta.cwiseProduct(delta);
      *hdv = rho * *hdv + (1.0 - rho) * d2;
      *p->values[i] += delta - reg;
    }
    p->clear();
    pi++;
  }
  ++updates;
}

void RmsPropTrainer::update(real nutt, real scale) {
  unsigned pi = 0;
  if (!shadow_params_allocated) {
    hg.resize(model->parameters_list().size());

    pi = 0;
    hlg.resize(model->lookup_parameters_list().size());
    for (auto p : model->lookup_parameters_list()) {
      hlg[pi++].resize(p->size());
    }

    shadow_params_allocated = true;
  }

  const float gscale = clip_gradients(nutt);
  float nutt_scale = 1.0 / nutt;
  pi = 0;
  for (auto p : model->parameters_list()) {
    real& d2 = hg[pi++];
    auto reg = (*p->values) * lambda;
    real g2 = (*p->g).squaredNorm();
    d2 = rho * d2 + (1.0 - rho) * g2;
    *p->values -= ((eta * scale * gscale * nutt_scale / sqrt(d2 + epsilon)) * *p->g + reg);
    p->clear();
  }

  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<real>& hlgx = hlg[pi++];
    for (auto i : p->non_zero_grads) {
      real& d2 = hlgx[i];
      auto reg = (*p->values[i]) * lambda;
      real g2 = (*p->grads[i]).squaredNorm();
      d2 = rho * d2 + (1.0 - rho) * g2;
      *p->values[i] -= ((eta * scale * gscale * nutt_scale / sqrt(d2 + epsilon)) * *p->grads[i] + reg);
    }
    p->clear();
  }
  ++updates;
}

void AdamTrainer::update(real nutt, real scale) {
  unsigned pi;
  if (!shadow_params_allocated) {
    m = AllocateShadowParameters(*model);
    lm = AllocateShadowLookupParameters(*model);
    v = AllocateShadowParameters(*model);
    lv = AllocateShadowLookupParameters(*model);
    shadow_params_allocated = true;
  }

  const float gscale = clip_gradients();
  float nutt_scale = 1.0 / nutt;
  pi = 0;
  static unsigned t = 0;
  for (auto p : model->parameters_list()) {
    ++t;
    auto g_t = (scale * gscale * nutt_scale) * *p->g;
    auto m_t = *m[pi].h;
    auto v_t = *v[pi].h;
    auto reg = (*p->values) * lambda;
    m_t = beta_1 * m_t + (1 - beta_1) * g_t;
    auto g2 = g_t.cwiseProduct(g_t);
    v_t = beta_2 * v_t + (1 - beta_2) * g2;
    float s1 = 1 - pow(beta_1, t);
    float s2 = 1 - pow(beta_2, t);
    auto mhat = m_t / s1;
    auto vhat = v_t / s2;
    auto delta = (-eta * mhat).cwiseQuotient((vhat.array().sqrt() + eps).matrix());
    *p->values += delta - reg;
    p->clear();
    pi++;
  }

  pi = 0;
  for (auto p : model->lookup_parameters_list()) {
    vector<Tensor>& vm = lm[pi].h;
    vector<Tensor>& vv = lv[pi].h;
    for (auto i : p->non_zero_grads) {
      auto m_t = *vm[i];
      auto v_t = *vv[i];
      auto g_t = scale * gscale * nutt_scale * *p->grads[i];
      auto g2 = g_t.cwiseProduct(g_t);
      auto reg = (*p->values[i]) * lambda;
      m_t = beta_1 * m_t + (1 - beta_1) * g_t;
      v_t = beta_2 * v_t + (1 - beta_2) * g2;
      float s1 = 1 - pow(beta_1, t);
      float s2 = 1 - pow(beta_2, t);
      auto mhat = m_t / s1;
      auto vhat = v_t / s2;
      auto delta = (-eta * mhat).cwiseQuotient((vhat.array().sqrt() + eps).matrix());
      *p->values[i] += delta - reg;
    }
    p->clear();
    pi++;
  }
  ++updates;
}

} // namespace cnn
<|endoftext|>


<commit_before>#include <algorithm>
#include <assert.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <exception>
#include <iostream>
#include "Map.h"
#include "MapManager.h"
#include "utils.h"
#include "Create.h"
#include "Create_Enums.h"
#include "File.h"

MapManager::MapManager(): map(nullptr) {}

void MapManager::closeMap() {
  delete map;
  map = nullptr;
}

void MapManager::openMap(int mapNum) {
  using namespace Maps;
  Map* loadMap = Create::newMap(mapNum);
  setMap( loadMap );
}

void MapManager::setMap(Maps::Map* map) {
  if (this->map != nullptr) {
    delete map;
  }
  this->map = map;
}

void MapManager::play() {
  assert( map != nullptr );
  while ( true ) // TODO: Make variable for this
  {
    map->activate();

    if (tempMap != nullptr) {
      std::swap(tempMap, map);
      delete tempMap;
      tempMap = nullptr;
    }
  }

}

void MapManager::save(const std::string &fileName) {
  assert(map != nullptr);
  map->save();
  File::save(fileName);
}

void MapManager::load(const std::string &fileName) {
  using namespace File;
  using namespace boost::property_tree;

  fs::fstream file;
  fs::path filePath = savePath;
  filePath /= fs::path{fileName};

  if (file.is_open()) { file.close(); }
  // make tree and load from file
  treeType loadTree;
  try {
    file.open( filePath, std::fstream::in );
    xml_parser::read_xml(file, loadTree, xml_parser::trim_whitespace);
  } catch (std::exception &e) {
    std::cerr << e.what();
  }

  auto it = loadTree.begin();
  while (it != loadTree.end()) {
    const std::string &key = it->first;
    const std::string &data = it->second.data();
    if (key == "Map") {
      delete tempMap; // just in case
      tempMap = Create::newMap(*it);
    }
    it++;
  }
  // tempMap and map are swapped automatically later.
}
<commit_msg>MapManager load<commit_after>#include <algorithm>
#include <assert.h>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <exception>
#include <iostream>
#include "Map.h"
#include "MapManager.h"
#include "utils.h"
#include "Create.h"
#include "Create_Enums.h"
#include "File.h"

MapManager::MapManager(): map(nullptr) {}

void MapManager::closeMap() {
  delete map;
  map = nullptr;
}

void MapManager::openMap(int mapNum) {
  using namespace Maps;
  Map* loadMap = Create::newMap(mapNum);
  setMap( loadMap );
}

void MapManager::setMap(Maps::Map* map) {
  if (this->map != nullptr) {
    delete map;
  }
  this->map = map;
}

void MapManager::play() {
  assert( map != nullptr );
  while ( true ) // TODO: Make variable for this
  {
    map->activate();

    if (tempMap != nullptr) {
      std::swap(tempMap, map);
      delete tempMap;
      tempMap = nullptr;
    }
  }

}

void MapManager::save(const std::string &fileName) {
  assert(map != nullptr);
  map->save();
  File::save(fileName);
}

void MapManager::load(const std::string &fileName) {
    File::load(fileName);

    // tempMap and map are swapped automatically later.
    delete tempMap;
    tempMap = Create::loadNewMap();
}
<|endoftext|>


<commit_before>#ifndef VEXCL_BACKEND_OPENCL_COMPILER_HPP
#define VEXCL_BACKEND_OPENCL_COMPILER_HPP

/*
The MIT License

Copyright (c) 2012-2016 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   vexcl/backend/opencl/compiler.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  OpenCL source code compilation wrapper.
 */

#include <cstdlib>

#include <boost/thread.hpp>

#include <vexcl/backend/common.hpp>
#include <vexcl/detail/backtrace.hpp>

#include <vexcl/backend/opencl/defines.hpp>
#include <CL/cl.hpp>

namespace vex {
namespace backend {
namespace opencl {

/// Saves program binaries for future reuse.
inline void save_program_binaries(
        const std::string &hash, const cl::Program &program
        )
{
    // Prevent writing to the same file by several threads at the same time.
    static boost::mutex mx;
    boost::lock_guard<boost::mutex> lock(mx);

    std::ofstream bfile(program_binaries_path(hash, true) + "kernel", std::ios::binary);
    if (!bfile) return;

    std::vector<size_t> sizes    = program.getInfo<CL_PROGRAM_BINARY_SIZES>();
    std::vector<char*>  binaries = program.getInfo<CL_PROGRAM_BINARIES>();

    assert(sizes.size() == 1);

    bfile.write((char*)&sizes[0], sizeof(size_t));
    bfile.write(binaries[0], sizes[0]);
    delete[] binaries[0];
}

/// Tries to read program binaries from file cache.
inline boost::optional<cl::Program> load_program_binaries(
        const std::string &hash, const cl::Context &context,
        const std::vector<cl::Device> &device,
        const std::string &options = ""
        )
{
    std::ifstream bfile(program_binaries_path(hash) + "kernel", std::ios::binary);
    if (!bfile) return boost::optional<cl::Program>();

    size_t n;
    std::vector<char> buf;

    bfile.read((char*)&n, sizeof(size_t));
    buf.resize(n);
    bfile.read(buf.data(), n);

    cl::Program program(context, device, cl::Program::Binaries(
 -                1, std::make_pair(static_cast<const void*>(buf.data()), n)));

    try {
        program.build(device, options.c_str());
    } catch(const cl::Error&) {
        std::cerr << "Loading binaries failed:" << std::endl
            << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0])
            << std::endl;
        return boost::optional<cl::Program>();
    }

    return boost::optional<cl::Program>(program);
}

/// Create and build a program from source string.
/**
 * If VEXCL_CACHE_KERNELS macro is defined, then program binaries are cached
 * in filesystem and reused in the following runs.
 */
inline cl::Program build_sources(
        const cl::CommandQueue &queue, const std::string &source,
        const std::string &options = ""
        )
{
#ifdef VEXCL_SHOW_KERNELS
    std::cout << source << std::endl;
#else
#  ifdef _MSC_VER
#    pragma warning(push)
#    pragma warning(disable: 4996)
#  endif
    if (getenv("VEXCL_SHOW_KERNELS"))
        std::cout << source << std::endl;
#  ifdef _MSC_VER
#    pragma warning(pop)
#  endif
#endif

    auto context = queue.getInfo<CL_QUEUE_CONTEXT>();
    auto device  = context.getInfo<CL_CONTEXT_DEVICES>();

    std::string compile_options = options + " " + get_compile_options(queue);

#ifdef VEXCL_CACHE_KERNELS
    // Get unique (hopefully) hash string for the kernel.
    std::ostringstream compiler_tag;
    compiler_tag
#if defined(_MSC_VER)
        << "MSC " << _MSC_VER
#elif defined(__clang__)
        << "Clang " << __clang_major__ << "." << __clang_minor__
#elif defined(__GNUC__)
        << "g++ " << __GNUC__ << "." << __GNUC_MINOR__
#else
        << "unknown"
#endif
        ;

    sha1_hasher sha1;
    sha1.process(source)
        .process(cl::Platform(device[0].getInfo<CL_DEVICE_PLATFORM>()).getInfo<CL_PLATFORM_NAME>())
        .process(device[0].getInfo<CL_DEVICE_NAME>())
        .process(compile_options)
        .process(compiler_tag.str())
        ;

    std::string hash = static_cast<std::string>(sha1);

    // Try to get cached program binaries:
    try {
        if (boost::optional<cl::Program> program = load_program_binaries(hash, context, device, compile_options))
            return *program;
    } catch (...) {
        // Shit happens.
        std::cerr << "Shit happened" << std::endl;
    }
#endif

    // If cache is not available, just compile the sources.
    cl::Program program(context, source);

    try {
        program.build(device, (options + " " + get_compile_options(queue)).c_str());
    } catch(const cl::Error&) {
        std::cerr << source
                  << std::endl
                  << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0])
                  << std::endl;

        vex::detail::print_backtrace();
        throw;
    }

#ifdef VEXCL_CACHE_KERNELS
    // Save program binaries for future reuse:
    save_program_binaries(hash, program);
#endif

    return program;
}

} // namespace opencl
} // namespace backend
} // namespace vex

#endif
<commit_msg>Fix an error in backend/opencl/compiler.hpp<commit_after>#ifndef VEXCL_BACKEND_OPENCL_COMPILER_HPP
#define VEXCL_BACKEND_OPENCL_COMPILER_HPP

/*
The MIT License

Copyright (c) 2012-2016 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   vexcl/backend/opencl/compiler.hpp
 * \author Denis Demidov <dennis.demidov@gmail.com>
 * \brief  OpenCL source code compilation wrapper.
 */

#include <cstdlib>

#include <boost/thread.hpp>

#include <vexcl/backend/common.hpp>
#include <vexcl/detail/backtrace.hpp>

#include <vexcl/backend/opencl/defines.hpp>
#include <CL/cl.hpp>

namespace vex {
namespace backend {
namespace opencl {

/// Saves program binaries for future reuse.
inline void save_program_binaries(
        const std::string &hash, const cl::Program &program
        )
{
    // Prevent writing to the same file by several threads at the same time.
    static boost::mutex mx;
    boost::lock_guard<boost::mutex> lock(mx);

    std::ofstream bfile(program_binaries_path(hash, true) + "kernel", std::ios::binary);
    if (!bfile) return;

    std::vector<size_t> sizes    = program.getInfo<CL_PROGRAM_BINARY_SIZES>();
    std::vector<char*>  binaries = program.getInfo<CL_PROGRAM_BINARIES>();

    assert(sizes.size() == 1);

    bfile.write((char*)&sizes[0], sizeof(size_t));
    bfile.write(binaries[0], sizes[0]);
    delete[] binaries[0];
}

/// Tries to read program binaries from file cache.
inline boost::optional<cl::Program> load_program_binaries(
        const std::string &hash, const cl::Context &context,
        const std::vector<cl::Device> &device,
        const std::string &options = ""
        )
{
    std::ifstream bfile(program_binaries_path(hash) + "kernel", std::ios::binary);
    if (!bfile) return boost::optional<cl::Program>();

    size_t n;
    std::vector<char> buf;

    bfile.read((char*)&n, sizeof(size_t));
    buf.resize(n);
    bfile.read(buf.data(), n);

    cl::Program program(context, device, cl::Program::Binaries(
                 1, std::make_pair(static_cast<const void*>(buf.data()), n)));

    try {
        program.build(device, options.c_str());
    } catch(const cl::Error&) {
        std::cerr << "Loading binaries failed:" << std::endl
            << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0])
            << std::endl;
        return boost::optional<cl::Program>();
    }

    return boost::optional<cl::Program>(program);
}

/// Create and build a program from source string.
/**
 * If VEXCL_CACHE_KERNELS macro is defined, then program binaries are cached
 * in filesystem and reused in the following runs.
 */
inline cl::Program build_sources(
        const cl::CommandQueue &queue, const std::string &source,
        const std::string &options = ""
        )
{
#ifdef VEXCL_SHOW_KERNELS
    std::cout << source << std::endl;
#else
#  ifdef _MSC_VER
#    pragma warning(push)
#    pragma warning(disable: 4996)
#  endif
    if (getenv("VEXCL_SHOW_KERNELS"))
        std::cout << source << std::endl;
#  ifdef _MSC_VER
#    pragma warning(pop)
#  endif
#endif

    auto context = queue.getInfo<CL_QUEUE_CONTEXT>();
    auto device  = context.getInfo<CL_CONTEXT_DEVICES>();

    std::string compile_options = options + " " + get_compile_options(queue);

#ifdef VEXCL_CACHE_KERNELS
    // Get unique (hopefully) hash string for the kernel.
    std::ostringstream compiler_tag;
    compiler_tag
#if defined(_MSC_VER)
        << "MSC " << _MSC_VER
#elif defined(__clang__)
        << "Clang " << __clang_major__ << "." << __clang_minor__
#elif defined(__GNUC__)
        << "g++ " << __GNUC__ << "." << __GNUC_MINOR__
#else
        << "unknown"
#endif
        ;

    sha1_hasher sha1;
    sha1.process(source)
        .process(cl::Platform(device[0].getInfo<CL_DEVICE_PLATFORM>()).getInfo<CL_PLATFORM_NAME>())
        .process(device[0].getInfo<CL_DEVICE_NAME>())
        .process(compile_options)
        .process(compiler_tag.str())
        ;

    std::string hash = static_cast<std::string>(sha1);

    // Try to get cached program binaries:
    try {
        if (boost::optional<cl::Program> program = load_program_binaries(hash, context, device, compile_options))
            return *program;
    } catch (...) {
        // Shit happens.
        std::cerr << "Failed to load precompiled binaries" << std::endl;
    }
#endif

    // If cache is not available, just compile the sources.
    cl::Program program(context, source);

    try {
        program.build(device, (options + " " + get_compile_options(queue)).c_str());
    } catch(const cl::Error&) {
        std::cerr << source
                  << std::endl
                  << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0])
                  << std::endl;

        vex::detail::print_backtrace();
        throw;
    }

#ifdef VEXCL_CACHE_KERNELS
    // Save program binaries for future reuse:
    save_program_binaries(hash, program);
#endif

    return program;
}

} // namespace opencl
} // namespace backend
} // namespace vex

#endif
<|endoftext|>


<commit_before>/* Copyright 2011 Dirk-Willem van Gulik, All Rights Reserved.
 *                dirkx(at)webweaving(dot)org
 *
  * 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.
 *
 * $Id: QuadratureAnalyserAnalyzerSettings.cpp 1037 2011-09-12 09:49:58Z dirkx $
 */

#include "QuadratureAnalyserAnalyzerSettings.h"
#include <AnalyzerHelpers.h>

QuadratureAnalyserAnalyzerSettings::QuadratureAnalyserAnalyzerSettings()
:	mInputChannelA( UNDEFINED_CHANNEL ),
	mInputChannelB( UNDEFINED_CHANNEL ),
	ticksPerRotation( 0 )
{
	mInputChannelAInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mInputChannelAInterface->SetTitleAndTooltip( "Quadrature A", "Standard Quadrature Decoder - input A (or left/cw/first)" );
	mInputChannelAInterface->SetChannel( mInputChannelA );

	mInputChannelBInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mInputChannelBInterface->SetTitleAndTooltip( "Quadrature B", "Standard Quadrature Decoder - input Bi (or right/ccw/last)" );
	mInputChannelBInterface->SetChannel( mInputChannelB );

	mTicksPerRotationInterface.reset( new AnalyzerSettingInterfaceInteger() );
	mTicksPerRotationInterface->SetTitleAndTooltip( "Impules/rotation",
		"Specify the number of changes per full revolution (or some other measure). Set to '0' to ignore - and not do speed/change calculations.");
	mTicksPerRotationInterface->SetMax( 1e12 );
	mTicksPerRotationInterface->SetMin( 0 );
	mTicksPerRotationInterface->SetInteger( ticksPerRotation);

	AddInterface( mInputChannelAInterface.get() );
	AddInterface( mInputChannelBInterface.get() );
	AddInterface( mTicksPerRotationInterface.get() );

	AddExportOption( 0, "Export as text/csv file" );
	AddExportExtension( 0, "text", "txt" );
	AddExportExtension( 0, "csv", "csv" );

	ClearChannels();
	AddChannel( mInputChannelA, "Quadrature A", false );
	AddChannel( mInputChannelB, "Quadrature B", false );
}

QuadratureAnalyserAnalyzerSettings::~QuadratureAnalyserAnalyzerSettings()
{
}

bool QuadratureAnalyserAnalyzerSettings::SetSettingsFromInterfaces()
{
	mInputChannelA = mInputChannelAInterface->GetChannel();
	mInputChannelB = mInputChannelBInterface->GetChannel();
	ticksPerRotation = mTicksPerRotationInterface->GetInteger();

	ClearChannels();
	AddChannel( mInputChannelA, "Quadrature A", true);
	AddChannel( mInputChannelB, "Quadrature B", true);

	return true;
}

void QuadratureAnalyserAnalyzerSettings::UpdateInterfacesFromSettings()
{
	mInputChannelAInterface->SetChannel( mInputChannelA );
	mInputChannelBInterface->SetChannel( mInputChannelB );
	mTicksPerRotationInterface->SetInteger( ticksPerRotation );
}

void QuadratureAnalyserAnalyzerSettings::LoadSettings( const char* settings )
{
	SimpleArchive text_archive;
	text_archive.SetString( settings );

	text_archive >> mInputChannelA;
	text_archive >> mInputChannelB;
	text_archive >> ticksPerRotation;

	ClearChannels();
        AddChannel( mInputChannelA, "Quadrature A", true);
        AddChannel( mInputChannelB, "Quadrature B", true);

	UpdateInterfacesFromSettings();
}

const char* QuadratureAnalyserAnalyzerSettings::SaveSettings()
{
	SimpleArchive text_archive;

	text_archive << mInputChannelA;
	text_archive << mInputChannelB;
	text_archive << ticksPerRotation;

	return SetReturnString( text_archive.GetString() );
}
<commit_msg>fix - rage of ticks per rotation setting was set to a number outside of the 32 bit integer range.<commit_after>/* Copyright 2011 Dirk-Willem van Gulik, All Rights Reserved.
 *                dirkx(at)webweaving(dot)org
 *
  * 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.
 *
 * $Id: QuadratureAnalyserAnalyzerSettings.cpp 1037 2011-09-12 09:49:58Z dirkx $
 */

#include <climits>

#include "QuadratureAnalyserAnalyzerSettings.h"
#include <AnalyzerHelpers.h>

QuadratureAnalyserAnalyzerSettings::QuadratureAnalyserAnalyzerSettings()
:	mInputChannelA( UNDEFINED_CHANNEL ),
	mInputChannelB( UNDEFINED_CHANNEL ),
	ticksPerRotation( 0 )
{
	mInputChannelAInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mInputChannelAInterface->SetTitleAndTooltip( "Quadrature A", "Standard Quadrature Decoder - input A (or left/cw/first)" );
	mInputChannelAInterface->SetChannel( mInputChannelA );

	mInputChannelBInterface.reset( new AnalyzerSettingInterfaceChannel() );
	mInputChannelBInterface->SetTitleAndTooltip( "Quadrature B", "Standard Quadrature Decoder - input Bi (or right/ccw/last)" );
	mInputChannelBInterface->SetChannel( mInputChannelB );

	mTicksPerRotationInterface.reset( new AnalyzerSettingInterfaceInteger() );
	mTicksPerRotationInterface->SetTitleAndTooltip( "Impules/rotation",
		"Specify the number of changes per full revolution (or some other measure). Set to '0' to ignore - and not do speed/change calculations.");
	mTicksPerRotationInterface->SetMax( INT_MAX );
	mTicksPerRotationInterface->SetMin( 0 );
	mTicksPerRotationInterface->SetInteger( ticksPerRotation);

	AddInterface( mInputChannelAInterface.get() );
	AddInterface( mInputChannelBInterface.get() );
	AddInterface( mTicksPerRotationInterface.get() );

	AddExportOption( 0, "Export as text/csv file" );
	AddExportExtension( 0, "text", "txt" );
	AddExportExtension( 0, "csv", "csv" );

	ClearChannels();
	AddChannel( mInputChannelA, "Quadrature A", false );
	AddChannel( mInputChannelB, "Quadrature B", false );
}

QuadratureAnalyserAnalyzerSettings::~QuadratureAnalyserAnalyzerSettings()
{
}

bool QuadratureAnalyserAnalyzerSettings::SetSettingsFromInterfaces()
{
	mInputChannelA = mInputChannelAInterface->GetChannel();
	mInputChannelB = mInputChannelBInterface->GetChannel();
	ticksPerRotation = mTicksPerRotationInterface->GetInteger();

	ClearChannels();
	AddChannel( mInputChannelA, "Quadrature A", true);
	AddChannel( mInputChannelB, "Quadrature B", true);

	return true;
}

void QuadratureAnalyserAnalyzerSettings::UpdateInterfacesFromSettings()
{
	mInputChannelAInterface->SetChannel( mInputChannelA );
	mInputChannelBInterface->SetChannel( mInputChannelB );
	mTicksPerRotationInterface->SetInteger( ticksPerRotation );
}

void QuadratureAnalyserAnalyzerSettings::LoadSettings( const char* settings )
{
	SimpleArchive text_archive;
	text_archive.SetString( settings );

	text_archive >> mInputChannelA;
	text_archive >> mInputChannelB;
	text_archive >> ticksPerRotation;

	ClearChannels();
        AddChannel( mInputChannelA, "Quadrature A", true);
        AddChannel( mInputChannelB, "Quadrature B", true);

	UpdateInterfacesFromSettings();
}

const char* QuadratureAnalyserAnalyzerSettings::SaveSettings()
{
	SimpleArchive text_archive;

	text_archive << mInputChannelA;
	text_archive << mInputChannelB;
	text_archive << ticksPerRotation;

	return SetReturnString( text_archive.GetString() );
}
<|endoftext|>