<commit_before>#pragma once

#ifndef RAZ_WINDOW_HPP
#define RAZ_WINDOW_HPP

#include <chrono>
#include <functional>
#include <memory>
#include <vector>

#include "glew/include/GL/glew.h"
#if defined(_WIN32)
#if defined(_MSC_VER)
#define NOMINMAX
#endif
#include "glew/include/GL/wglew.h"
#elif defined(__gnu_linux__)
#include "glew/include/GL/glxew.h"
#endif
#include "glfw/include/GLFW/glfw3.h"
#include "RaZ/Math/Vector.hpp"
#include "RaZ/Utils/Image.hpp"
#include "RaZ/Utils/Overlay.hpp"
#include "RaZ/Utils/Input.hpp"

namespace Raz {

class Window;
using WindowPtr = std::unique_ptr<Window>;

using KeyboardCallbacks    = std::vector<std::tuple<int, std::function<void(float)>, Input::ActionTrigger, std::function<void()>>>;
using MouseButtonCallbacks = std::vector<std::tuple<int, std::function<void(float)>, Input::ActionTrigger, std::function<void()>>>;
using MouseScrollCallback  = std::function<void(double, double)>;
using MouseMoveCallback    = std::tuple<double, double, std::function<void(double, double)>>;
using InputActions         = std::unordered_map<int, std::pair<std::function<void(float)>, Input::ActionTrigger>>;
using InputCallbacks       = std::tuple<KeyboardCallbacks, MouseButtonCallbacks, MouseScrollCallback, MouseMoveCallback, InputActions>;

class Window {
public:
  Window(unsigned int width, unsigned int height, const std::string& title = "", uint8_t AASampleCount = 1);

  unsigned int getWidth() const { return m_width; }
  unsigned int getHeight() const { return m_height; }
  const Vec4f& getClearColor() const { return m_clearColor; }

  void setClearColor(const Vec4f& clearColor) { m_clearColor = clearColor; }
  void setClearColor(float red, float green, float blue, float alpha = 1.f) { setClearColor(Vec4f({ red, green, blue, alpha })); }
  void setTitle(const std::string& title) const { glfwSetWindowTitle(m_window, title.c_str()); }
  void setIcon(const Image& img) const;
  void setIcon(const std::string& fileName) const { setIcon(Image(fileName, true)); }

  template <typename... Args> static WindowPtr create(Args&&... args) { return std::make_unique<Window>(std::forward<Args>(args)...); }

  void enableFaceCulling(bool value = true) const;
  void disableFaceCulling() const { enableFaceCulling(false); }
  bool recoverVerticalSyncState() const;
  void enableVerticalSync(bool value = true) const;
  void disableVerticalSync() const { enableVerticalSync(false); }
  void changeCursorState(Cursor::State state) const { glfwSetInputMode(m_window, GLFW_CURSOR, state); }
  void showCursor() const { changeCursorState(Cursor::State::NORMAL); }
  void hideCursor() const { changeCursorState(Cursor::State::HIDDEN); }
  void disableCursor() const { changeCursorState(Cursor::State::DISABLED); }
  void addKeyCallback(Keyboard::Key key, std::function<void(float)> actionPress,
                                         Input::ActionTrigger frequency = Input::ALWAYS,
                                         std::function<void()> actionRelease = nullptr);
  void addMouseButtonCallback(Mouse::Button button, std::function<void(float)> actionPress,
                                                    Input::ActionTrigger frequency = Input::ALWAYS,
                                                    std::function<void()> actionRelease = nullptr);
  void addMouseScrollCallback(std::function<void(double, double)> func);
  void addMouseMoveCallback(std::function<void(double, double)> func);
  void updateCallbacks() const;
  void enableOverlay() { m_overlay = Overlay::create(m_window); }
  void disableOverlay() { m_overlay.reset(); }
  void addOverlayElement(OverlayElementType type, const std::string& text,
                         std::function<void()> actionOn = nullptr, std::function<void()> actionOff = nullptr);
  void addOverlayText(const std::string& text);
  void addOverlayButton(const std::string& text, std::function<void()> action);
  void addOverlayCheckbox(const std::string& text, bool initVal, std::function<void()> actionOn, std::function<void()> actionOff);
  void addOverlaySeparator();
  void addOverlayFrameTime(const std::string& formattedText);
  void addOverlayFpsCounter(const std::string& formattedText);
  bool run(float deltaTime);
  Vec2f recoverMousePosition() const;
  void setShouldClose() const { glfwSetWindowShouldClose(m_window, true); }
  void close();

  ~Window() { close(); }

private:
  unsigned int m_width {};
  unsigned int m_height {};
  Vec4f m_clearColor = Vec4f({ 0.15f, 0.15f, 0.15f, 1.f });
  GLFWwindow* m_window {};
  InputCallbacks m_callbacks {};
  OverlayPtr m_overlay {};
};

} // namespace Raz

#endif // RAZ_WINDOW_HPP
<commit_msg>[Utils/Windows] Added documentation for the Window class<commit_after>#pragma once

#ifndef RAZ_WINDOW_HPP
#define RAZ_WINDOW_HPP

#include <chrono>
#include <functional>
#include <memory>
#include <vector>

#include "glew/include/GL/glew.h"
#if defined(_WIN32)
#if defined(_MSC_VER)
#define NOMINMAX
#endif
#include "glew/include/GL/wglew.h"
#elif defined(__gnu_linux__)
#include "glew/include/GL/glxew.h"
#endif
#include "glfw/include/GLFW/glfw3.h"
#include "RaZ/Math/Vector.hpp"
#include "RaZ/Utils/Image.hpp"
#include "RaZ/Utils/Overlay.hpp"
#include "RaZ/Utils/Input.hpp"

namespace Raz {

using KeyboardCallbacks    = std::vector<std::tuple<int, std::function<void(float)>, Input::ActionTrigger, std::function<void()>>>;
using MouseButtonCallbacks = std::vector<std::tuple<int, std::function<void(float)>, Input::ActionTrigger, std::function<void()>>>;
using MouseScrollCallback  = std::function<void(double, double)>;
using MouseMoveCallback    = std::tuple<double, double, std::function<void(double, double)>>;
using InputActions         = std::unordered_map<int, std::pair<std::function<void(float)>, Input::ActionTrigger>>;
using InputCallbacks       = std::tuple<KeyboardCallbacks, MouseButtonCallbacks, MouseScrollCallback, MouseMoveCallback, InputActions>;

/// Graphical window to render the scenes on, with input custom actions.
class Window {
public:
  Window(unsigned int width, unsigned int height, const std::string& title = "", uint8_t AASampleCount = 1);

  unsigned int getWidth() const { return m_width; }
  unsigned int getHeight() const { return m_height; }
  const Vec4f& getClearColor() const { return m_clearColor; }

  void setClearColor(const Vec4f& clearColor) { m_clearColor = clearColor; }
  void setClearColor(float red, float green, float blue, float alpha = 1.f) { setClearColor(Vec4f({ red, green, blue, alpha })); }
  void setTitle(const std::string& title) const { glfwSetWindowTitle(m_window, title.c_str()); }
  void setIcon(const Image& img) const;
  void setIcon(const std::string& fileName) const { setIcon(Image(fileName, true)); }

  /// Changes the face culling's state.
  /// Enables or disables face culling according to the given parameter.
  /// \param value Value to apply.
  void enableFaceCulling(bool value = true) const;
  /// Disables the face culling.
  void disableFaceCulling() const { enableFaceCulling(false); }
  /// Fetches the current vertical synchronization's state.
  /// \return True if vertical sync is enabled, false otherwise.
  bool recoverVerticalSyncState() const;
  /// Changes the vertical synchronization's state.
  /// Enables or disables vertical sync according to the given parameter.
  /// \param value Value to apply.
  void enableVerticalSync(bool value = true) const;
  /// Disables vertical synchronization.
  void disableVerticalSync() const { enableVerticalSync(false); }
  /// Changes the cursor's state.
  /// Defines the new behavior of the mouse's cursor, if it should be shown, hidden or disabled.
  /// The functions showCursor(), hideCursor() & disableCursor() can be used instead.
  /// \param state State to apply.
  void changeCursorState(Cursor::State state) const { glfwSetInputMode(m_window, GLFW_CURSOR, state); }
  /// Shows the mouse cursor.
  /// Default behavior.
  void showCursor() const { changeCursorState(Cursor::State::NORMAL); }
  /// Hides the mouse cursor.
  /// The cursor becomes invisible while being inside the window's frame. It can go out of the window.
  void hideCursor() const { changeCursorState(Cursor::State::HIDDEN); }
  /// Disables the mouse cursor.
  /// The cursor always goes back to the window's center and becomes totally invisible. It can't go out of the window.
  void disableCursor() const { changeCursorState(Cursor::State::DISABLED); }
  /// Defines an action on keyboard's key press & release.
  /// \param key Key triggering the given action(s).
  /// \param actionPress Action to be executed when the given key is pressed.
  /// \param frequency Frequency at which to execute the actions.
  /// \param actionRelease Action to be executed when the given key is released.
  void addKeyCallback(Keyboard::Key key, std::function<void(float)> actionPress,
                                         Input::ActionTrigger frequency = Input::ALWAYS,
                                         std::function<void()> actionRelease = nullptr);
  /// Defines an action on mouse button click or release.
  /// \param button Button triggering the given action(s).
  /// \param actionPress Action to be executed when the given mouse button is pressed.
  /// \param frequency Frequency at which to execute the actions.
  /// \param actionRelease Action to be executed when the given mouse button is released.
  void addMouseButtonCallback(Mouse::Button button, std::function<void(float)> actionPress,
                                                    Input::ActionTrigger frequency = Input::ALWAYS,
                                                    std::function<void()> actionRelease = nullptr);
  /// Defines an action on mouse wheel scroll.
  /// \param func Action to be executed when scrolling.
  void addMouseScrollCallback(std::function<void(double, double)> func);
  /// Defines an action on mouse move.
  /// \param func Action to be executed when the mouse is moved.
  void addMouseMoveCallback(std::function<void(double, double)> func);
  /// Associates all of the callbacks, making them active.
  void updateCallbacks() const;
  /// Enables the overlay.
  void enableOverlay() { m_overlay = Overlay::create(m_window); }
  /// Disables the overlay.
  void disableOverlay() { m_overlay.reset(); }
  /// Adds an element on the overlay.
  /// \param type Type of the element to add.
  /// \param text Text to be displayed beside the element.
  /// \param actionOn Action to be executed when clicked or toggled on.
  /// \param actionOff Action to be executed when toggled off.
  void addOverlayElement(OverlayElementType type, const std::string& text,
                         std::function<void()> actionOn = nullptr, std::function<void()> actionOff = nullptr);
  /// Adds text on the overlay.
  /// \param text Text to be displayed.
  void addOverlayText(const std::string& text);
  /// Adds a button on the overlay.
  /// \param text Text to be displayed beside the button.
  /// \param action Action to be executed when clicked.
  void addOverlayButton(const std::string& text, std::function<void()> action);
  /// Adds a checkbox on the overlay.
  /// \param text Text to be displayed beside the checkbox.
  /// \param initVal Initial value, checked or not.
  /// \param actionOn Action to be executed when toggled on.
  /// \param actionOff Action to be executed when toggled off.
  void addOverlayCheckbox(const std::string& text, bool initVal, std::function<void()> actionOn, std::function<void()> actionOff);
  /// Adds an horizontal separator on the overlay.
  void addOverlaySeparator();
  /// Adds a frame time display on the overlay.
  /// \param formattedText Text with a formatting placeholder to display the frame time (%.Xf, X being the precision after the comma).
  void addOverlayFrameTime(const std::string& formattedText);
  /// Adds a FPS (frames per second) counter on the overlay.
  /// \param formattedText Text with a formatting placeholder to display the FPS (%.Xf, X being the precision after the comma).
  void addOverlayFpsCounter(const std::string& formattedText);
  /// Runs the window, refreshing its state by displaying the rendered scene, drawing the overlay, etc.
  /// \param deltaTime Amount of time elapsed since the last frame.
  /// \return True if the window hasn't been required to close, false otherwise.
  bool run(float deltaTime);
  /// Fetches the mouse position onto the window.
  /// \return 2D vector representing the mouse's position relative to the window.
  Vec2f recoverMousePosition() const;
  /// Tells the window that it should close.
  void setShouldClose() const { glfwSetWindowShouldClose(m_window, true); }
  /// Closes the window.
  void close();

  ~Window() { close(); }

private:
  unsigned int m_width {};
  unsigned int m_height {};
  Vec4f m_clearColor = Vec4f({ 0.15f, 0.15f, 0.15f, 1.f });
  GLFWwindow* m_window {};
  InputCallbacks m_callbacks {};
  OverlayPtr m_overlay {};
};

} // namespace Raz

#endif // RAZ_WINDOW_HPP
<|endoftext|>


<commit_before>/*
Copyright (c) 2013, Richard Martin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Richard Martin nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RICHARD MARTIN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef VectorSource_HEADER
#define VectorSource_HEADER

#include "DataSource.hpp"

namespace libsim
{

}

#endif<commit_msg>Remove incorrect vector file<commit_after><|endoftext|>


<commit_before>/*  XMMS2 - X Music Multiplexer System
 *  Copyright (C) 2003-2007 XMMS2 Team and Ma Xuan
 *
 *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
 *
 *  This library 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.
 *
 *  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.
 */

#include <mac/All.h>
#include <mac/MACLib.h>
#include <mac/APETag.h>
#include <mac/APEInfo.h>
#include <mac/CharacterHelper.h>

extern "C" {

#include "source_adapter.h"

#include "xmms/xmms_log.h"
#include "xmms/xmms_xformplugin.h"

#include <stdlib.h>
#include <stdio.h>

/*
 * Type Definitions
 */
typedef struct {
	guint start_time;

	IAPEDecompress *p_decompress;

	guint block_align;
	guint sample_rate;
	guint bits_per_sample;
	guint channels;
} xmms_mac_data_t;

typedef enum { STRING, INTEGER } ptype;
typedef struct {
	const gchar *vname;
	const gchar *xname;
	ptype type;
} props;

static const props properties[] = {
	{ "title",                XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE,     STRING  },
	{ "artist",               XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST,    STRING  },
	{ "album",                XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM,     STRING  },
	{ "tracknumber",          XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR,   INTEGER },
	{ "date",                 XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR,      STRING  },
	{ "year",                 XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR,      STRING  },
	{ "genre",                XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE,     STRING  },
	{ "comment",              XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT,   STRING  },
	{ "discnumber",           XMMS_MEDIALIB_ENTRY_PROPERTY_PARTOFSET, INTEGER }
};

/*
 * Function prototypes
 */

static gboolean xmms_mac_plugin_setup (xmms_xform_plugin_t *xform_plugin);

static void xmms_mac_destroy (xmms_xform_t *decoder);
static gboolean xmms_mac_init (xmms_xform_t *decoder);
static gint xmms_mac_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err);
static gint64 xmms_mac_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err);

static void xmms_mac_get_media_info (xmms_xform_t *decoder);

/*
 * Plugin header
 */

XMMS_XFORM_PLUGIN ("mac",
                   "Monkey's Audio", XMMS_VERSION,
                   "Monkey's Audio Decoder",
                   xmms_mac_plugin_setup);

}

static gboolean
xmms_mac_plugin_setup (xmms_xform_plugin_t *xform_plugin)
{
	xmms_xform_methods_t methods;

	XMMS_XFORM_METHODS_INIT (methods);

	methods.init = xmms_mac_init;
	methods.destroy = xmms_mac_destroy;
	methods.read = xmms_mac_read;
	methods.seek = xmms_mac_seek;

	xmms_xform_plugin_methods_set (xform_plugin, &methods);

	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "audio/x-ape",
	                              NULL);

	xmms_magic_add ("Monkey's Audio Magic", "audio/x-ape",
	                "0 string MAC ", NULL);

	return TRUE;
}

static gboolean
xmms_mac_init (xmms_xform_t *xform)
{
	xmms_mac_data_t *data;
	gint start_block = -1, end_block = -1;
	gint err = 0;
	CAPEInfo *ape_info = NULL;

	XMMS_DBG ("xmms_mac_init");

	g_return_val_if_fail (xform, FALSE);

	data = g_new0 (xmms_mac_data_t, 1);

	xmms_xform_private_data_set (xform, data);

	CSourceAdapter *source_adapter = new CSourceAdapter (xform);
	ape_info = new CAPEInfo (&err, source_adapter);

	/*
	 * Since we have to use a source adapter, so
	 * using this function to create the decompressor is the only way.
	 */
	data->p_decompress = CreateIAPEDecompressEx2 (ape_info, start_block, end_block, &err);

	data->block_align = data->p_decompress->GetInfo (APE_INFO_BLOCK_ALIGN);
	data->sample_rate = data->p_decompress->GetInfo (APE_INFO_SAMPLE_RATE);
	data->bits_per_sample = data->p_decompress->GetInfo (APE_INFO_BITS_PER_SAMPLE);
	data->channels = data->p_decompress->GetInfo (APE_INFO_CHANNELS);

	xmms_mac_get_media_info (xform);

	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm",
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_S16,
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             data->channels,
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             data->sample_rate,
	                             XMMS_STREAM_TYPE_END);

	return TRUE;
}

static void
xmms_mac_destroy (xmms_xform_t *xform)
{
	xmms_mac_data_t *data;

	XMMS_DBG ("xmms_mac_destroy");
	g_return_if_fail (xform);

	data = (xmms_mac_data_t *)xmms_xform_private_data_get (xform);
	g_return_if_fail (data);

	if (data->p_decompress) {
		delete data->p_decompress;
	}

	g_free (data);
}

static void
xmms_mac_get_media_info (xmms_xform_t *xform)
{
	xmms_mac_data_t *data;
	xmms_error_t error;

	XMMS_DBG ("xmms_mac_get_media_info");

	g_return_if_fail (xform);

	data = (xmms_mac_data_t *)xmms_xform_private_data_get (xform);

	xmms_error_reset (&error);

	/* Meta information */

	CAPETag *p_ape_tag = (CAPETag *)(data->p_decompress->GetInfo (APE_INFO_TAG));

	BOOL bHasID3Tag = p_ape_tag->GetHasID3Tag ();
	BOOL bHasAPETag = p_ape_tag->GetHasAPETag ();

	if (bHasID3Tag || bHasAPETag) {
		CAPETagField * pTagField;
		int index = 0;
		while ((pTagField = p_ape_tag->GetTagField (index)) != NULL) {
			index ++;

			const wchar_t *field_name;
			char field_value[255];

			gchar *name;

			field_name = pTagField->GetFieldName ();
			name = (gchar *)GetUTF8FromUTF16 (field_name);

			memset (field_value, 0, 255);
			int size = 255;
			p_ape_tag->GetFieldString (field_name, (char *)field_value, &size, TRUE);

			guint i = 0;
			for (i = 0; i < G_N_ELEMENTS (properties); i++) {
				if (g_strcasecmp (name, properties[i].vname) == 0) {
					if (properties[i].type == INTEGER) {
						gint tmp = strtol (field_value, NULL, 10);
						xmms_xform_metadata_set_int (xform,
						                             properties[i].xname,
						                             tmp);
					} else {
						xmms_xform_metadata_set_str (xform,
						                             properties[i].xname,
						                             field_value);
					}
					break;
				}
			}
			if (i >= G_N_ELEMENTS (properties)) {
				xmms_xform_metadata_set_str (xform, name, field_value);
			}
			g_free (name);
		}
	}

	gchar *name, *value, *metakey;
	gint filesize;

	metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE;
	if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) {
		gint duration = data->p_decompress->GetInfo (APE_DECOMPRESS_LENGTH_MS);
		metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION;
		xmms_xform_metadata_set_int (xform, metakey, duration);
	}

	/* Technical Information */

	/* APE Version */
	name = "Version";
	value = g_strdup_printf ("%.2f", (float) data->p_decompress->GetInfo (APE_INFO_FILE_VERSION) / float (1000));
	xmms_xform_metadata_set_str (xform, name, value);
	g_free (value);

	/* Compression Level */
	name = "Compression Level";
	switch (data->p_decompress->GetInfo (APE_INFO_COMPRESSION_LEVEL)) {
	case COMPRESSION_LEVEL_FAST:
		value = "Fast";
		break;
	case COMPRESSION_LEVEL_NORMAL:
		value = "Normal";
		break;
	case COMPRESSION_LEVEL_HIGH:
		value = "High";
		break;
	case COMPRESSION_LEVEL_EXTRA_HIGH:
		value = "Extra High";
		break;
	case COMPRESSION_LEVEL_INSANE:
		value = "Insane";
		break;
	}
	xmms_xform_metadata_set_str (xform, name, value);

	/* Format Flags */
	name = "Flags";
	xmms_xform_metadata_set_int (xform, name, data->p_decompress->GetInfo (APE_INFO_FORMAT_FLAGS));

	/* Average Bitrate */
	xmms_xform_metadata_set_int (xform,
	                             XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE,
	                             data->p_decompress->GetInfo (APE_INFO_AVERAGE_BITRATE));
}

static gint
xmms_mac_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err)
{
	xmms_mac_data_t *data;

	int blocks_to_read = 0, actrual_read = 0;
	int nRetVal = 0;

	data = (xmms_mac_data_t *)xmms_xform_private_data_get (xform);

	blocks_to_read = len / data->block_align;

	nRetVal = data->p_decompress->GetData ((gchar *)buf, blocks_to_read, &actrual_read);

	return actrual_read * data->block_align;
}

static gint64
xmms_mac_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err)
{
	xmms_mac_data_t *data;
	gint64 blocks;

	g_return_val_if_fail (xform, FALSE);

	data = (xmms_mac_data_t *)xmms_xform_private_data_get (xform);
	switch (whence) {
	case XMMS_XFORM_SEEK_CUR:
		blocks = data->p_decompress->GetInfo (APE_DECOMPRESS_CURRENT_BLOCK);
		blocks += samples;
		break;
	case XMMS_XFORM_SEEK_SET:
		blocks = samples;
		break;
	case XMMS_XFORM_SEEK_END:
		blocks = data->p_decompress->GetInfo (APE_DECOMPRESS_TOTAL_BLOCKS);
		blocks += samples;
		break;
	}
	data->p_decompress->Seek (blocks);

	return blocks;
}

<commit_msg>BUG(1778): Fix crash in mac plugin on files without ape tag<commit_after>/*  XMMS2 - X Music Multiplexer System
 *  Copyright (C) 2003-2007 XMMS2 Team and Ma Xuan
 *
 *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
 *
 *  This library 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.
 *
 *  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.
 */

#include <mac/All.h>
#include <mac/MACLib.h>
#include <mac/APETag.h>
#include <mac/APEInfo.h>
#include <mac/CharacterHelper.h>

extern "C" {

#include "source_adapter.h"

#include "xmms/xmms_log.h"
#include "xmms/xmms_xformplugin.h"

#include <stdlib.h>
#include <stdio.h>

/*
 * Type Definitions
 */
typedef struct {
	guint start_time;

	IAPEDecompress *p_decompress;

	guint block_align;
	guint sample_rate;
	guint bits_per_sample;
	guint channels;
} xmms_mac_data_t;

typedef enum { STRING, INTEGER } ptype;
typedef struct {
	const gchar *vname;
	const gchar *xname;
	ptype type;
} props;

static const props properties[] = {
	{ "title",                XMMS_MEDIALIB_ENTRY_PROPERTY_TITLE,     STRING  },
	{ "artist",               XMMS_MEDIALIB_ENTRY_PROPERTY_ARTIST,    STRING  },
	{ "album",                XMMS_MEDIALIB_ENTRY_PROPERTY_ALBUM,     STRING  },
	{ "tracknumber",          XMMS_MEDIALIB_ENTRY_PROPERTY_TRACKNR,   INTEGER },
	{ "date",                 XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR,      STRING  },
	{ "year",                 XMMS_MEDIALIB_ENTRY_PROPERTY_YEAR,      STRING  },
	{ "genre",                XMMS_MEDIALIB_ENTRY_PROPERTY_GENRE,     STRING  },
	{ "comment",              XMMS_MEDIALIB_ENTRY_PROPERTY_COMMENT,   STRING  },
	{ "discnumber",           XMMS_MEDIALIB_ENTRY_PROPERTY_PARTOFSET, INTEGER }
};

/*
 * Function prototypes
 */

static gboolean xmms_mac_plugin_setup (xmms_xform_plugin_t *xform_plugin);

static void xmms_mac_destroy (xmms_xform_t *decoder);
static gboolean xmms_mac_init (xmms_xform_t *decoder);
static gint xmms_mac_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err);
static gint64 xmms_mac_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err);

static void xmms_mac_get_media_info (xmms_xform_t *decoder);

/*
 * Plugin header
 */

XMMS_XFORM_PLUGIN ("mac",
                   "Monkey's Audio", XMMS_VERSION,
                   "Monkey's Audio Decoder",
                   xmms_mac_plugin_setup);

}

static gboolean
xmms_mac_plugin_setup (xmms_xform_plugin_t *xform_plugin)
{
	xmms_xform_methods_t methods;

	XMMS_XFORM_METHODS_INIT (methods);

	methods.init = xmms_mac_init;
	methods.destroy = xmms_mac_destroy;
	methods.read = xmms_mac_read;
	methods.seek = xmms_mac_seek;

	xmms_xform_plugin_methods_set (xform_plugin, &methods);

	xmms_xform_plugin_indata_add (xform_plugin,
	                              XMMS_STREAM_TYPE_MIMETYPE,
	                              "audio/x-ape",
	                              NULL);

	xmms_magic_add ("Monkey's Audio Magic", "audio/x-ape",
	                "0 string MAC ", NULL);

	return TRUE;
}

static gboolean
xmms_mac_init (xmms_xform_t *xform)
{
	xmms_mac_data_t *data;
	gint start_block = -1, end_block = -1;
	gint err = 0;
	CAPEInfo *ape_info = NULL;

	XMMS_DBG ("xmms_mac_init");

	g_return_val_if_fail (xform, FALSE);

	data = g_new0 (xmms_mac_data_t, 1);

	xmms_xform_private_data_set (xform, data);

	CSourceAdapter *source_adapter = new CSourceAdapter (xform);
	ape_info = new CAPEInfo (&err, source_adapter);

	/*
	 * Since we have to use a source adapter, so
	 * using this function to create the decompressor is the only way.
	 */
	data->p_decompress = CreateIAPEDecompressEx2 (ape_info, start_block, end_block, &err);

	data->block_align = data->p_decompress->GetInfo (APE_INFO_BLOCK_ALIGN);
	data->sample_rate = data->p_decompress->GetInfo (APE_INFO_SAMPLE_RATE);
	data->bits_per_sample = data->p_decompress->GetInfo (APE_INFO_BITS_PER_SAMPLE);
	data->channels = data->p_decompress->GetInfo (APE_INFO_CHANNELS);

	xmms_mac_get_media_info (xform);

	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm",
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_S16,
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             data->channels,
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             data->sample_rate,
	                             XMMS_STREAM_TYPE_END);

	return TRUE;
}

static void
xmms_mac_destroy (xmms_xform_t *xform)
{
	xmms_mac_data_t *data;

	XMMS_DBG ("xmms_mac_destroy");
	g_return_if_fail (xform);

	data = (xmms_mac_data_t *)xmms_xform_private_data_get (xform);
	g_return_if_fail (data);

	if (data->p_decompress) {
		delete data->p_decompress;
	}

	g_free (data);
}

static void
xmms_mac_get_media_info (xmms_xform_t *xform)
{
	xmms_mac_data_t *data;
	xmms_error_t error;

	XMMS_DBG ("xmms_mac_get_media_info");

	g_return_if_fail (xform);

	data = (xmms_mac_data_t *)xmms_xform_private_data_get (xform);

	xmms_error_reset (&error);

	/* Meta information */

	CAPETag *p_ape_tag = (CAPETag *)(data->p_decompress->GetInfo (APE_INFO_TAG));

	if (p_ape_tag) {
		BOOL bHasID3Tag = p_ape_tag->GetHasID3Tag ();
		BOOL bHasAPETag = p_ape_tag->GetHasAPETag ();

		if (bHasID3Tag || bHasAPETag) {
			CAPETagField * pTagField;
			int index = 0;
			while ((pTagField = p_ape_tag->GetTagField (index)) != NULL) {
				index ++;

				const wchar_t *field_name;
				char field_value[255];

				gchar *name;

				field_name = pTagField->GetFieldName ();
				name = (gchar *)GetUTF8FromUTF16 (field_name);

				memset (field_value, 0, 255);
				int size = 255;
				p_ape_tag->GetFieldString (field_name, (char *)field_value, &size, TRUE);

				guint i = 0;
				for (i = 0; i < G_N_ELEMENTS (properties); i++) {
					if (g_strcasecmp (name, properties[i].vname) == 0) {
						if (properties[i].type == INTEGER) {
							gint tmp = strtol (field_value, NULL, 10);
							xmms_xform_metadata_set_int (xform,
														 properties[i].xname,
														 tmp);
						} else {
							xmms_xform_metadata_set_str (xform,
														 properties[i].xname,
														 field_value);
						}
						break;
					}
				}
				if (i >= G_N_ELEMENTS (properties)) {
					xmms_xform_metadata_set_str (xform, name, field_value);
				}
				g_free (name);
			}
		}
	}

	gchar *name, *value, *metakey;
	gint filesize;

	metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_SIZE;
	if (xmms_xform_metadata_get_int (xform, metakey, &filesize)) {
		gint duration = data->p_decompress->GetInfo (APE_DECOMPRESS_LENGTH_MS);
		metakey = XMMS_MEDIALIB_ENTRY_PROPERTY_DURATION;
		xmms_xform_metadata_set_int (xform, metakey, duration);
	}

	/* Technical Information */

	/* APE Version */
	name = "Version";
	value = g_strdup_printf ("%.2f", (float) data->p_decompress->GetInfo (APE_INFO_FILE_VERSION) / float (1000));
	xmms_xform_metadata_set_str (xform, name, value);
	g_free (value);

	/* Compression Level */
	name = "Compression Level";
	switch (data->p_decompress->GetInfo (APE_INFO_COMPRESSION_LEVEL)) {
	case COMPRESSION_LEVEL_FAST:
		value = "Fast";
		break;
	case COMPRESSION_LEVEL_NORMAL:
		value = "Normal";
		break;
	case COMPRESSION_LEVEL_HIGH:
		value = "High";
		break;
	case COMPRESSION_LEVEL_EXTRA_HIGH:
		value = "Extra High";
		break;
	case COMPRESSION_LEVEL_INSANE:
		value = "Insane";
		break;
	}
	xmms_xform_metadata_set_str (xform, name, value);

	/* Format Flags */
	name = "Flags";
	xmms_xform_metadata_set_int (xform, name, data->p_decompress->GetInfo (APE_INFO_FORMAT_FLAGS));

	/* Average Bitrate */
	xmms_xform_metadata_set_int (xform,
	                             XMMS_MEDIALIB_ENTRY_PROPERTY_BITRATE,
	                             data->p_decompress->GetInfo (APE_INFO_AVERAGE_BITRATE));
}

static gint
xmms_mac_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err)
{
	xmms_mac_data_t *data;

	int blocks_to_read = 0, actrual_read = 0;
	int nRetVal = 0;

	data = (xmms_mac_data_t *)xmms_xform_private_data_get (xform);

	blocks_to_read = len / data->block_align;

	nRetVal = data->p_decompress->GetData ((gchar *)buf, blocks_to_read, &actrual_read);

	return actrual_read * data->block_align;
}

static gint64
xmms_mac_seek (xmms_xform_t *xform, gint64 samples, xmms_xform_seek_mode_t whence, xmms_error_t *err)
{
	xmms_mac_data_t *data;
	gint64 blocks;

	g_return_val_if_fail (xform, FALSE);

	data = (xmms_mac_data_t *)xmms_xform_private_data_get (xform);
	switch (whence) {
	case XMMS_XFORM_SEEK_CUR:
		blocks = data->p_decompress->GetInfo (APE_DECOMPRESS_CURRENT_BLOCK);
		blocks += samples;
		break;
	case XMMS_XFORM_SEEK_SET:
		blocks = samples;
		break;
	case XMMS_XFORM_SEEK_END:
		blocks = data->p_decompress->GetInfo (APE_DECOMPRESS_TOTAL_BLOCKS);
		blocks += samples;
		break;
	}
	data->p_decompress->Seek (blocks);

	return blocks;
}

<|endoftext|>


<commit_before>#pragma once
/**
	@file
	@brief bit vector
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <cybozu/exception.hpp>
#include <algorithm>
#include <vector>
#include <assert.h>

namespace cybozu {

template<class T>
size_t RoundupBit(size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	return (bitLen + unitSize - 1) / unitSize;
}

template<class T>
T GetMaskBit(size_t bitLen)
{
	assert(bitLen < sizeof(T) * 8);
	return (T(1) << bitLen) - 1;
}

template<class T>
void SetBlockBit(T *buf, size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	const size_t q = bitLen / unitSize;
	const size_t r = bitLen % unitSize;
	buf[q] |= T(1) << r;
}
template<class T>
void ResetBlockBit(T *buf, size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	const size_t q = bitLen / unitSize;
	const size_t r = bitLen % unitSize;
	buf[q] &= ~(T(1) << r);
}
template<class T>
bool GetBlockBit(const T *buf, size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	const size_t q = bitLen / unitSize;
	const size_t r = bitLen % unitSize;
	return (buf[q] & (T(1) << r)) != 0;
}

template<class T>
void CopyBit(T* dst, const T* src, size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	const size_t q = bitLen / unitSize;
	const size_t r = bitLen % unitSize;
	for (size_t i = 0; i < q; i++) dst[i] = src[i];
	if (r == 0) return;
	dst[q] = src[q] & GetMaskBit<T>(r);
}
/*
	dst[] = (src[] << shift) | ext
	@param dst [out] dst[0..n)
	@param src [in] src[0..n)
	@param bitLen [in] length of src, dst
	@param shift [in] 0 <= shift < unitSize
	@param ext [in] or bit
*/
template<class T>
T ShiftLeftBit(T* dst, const T* src, size_t bitLen, size_t shift, T ext = 0)
{
	if (bitLen == 0) return 0;
	const size_t unitSize = sizeof(T) * 8;
	if (shift >= unitSize) {
		throw cybozu::Exception("ShiftLeftBit:large shift") << shift;
	}
	const size_t n = RoundupBit<T>(bitLen); // n >= 1 because bitLen > 0
	const size_t r = bitLen % unitSize;
	const T mask = r > 0 ? GetMaskBit<T>(r) : T(-1);
	if (shift == 0) {
		if (n == 1) {
			dst[0] = (src[0] & mask) | ext;
		} else {
			dst[n - 1] = src[n - 1] & mask;
			for (size_t i = n - 2; i > 0; i--) {
				dst[i] = src[i];
			}
			dst[0] = src[0] | ext;
		}
		return 0;
	}
	const size_t revShift = unitSize - shift;
	T prev = src[n - 1] & mask;
	const T ret = prev >> revShift;
	for (size_t i = n - 1; i > 0; i--) {
		T v = src[i - 1];
		dst[i] = (prev << shift) | (v >> revShift);
		prev = v;
	}
	dst[0] = (prev << shift) | ext;
	return ret;
}
/*
	dst[] = src[] >> shift
	@param dst [out] dst[0..n)
	@param src [in] src[0..n)
	@param bitLen [in] length of src, dst
	@param shift [in] 0 <= shift < (sizeof(T) * 8)
*/
template<class T>
void ShiftRightBit(T* dst, const T* src, size_t bitLen, size_t shift)
{
	if (bitLen == 0) return;
	const size_t unitSize = sizeof(T) * 8;
	if (shift >= unitSize) {
		throw cybozu::Exception("ShiftRightBit:bad shift") << shift;
	}
	if (shift == 0) {
		CopyBit<T>(dst, src, bitLen);
		return;
	}
	const size_t n = RoundupBit<T>(bitLen); // n >= 1 because bitLen > 0
	const size_t r = bitLen % unitSize;
	const T mask = r ? GetMaskBit<T>(r) : T(-1);
	const size_t revShift = unitSize - shift;
	if (n == 1) {
		dst[0] = (src[0] & mask) >> shift;
		return;
	}
	T prev = src[0];
	for (size_t i = 0; i < n - 2; i++) {
		T v = src[i + 1];
		dst[i] = (prev >> shift) | (v << revShift);
		prev = v;
	}
	{ // i = n - 1
		T v = src[n - 1] & mask;
		dst[n - 2] = (prev >> shift) | (v << revShift);
		prev = v;
	}
	dst[n - 1] = prev >> shift;
}

template<class T>
class BitVectorT {
	static const size_t unitSize = sizeof(T) * 8;
	size_t bitLen_;
	std::vector<T> v_;
public:
	BitVectorT() : bitLen_(0) {}
	BitVectorT(const T *buf, size_t bitLen)
	{
		init(buf, bitLen);
	}
	void init(const T *buf, size_t bitLen)
	{
		resize(bitLen);
		std::copy(buf, buf + v_.size(), &v_[0]);
	}
	void resize(size_t bitLen)
	{
		bitLen_ = bitLen;
		const size_t q = bitLen / unitSize;
		const size_t r = bitLen % unitSize;
		if (r == 0) {
			v_.resize(q);
		} else {
			// ensure zero out of [0, bitLen)
			v_.resize(q + 1);
			T mask = GetMaskBit<T>(r);
			v_[q] &= mask;
		}
	}
	void reserve(size_t bitLen)
	{
		v_.reserve(RoundupBit<T>(bitLen));
	}
	bool get(size_t idx) const
	{
		if (idx >= bitLen_) throw cybozu::Exception("BitVectorT:get:bad idx") << idx;
		return GetBlockBit(v_.data(), idx);
	}
	void clear()
	{
		bitLen_ = 0;
		v_.clear();
	}
	void set(size_t idx, bool b)
	{
		if (b) {
			set(idx);
		} else {
			reset(idx);
		}
	}
	// set(idx, true);
	void set(size_t idx)
	{
		if (idx >= bitLen_) throw cybozu::Exception("BitVectorT:set:bad idx") << idx;
		SetBlockBit(v_.data(), idx);
	}
	// set(idx, false);
	void reset(size_t idx)
	{
		if (idx >= bitLen_) throw cybozu::Exception("BitVectorT:reset:bad idx") << idx;
		ResetBlockBit(v_.data(), idx);
	}
	size_t size() const { return bitLen_; }
	const T *getBlock() const { return &v_[0]; }
	T *getBlock() { return &v_[0]; }
	size_t getBlockSize() const { return v_.size(); }
	/*
		append src[0, bitLen)
	*/
	void append(const T* src, size_t bitLen)
	{
		if (bitLen == 0) return;
		const size_t q = bitLen_ / unitSize;
		const size_t r = bitLen_ % unitSize;
		resize(bitLen_ + bitLen);
		if (r == 0) {
			CopyBit<T>(&v_[q], src, bitLen);
			return;
		}
		T over = ShiftLeftBit<T>(&v_[q], src, bitLen, r, v_[q] & GetMaskBit<T>(r));
		if (RoundupBit<T>(bitLen + r) > RoundupBit<T>(bitLen)) {
			v_[v_.size() - 1] = over;
		}
	}
	/*
		append src & mask(bitLen)
	*/
	void append(uint64_t src, size_t bitLen)
	{
		if (bitLen == 0) return;
		if (bitLen > unitSize) {
			throw cybozu::Exception("BitVectorT:append:bad bitLen") << bitLen;
		}
		if (bitLen < unitSize) {
			src &= GetMaskBit<T>(bitLen);
		}
		const size_t q = bitLen_ / unitSize;
		const size_t r = bitLen_ % unitSize;
		resize(bitLen_ + bitLen);
		if (r == 0) {
			v_[q] = T(src);
			return;
		}
		v_[q] |= T(src << r);
		v_[q + 1] = T(src >> (unitSize - r));
	}
	/*
		append bitVector
	*/
	void append(const BitVectorT<T>& v)
	{
		append(v.getBlock(), v.size());
	}
	/*
		dst[0, bitLen) = vec[pos, pos + bitLen)
	*/
	void extract(T* dst, size_t pos, size_t bitLen) const
	{
		if (bitLen == 0) return;
		if (pos + bitLen > bitLen_) {
			throw cybozu::Exception("BitVectorT:extract:bad range") << bitLen << pos << bitLen_;
		}
		const size_t q = pos / unitSize;
		const size_t r = pos % unitSize;
		if (r == 0) {
			CopyBit<T>(dst, &v_[q], bitLen);
			return;
		}
		ShiftRightBit<T>(dst, &v_[q], bitLen + r, r);
	}
	/*
		dst = vec[pos, pos + bitLen)
	*/
	void extract(BitVectorT<T>& dst, size_t pos, size_t bitLen) const
	{
		dst.resize(bitLen);
		extract(dst.getBlock(), pos, bitLen);
	}
	/*
		return vec[pos, pos + bitLen)
	*/
	T extract(size_t pos, size_t bitLen) const
	{
		if (bitLen == 0) return 0;
		if (bitLen > unitSize || pos + bitLen > bitLen_) {
			throw cybozu::Exception("BitVectorT:extract:bad range") << bitLen << pos << bitLen_;
		}
		const size_t q = pos / unitSize;
		const size_t r = pos % unitSize;
		T v;
		if (r == 0) {
			v = v_[q];
		} else {
			v = (v_[q] >> r) | v_[q + 1] << (unitSize - r);
		}
		if (bitLen == unitSize) {
			return v;
		} else {
			return v & GetMaskBit<T>(bitLen);
		}
	}
	bool operator==(const BitVectorT<T>& rhs) const { return v_ == rhs.v_; }
	bool operator!=(const BitVectorT<T>& rhs) const { return v_ != rhs.v_; }
};

typedef BitVectorT<size_t> BitVector;

} // cybozu
<commit_msg>clear if decrese size<commit_after>#pragma once
/**
	@file
	@brief bit vector
	@author MITSUNARI Shigeo(@herumi)
	@license modified new BSD license
	http://opensource.org/licenses/BSD-3-Clause
*/
#include <cybozu/exception.hpp>
#include <algorithm>
#include <vector>
#include <assert.h>

namespace cybozu {

template<class T>
size_t RoundupBit(size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	return (bitLen + unitSize - 1) / unitSize;
}

template<class T>
T GetMaskBit(size_t bitLen)
{
	assert(bitLen < sizeof(T) * 8);
	return (T(1) << bitLen) - 1;
}

template<class T>
void SetBlockBit(T *buf, size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	const size_t q = bitLen / unitSize;
	const size_t r = bitLen % unitSize;
	buf[q] |= T(1) << r;
}
template<class T>
void ResetBlockBit(T *buf, size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	const size_t q = bitLen / unitSize;
	const size_t r = bitLen % unitSize;
	buf[q] &= ~(T(1) << r);
}
template<class T>
bool GetBlockBit(const T *buf, size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	const size_t q = bitLen / unitSize;
	const size_t r = bitLen % unitSize;
	return (buf[q] & (T(1) << r)) != 0;
}

template<class T>
void CopyBit(T* dst, const T* src, size_t bitLen)
{
	const size_t unitSize = sizeof(T) * 8;
	const size_t q = bitLen / unitSize;
	const size_t r = bitLen % unitSize;
	for (size_t i = 0; i < q; i++) dst[i] = src[i];
	if (r == 0) return;
	dst[q] = src[q] & GetMaskBit<T>(r);
}
/*
	dst[] = (src[] << shift) | ext
	@param dst [out] dst[0..n)
	@param src [in] src[0..n)
	@param bitLen [in] length of src, dst
	@param shift [in] 0 <= shift < unitSize
	@param ext [in] or bit
*/
template<class T>
T ShiftLeftBit(T* dst, const T* src, size_t bitLen, size_t shift, T ext = 0)
{
	if (bitLen == 0) return 0;
	const size_t unitSize = sizeof(T) * 8;
	if (shift >= unitSize) {
		throw cybozu::Exception("ShiftLeftBit:large shift") << shift;
	}
	const size_t n = RoundupBit<T>(bitLen); // n >= 1 because bitLen > 0
	const size_t r = bitLen % unitSize;
	const T mask = r > 0 ? GetMaskBit<T>(r) : T(-1);
	if (shift == 0) {
		if (n == 1) {
			dst[0] = (src[0] & mask) | ext;
		} else {
			dst[n - 1] = src[n - 1] & mask;
			for (size_t i = n - 2; i > 0; i--) {
				dst[i] = src[i];
			}
			dst[0] = src[0] | ext;
		}
		return 0;
	}
	const size_t revShift = unitSize - shift;
	T prev = src[n - 1] & mask;
	const T ret = prev >> revShift;
	for (size_t i = n - 1; i > 0; i--) {
		T v = src[i - 1];
		dst[i] = (prev << shift) | (v >> revShift);
		prev = v;
	}
	dst[0] = (prev << shift) | ext;
	return ret;
}
/*
	dst[] = src[] >> shift
	@param dst [out] dst[0..n)
	@param src [in] src[0..n)
	@param bitLen [in] length of src, dst
	@param shift [in] 0 <= shift < (sizeof(T) * 8)
*/
template<class T>
void ShiftRightBit(T* dst, const T* src, size_t bitLen, size_t shift)
{
	if (bitLen == 0) return;
	const size_t unitSize = sizeof(T) * 8;
	if (shift >= unitSize) {
		throw cybozu::Exception("ShiftRightBit:bad shift") << shift;
	}
	if (shift == 0) {
		CopyBit<T>(dst, src, bitLen);
		return;
	}
	const size_t n = RoundupBit<T>(bitLen); // n >= 1 because bitLen > 0
	const size_t r = bitLen % unitSize;
	const T mask = r ? GetMaskBit<T>(r) : T(-1);
	const size_t revShift = unitSize - shift;
	if (n == 1) {
		dst[0] = (src[0] & mask) >> shift;
		return;
	}
	T prev = src[0];
	for (size_t i = 0; i < n - 2; i++) {
		T v = src[i + 1];
		dst[i] = (prev >> shift) | (v << revShift);
		prev = v;
	}
	{ // i = n - 1
		T v = src[n - 1] & mask;
		dst[n - 2] = (prev >> shift) | (v << revShift);
		prev = v;
	}
	dst[n - 1] = prev >> shift;
}

template<class T>
class BitVectorT {
	static const size_t unitSize = sizeof(T) * 8;
	size_t bitLen_;
	std::vector<T> v_;
public:
	BitVectorT() : bitLen_(0) {}
	BitVectorT(const T *buf, size_t bitLen)
	{
		init(buf, bitLen);
	}
	void init(const T *buf, size_t bitLen)
	{
		resize(bitLen);
		std::copy(buf, buf + v_.size(), &v_[0]);
	}
	void resize(size_t bitLen)
	{
		bitLen_ = bitLen;
		const size_t q = bitLen / unitSize;
		const size_t r = bitLen % unitSize;
		if (r == 0) {
			v_.resize(q);
		} else {
			// ensure zero out of [0, bitLen)
			v_.resize(q + 1);
			T v = v_[q];
			if (v > 0) {
				v_[q] = v & GetMaskBit<T>(r);
			}
		}
	}
	void reserve(size_t bitLen)
	{
		v_.reserve(RoundupBit<T>(bitLen));
	}
	bool get(size_t idx) const
	{
		if (idx >= bitLen_) throw cybozu::Exception("BitVectorT:get:bad idx") << idx;
		return GetBlockBit(v_.data(), idx);
	}
	void clear()
	{
		bitLen_ = 0;
		v_.clear();
	}
	void set(size_t idx, bool b)
	{
		if (b) {
			set(idx);
		} else {
			reset(idx);
		}
	}
	// set(idx, true);
	void set(size_t idx)
	{
		if (idx >= bitLen_) throw cybozu::Exception("BitVectorT:set:bad idx") << idx;
		SetBlockBit(v_.data(), idx);
	}
	// set(idx, false);
	void reset(size_t idx)
	{
		if (idx >= bitLen_) throw cybozu::Exception("BitVectorT:reset:bad idx") << idx;
		ResetBlockBit(v_.data(), idx);
	}
	size_t size() const { return bitLen_; }
	const T *getBlock() const { return &v_[0]; }
	T *getBlock() { return &v_[0]; }
	size_t getBlockSize() const { return v_.size(); }
	/*
		append src[0, bitLen)
	*/
	void append(const T* src, size_t bitLen)
	{
		if (bitLen == 0) return;
		const size_t q = bitLen_ / unitSize;
		const size_t r = bitLen_ % unitSize;
		resize(bitLen_ + bitLen);
		if (r == 0) {
			CopyBit<T>(&v_[q], src, bitLen);
			return;
		}
		T over = ShiftLeftBit<T>(&v_[q], src, bitLen, r, v_[q] & GetMaskBit<T>(r));
		if (RoundupBit<T>(bitLen + r) > RoundupBit<T>(bitLen)) {
			v_[v_.size() - 1] = over;
		}
	}
	/*
		append src & mask(bitLen)
	*/
	void append(uint64_t src, size_t bitLen)
	{
		if (bitLen == 0) return;
		if (bitLen > unitSize) {
			throw cybozu::Exception("BitVectorT:append:bad bitLen") << bitLen;
		}
		if (bitLen < unitSize) {
			src &= GetMaskBit<T>(bitLen);
		}
		const size_t q = bitLen_ / unitSize;
		const size_t r = bitLen_ % unitSize;
		resize(bitLen_ + bitLen);
		if (r == 0) {
			v_[q] = T(src);
			return;
		}
		v_[q] |= T(src << r);
		v_[q + 1] = T(src >> (unitSize - r));
	}
	/*
		append bitVector
	*/
	void append(const BitVectorT<T>& v)
	{
		append(v.getBlock(), v.size());
	}
	/*
		dst[0, bitLen) = vec[pos, pos + bitLen)
	*/
	void extract(T* dst, size_t pos, size_t bitLen) const
	{
		if (bitLen == 0) return;
		if (pos + bitLen > bitLen_) {
			throw cybozu::Exception("BitVectorT:extract:bad range") << bitLen << pos << bitLen_;
		}
		const size_t q = pos / unitSize;
		const size_t r = pos % unitSize;
		if (r == 0) {
			CopyBit<T>(dst, &v_[q], bitLen);
			return;
		}
		ShiftRightBit<T>(dst, &v_[q], bitLen + r, r);
	}
	/*
		dst = vec[pos, pos + bitLen)
	*/
	void extract(BitVectorT<T>& dst, size_t pos, size_t bitLen) const
	{
		dst.resize(bitLen);
		extract(dst.getBlock(), pos, bitLen);
	}
	/*
		return vec[pos, pos + bitLen)
	*/
	T extract(size_t pos, size_t bitLen) const
	{
		if (bitLen == 0) return 0;
		if (bitLen > unitSize || pos + bitLen > bitLen_) {
			throw cybozu::Exception("BitVectorT:extract:bad range") << bitLen << pos << bitLen_;
		}
		const size_t q = pos / unitSize;
		const size_t r = pos % unitSize;
		T v;
		if (r == 0) {
			v = v_[q];
		} else {
			v = (v_[q] >> r) | v_[q + 1] << (unitSize - r);
		}
		if (bitLen == unitSize) {
			return v;
		} else {
			return v & GetMaskBit<T>(bitLen);
		}
	}
	bool operator==(const BitVectorT<T>& rhs) const { return v_ == rhs.v_; }
	bool operator!=(const BitVectorT<T>& rhs) const { return v_ != rhs.v_; }
};

typedef BitVectorT<size_t> BitVector;

} // cybozu
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"

#if EIGEN_ALIGN
#define ALIGNMENT EIGEN_ALIGN_BYTES
#else
#define ALIGNMENT 1
#endif

typedef Matrix<float,8,1> Vector8f;

void check_handmade_aligned_malloc()
{
  for(int i = 1; i < 1000; i++)
  {
    char *p = (char*)internal::handmade_aligned_malloc(i);
    VERIFY(size_t(p)%ALIGNMENT==0);
    // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
    for(int j = 0; j < i; j++) p[j]=0;
    internal::handmade_aligned_free(p);
  }
}

void check_aligned_malloc()
{
  for(int i = 1; i < 1000; i++)
  {
    char *p = (char*)internal::aligned_malloc(i);
    VERIFY(size_t(p)%ALIGNMENT==0);
    // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
    for(int j = 0; j < i; j++) p[j]=0;
    internal::aligned_free(p);
  }
}

void check_aligned_new()
{
  for(int i = 1; i < 1000; i++)
  {
    float *p = internal::aligned_new<float>(i);
    VERIFY(size_t(p)%ALIGNMENT==0);
    // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
    for(int j = 0; j < i; j++) p[j]=0;
    internal::aligned_delete(p,i);
  }
}

void check_aligned_stack_alloc()
{
  for(int i = 1; i < 1000; i++)
  {
    ei_declare_aligned_stack_constructed_variable(float,p,i,0);
    VERIFY(size_t(p)%ALIGNMENT==0);
    // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
    for(int j = 0; j < i; j++) p[j]=0;
  }
}

// test compilation with both a struct and a class...
struct MyStruct
{
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  char dummychar;
  Vector8f avec;
};

class MyClassA
{
  public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    char dummychar;
    Vector8f avec;
};

template<typename T> void check_dynaligned()
{
  // TODO have to be updated once we support multiple alignment values
  if(T::SizeAtCompileTime % ALIGNMENT == 0)
  {
    T* obj = new T;
    VERIFY(T::NeedsToAlign==1);
    VERIFY(size_t(obj)%ALIGNMENT==0);
    delete obj;
  }
}

template<typename T> void check_custom_new_delete()
{
  {
    T* t = new T;
    delete t;
  }

  {
    std::size_t N = internal::random<std::size_t>(1,10);
    T* t = new T[N];
    delete[] t;
  }

#ifdef EIGEN_ALIGN
  {
    T* t = static_cast<T *>((T::operator new)(sizeof(T)));
    (T::operator delete)(t, sizeof(T));
  }

  {
    T* t = static_cast<T *>((T::operator new)(sizeof(T)));
    (T::operator delete)(t);
  }
#endif
}

void test_dynalloc()
{
  // low level dynamic memory allocation
  CALL_SUBTEST(check_handmade_aligned_malloc());
  CALL_SUBTEST(check_aligned_malloc());
  CALL_SUBTEST(check_aligned_new());
  CALL_SUBTEST(check_aligned_stack_alloc());

  for (int i=0; i<g_repeat*100; ++i)
  {
    CALL_SUBTEST(check_dynaligned<Vector4f>() );
    CALL_SUBTEST(check_dynaligned<Vector2d>() );
    CALL_SUBTEST(check_dynaligned<Matrix4f>() );
    CALL_SUBTEST(check_dynaligned<Vector4d>() );
    CALL_SUBTEST(check_dynaligned<Vector4i>() );
    CALL_SUBTEST(check_dynaligned<Vector8f>() );

    CALL_SUBTEST( check_custom_new_delete<Vector4f>() );
    CALL_SUBTEST( check_custom_new_delete<Vector2f>() );
    CALL_SUBTEST( check_custom_new_delete<Matrix4f>() );
    CALL_SUBTEST( check_custom_new_delete<MatrixXi>() );
  }

  // check static allocation, who knows ?
  #if EIGEN_ALIGN_STATICALLY
  {
    MyStruct foo0;  VERIFY(size_t(foo0.avec.data())%ALIGNMENT==0);
    MyClassA fooA;  VERIFY(size_t(fooA.avec.data())%ALIGNMENT==0);
  }

  // dynamic allocation, single object
  for (int i=0; i<g_repeat*100; ++i)
  {
    MyStruct *foo0 = new MyStruct();  VERIFY(size_t(foo0->avec.data())%ALIGNMENT==0);
    MyClassA *fooA = new MyClassA();  VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0);
    delete foo0;
    delete fooA;
  }

  // dynamic allocation, array
  const int N = 10;
  for (int i=0; i<g_repeat*100; ++i)
  {
    MyStruct *foo0 = new MyStruct[N];  VERIFY(size_t(foo0->avec.data())%ALIGNMENT==0);
    MyClassA *fooA = new MyClassA[N];  VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0);
    delete[] foo0;
    delete[] fooA;
  }
  #endif

}
<commit_msg>Memory allocated on the stack is freed at the function exit, so reduce iteration count to avoid stack overflow<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"

#if EIGEN_ALIGN
#define ALIGNMENT EIGEN_ALIGN_BYTES
#else
#define ALIGNMENT 1
#endif

typedef Matrix<float,8,1> Vector8f;

void check_handmade_aligned_malloc()
{
  for(int i = 1; i < 1000; i++)
  {
    char *p = (char*)internal::handmade_aligned_malloc(i);
    VERIFY(size_t(p)%ALIGNMENT==0);
    // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
    for(int j = 0; j < i; j++) p[j]=0;
    internal::handmade_aligned_free(p);
  }
}

void check_aligned_malloc()
{
  for(int i = 1; i < 1000; i++)
  {
    char *p = (char*)internal::aligned_malloc(i);
    VERIFY(size_t(p)%ALIGNMENT==0);
    // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
    for(int j = 0; j < i; j++) p[j]=0;
    internal::aligned_free(p);
  }
}

void check_aligned_new()
{
  for(int i = 1; i < 1000; i++)
  {
    float *p = internal::aligned_new<float>(i);
    VERIFY(size_t(p)%ALIGNMENT==0);
    // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
    for(int j = 0; j < i; j++) p[j]=0;
    internal::aligned_delete(p,i);
  }
}

void check_aligned_stack_alloc()
{
  for(int i = 1; i < 400; i++)
  {
    ei_declare_aligned_stack_constructed_variable(float,p,i,0);
    VERIFY(size_t(p)%ALIGNMENT==0);
    // if the buffer is wrongly allocated this will give a bad write --> check with valgrind
    for(int j = 0; j < i; j++) p[j]=0;
  }
}

// test compilation with both a struct and a class...
struct MyStruct
{
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
  char dummychar;
  Vector8f avec;
};

class MyClassA
{
  public:
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    char dummychar;
    Vector8f avec;
};

template<typename T> void check_dynaligned()
{
  // TODO have to be updated once we support multiple alignment values
  if(T::SizeAtCompileTime % ALIGNMENT == 0)
  {
    T* obj = new T;
    VERIFY(T::NeedsToAlign==1);
    VERIFY(size_t(obj)%ALIGNMENT==0);
    delete obj;
  }
}

template<typename T> void check_custom_new_delete()
{
  {
    T* t = new T;
    delete t;
  }

  {
    std::size_t N = internal::random<std::size_t>(1,10);
    T* t = new T[N];
    delete[] t;
  }

#ifdef EIGEN_ALIGN
  {
    T* t = static_cast<T *>((T::operator new)(sizeof(T)));
    (T::operator delete)(t, sizeof(T));
  }

  {
    T* t = static_cast<T *>((T::operator new)(sizeof(T)));
    (T::operator delete)(t);
  }
#endif
}

void test_dynalloc()
{
  // low level dynamic memory allocation
  CALL_SUBTEST(check_handmade_aligned_malloc());
  CALL_SUBTEST(check_aligned_malloc());
  CALL_SUBTEST(check_aligned_new());
  CALL_SUBTEST(check_aligned_stack_alloc());

  for (int i=0; i<g_repeat*100; ++i)
  {
    CALL_SUBTEST(check_dynaligned<Vector4f>() );
    CALL_SUBTEST(check_dynaligned<Vector2d>() );
    CALL_SUBTEST(check_dynaligned<Matrix4f>() );
    CALL_SUBTEST(check_dynaligned<Vector4d>() );
    CALL_SUBTEST(check_dynaligned<Vector4i>() );
    CALL_SUBTEST(check_dynaligned<Vector8f>() );

    CALL_SUBTEST( check_custom_new_delete<Vector4f>() );
    CALL_SUBTEST( check_custom_new_delete<Vector2f>() );
    CALL_SUBTEST( check_custom_new_delete<Matrix4f>() );
    CALL_SUBTEST( check_custom_new_delete<MatrixXi>() );
  }

  // check static allocation, who knows ?
  #if EIGEN_ALIGN_STATICALLY
  {
    MyStruct foo0;  VERIFY(size_t(foo0.avec.data())%ALIGNMENT==0);
    MyClassA fooA;  VERIFY(size_t(fooA.avec.data())%ALIGNMENT==0);
  }

  // dynamic allocation, single object
  for (int i=0; i<g_repeat*100; ++i)
  {
    MyStruct *foo0 = new MyStruct();  VERIFY(size_t(foo0->avec.data())%ALIGNMENT==0);
    MyClassA *fooA = new MyClassA();  VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0);
    delete foo0;
    delete fooA;
  }

  // dynamic allocation, array
  const int N = 10;
  for (int i=0; i<g_repeat*100; ++i)
  {
    MyStruct *foo0 = new MyStruct[N];  VERIFY(size_t(foo0->avec.data())%ALIGNMENT==0);
    MyClassA *fooA = new MyClassA[N];  VERIFY(size_t(fooA->avec.data())%ALIGNMENT==0);
    delete[] foo0;
    delete[] fooA;
  }
  #endif

}
<|endoftext|>


<commit_before>/// @file
/// @author  Boris Mikic
/// @version 2.4
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php

#ifdef HAVE_OPENAL
#include <stdio.h>
#include <string.h>
#include "xal.h"

#ifndef __APPLE__
#include <AL/al.h>
#else
#include <TargetConditionals.h>
#include <OpenAL/al.h>
#endif

#include "AudioManager.h"
#include "Buffer.h"
#include "Category.h"
#include "OpenAL_AudioManager.h"
#include "OpenAL_Player.h"
#include "Sound.h"

namespace xal
{
	OpenAL_Player::OpenAL_Player(Sound* sound, Buffer* buffer) :
		Player(sound, buffer), sourceId(0)
	{
		memset(this->bufferIds, 0, STREAM_BUFFER_COUNT * sizeof(unsigned int));
		alGenBuffers((!this->sound->isStreamed() ? 1 : STREAM_BUFFER_COUNT), this->bufferIds);
	}

	OpenAL_Player::~OpenAL_Player()
	{
		// AudioManager calls _stop before destruction
		alDeleteBuffers((!this->sound->isStreamed() ? 1 : STREAM_BUFFER_COUNT), this->bufferIds);
	}

	void OpenAL_Player::_update(float k)
	{
		Player::_update(k);
		if (!this->_systemIsPlaying() && this->sourceId != 0)
		{
			this->_stopSound();
		}
	}

	bool OpenAL_Player::_systemIsPlaying()
	{
		if (this->sourceId == 0)
		{
			return false;
		}
		if (this->sound->isStreamed())
		{
			return (this->_getQueuedBuffersCount() > 0 || this->_getProcessedBuffersCount() > 0);
		}
		int state;
		alGetSourcei(this->sourceId, AL_SOURCE_STATE, &state);
		return (state == AL_PLAYING);
	}

	float OpenAL_Player::_systemGetOffset()
	{
		float offset = 0.0f;
#if !TARGET_OS_MAC
		if (this->sourceId != 0)
		{
			alGetSourcef(this->sourceId, AL_SAMPLE_OFFSET, &offset);
		}
#else
		// did not find anything that works on Mac OS X and iOS!
#endif
		return offset;
	}

	void OpenAL_Player::_systemSetOffset(float value)
	{
#if !TARGET_OS_MAC
		// TODO - should be int
		if (this->sourceId != 0)
		{
			alSourcef(this->sourceId, AL_SAMPLE_OFFSET, value);
		}
		//alSourcei(this->sourceId, AL_SAMPLE_OFFSET, value);
#else
		// did not find anything that works on Mac OS X and iOS!
#endif
	}

	bool OpenAL_Player::_systemPreparePlay()
	{
		if (this->sourceId == 0)
		{
			this->sourceId = ((OpenAL_AudioManager*)xal::mgr)->_allocateSourceId();
		}
		return (this->sourceId != 0);
	}

	void OpenAL_Player::_systemPrepareBuffer()
	{
		// making sure all buffer data is loaded before accessing anything
		if (!this->sound->isStreamed())
		{
			this->_fillBuffers(0, 1);
			alSourcei(this->sourceId, AL_BUFFER, this->bufferIds[0]);
			alSourcei(this->sourceId, AL_LOOPING, this->looping);
		}
		else
		{
			alSourcei(this->sourceId, AL_BUFFER, AL_NONE);
			alSourcei(this->sourceId, AL_LOOPING, false);
			int count = STREAM_BUFFER_COUNT;
			if (!this->paused)
			{
				count = this->_fillBuffers(this->bufferIndex, STREAM_BUFFER_COUNT);
			}
			if (count > 0)
			{
				this->_queueBuffers(this->bufferIndex, count);
				this->bufferIndex = (this->bufferIndex + count) % STREAM_BUFFER_COUNT;
			}
		}
	}

	void OpenAL_Player::_systemUpdateGain()
	{
		if (this->sourceId != 0)
		{
			alSourcef(this->sourceId, AL_GAIN, this->_calcGain());
		}
	}

	void OpenAL_Player::_systemUpdateFadeGain()
	{
		if (this->sourceId != 0)
		{
			alSourcef(this->sourceId, AL_GAIN, this->_calcFadeGain());
		}
	}

	void OpenAL_Player::_systemPlay()
	{
		if (this->sourceId != 0)
		{
			alSourcePlay(this->sourceId);
		}
	}

	void OpenAL_Player::_systemStop()
	{
		if (this->sourceId != 0)
		{
			if (!this->sound->isStreamed())
			{
				alSourceStop(this->sourceId);
				alSourcei(this->sourceId, AL_BUFFER, AL_NONE); // necessary to avoid a memory leak in OpenAL
			}
			else
			{
				int processed = this->_getProcessedBuffersCount();
				alSourceStop(this->sourceId);
				this->_unqueueBuffers();
				alSourcei(this->sourceId, AL_BUFFER, AL_NONE); // necessary to avoid a memory leak in OpenAL
				if (this->paused)
				{
					this->bufferIndex = (this->bufferIndex + processed) % STREAM_BUFFER_COUNT;
				}
				else
				{
					this->bufferIndex = 0;
					this->buffer->rewind();
				}
			}
			((OpenAL_AudioManager*)xal::mgr)->_releaseSourceId(this->sourceId);
			this->sourceId = 0;
		}
	}

	void OpenAL_Player::_systemUpdateStream()
	{
		int queued = this->_getQueuedBuffersCount();
		if (queued == 0)
		{
			this->_stopSound();
			return;
		}
		int processed = this->_getProcessedBuffersCount();
		if (processed == 0)
		{
			return;
		}
		this->_unqueueBuffers((this->bufferIndex + STREAM_BUFFER_COUNT - queued) % STREAM_BUFFER_COUNT, processed);
		int count = this->_fillBuffers(this->bufferIndex, processed);
		if (count > 0)
		{
			this->_queueBuffers(this->bufferIndex, count);
			this->bufferIndex = (this->bufferIndex + count) % STREAM_BUFFER_COUNT;
			bool playing = (processed < STREAM_BUFFER_COUNT);
			if (playing)
			{
				int state;
				alGetSourcei(this->sourceId, AL_SOURCE_STATE, &state);
				if (state != AL_PLAYING)
				{
					playing = false;
				}
			}
			if (!playing) // underrun happened, sound was stopped by OpenAL so let's reboot it properly
			{
				this->_pause();
				this->_play();
			}
		}
		if (this->_getQueuedBuffersCount() == 0)
		{
			this->_stopSound();
		}
	}

	int OpenAL_Player::_getQueuedBuffersCount()
	{
		int queued = 0;
		if (this->sourceId)
		{
			alGetSourcei(this->sourceId, AL_BUFFERS_QUEUED, &queued);
		}
		return queued;
	}

	int OpenAL_Player::_getProcessedBuffersCount()
	{
		int processed = 0;
		if (this->sourceId)
		{
			alGetSourcei(this->sourceId, AL_BUFFERS_PROCESSED, &processed);
		}
		return processed;
	}

	int OpenAL_Player::_fillBuffers(int index, int count)
	{
		int size = this->buffer->load(this->looping, count * STREAM_BUFFER_SIZE);
		if (!this->sound->isStreamed())
		{
			alBufferData(this->bufferIds[index], (this->buffer->getChannels() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16),
				this->buffer->getStream(), size, this->buffer->getSamplingRate());
			return 1;
		}
		int filled = (size + STREAM_BUFFER_SIZE - 1) / STREAM_BUFFER_SIZE;
		unsigned char* stream = this->buffer->getStream();
		unsigned int format = (this->buffer->getChannels() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16);
		int samplingRate = this->buffer->getSamplingRate();
		for_iter (i, 0, filled)
		{
			alBufferData(this->bufferIds[(index + i) % STREAM_BUFFER_COUNT], format,
				&stream[i * STREAM_BUFFER_SIZE], hmin(size, STREAM_BUFFER_SIZE), samplingRate);
			size -= STREAM_BUFFER_SIZE;
		}
		return filled;
	}

	void OpenAL_Player::_queueBuffers(int index, int count)
	{
		if (index + count <= STREAM_BUFFER_COUNT)
		{
			alSourceQueueBuffers(this->sourceId, count, &this->bufferIds[index]);
		}
		else
		{
			alSourceQueueBuffers(this->sourceId, STREAM_BUFFER_COUNT - index, &this->bufferIds[index]);
			alSourceQueueBuffers(this->sourceId, count + index - STREAM_BUFFER_COUNT, this->bufferIds);
		}
	}

	void OpenAL_Player::_queueBuffers()
	{
		int queued = this->_getQueuedBuffersCount();
		if (queued < STREAM_BUFFER_COUNT)
		{
			this->_queueBuffers(this->bufferIndex, STREAM_BUFFER_COUNT - queued);
		}
	}

	void OpenAL_Player::_unqueueBuffers(int index, int count)
	{
		if (index + count <= STREAM_BUFFER_COUNT)
		{
#ifdef _IOS // needed for ios because in IOS 5 alSourceUnqueueBuffers doesn't lock the thread and returns before all requested buffers were unqueued
			int n = this->_getQueuedBuffersCount();
#endif
			alSourceUnqueueBuffers(this->sourceId, count, &this->bufferIds[index]);
#ifdef _IOS
			while (n - this->_getQueuedBuffersCount() != count)
			{
				hthread::sleep(1);
			}
#endif
		}
		else
		{
#ifdef _IOS
			int n = this->_getQueuedBuffersCount();
#endif
			alSourceUnqueueBuffers(this->sourceId, STREAM_BUFFER_COUNT - index, &this->bufferIds[index]);
#ifdef _IOS
			while (n - this->_getQueuedBuffersCount() != STREAM_BUFFER_COUNT - index)
			{
				hthread::sleep(1);
			}
			n -= STREAM_BUFFER_COUNT - index;
#endif
			alSourceUnqueueBuffers(this->sourceId, count + index - STREAM_BUFFER_COUNT, this->bufferIds);
#ifdef _IOS
			while (n - this->_getQueuedBuffersCount() != count + index - STREAM_BUFFER_COUNT)
			{
				hthread::sleep(1);
			}
#endif
		}
	}

	void OpenAL_Player::_unqueueBuffers()
	{
		int queued = this->_getQueuedBuffersCount();
		if (queued > 0)
		{
			this->_unqueueBuffers((this->bufferIndex + STREAM_BUFFER_COUNT - queued) % STREAM_BUFFER_COUNT, queued);
		}
	}

}
#endif
<commit_msg>* prevented buffer unqueue on systemStop on iOS due to iOS OpenAL bug. it'll work ok since the source is destroyed anyway.<commit_after>/// @file
/// @author  Boris Mikic
/// @version 2.4
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://www.opensource.org/licenses/bsd-license.php

#ifdef HAVE_OPENAL
#include <stdio.h>
#include <string.h>
#include "xal.h"

#ifndef __APPLE__
#include <AL/al.h>
#else
#include <TargetConditionals.h>
#include <OpenAL/al.h>
#endif

#include "AudioManager.h"
#include "Buffer.h"
#include "Category.h"
#include "OpenAL_AudioManager.h"
#include "OpenAL_Player.h"
#include "Sound.h"

namespace xal
{
	OpenAL_Player::OpenAL_Player(Sound* sound, Buffer* buffer) :
		Player(sound, buffer), sourceId(0)
	{
		memset(this->bufferIds, 0, STREAM_BUFFER_COUNT * sizeof(unsigned int));
		alGenBuffers((!this->sound->isStreamed() ? 1 : STREAM_BUFFER_COUNT), this->bufferIds);
	}

	OpenAL_Player::~OpenAL_Player()
	{
		// AudioManager calls _stop before destruction
		alDeleteBuffers((!this->sound->isStreamed() ? 1 : STREAM_BUFFER_COUNT), this->bufferIds);
	}

	void OpenAL_Player::_update(float k)
	{
		Player::_update(k);
		if (!this->_systemIsPlaying() && this->sourceId != 0)
		{
			this->_stopSound();
		}
	}

	bool OpenAL_Player::_systemIsPlaying()
	{
		if (this->sourceId == 0)
		{
			return false;
		}
		if (this->sound->isStreamed())
		{
			return (this->_getQueuedBuffersCount() > 0 || this->_getProcessedBuffersCount() > 0);
		}
		int state;
		alGetSourcei(this->sourceId, AL_SOURCE_STATE, &state);
		return (state == AL_PLAYING);
	}

	float OpenAL_Player::_systemGetOffset()
	{
		float offset = 0.0f;
#if !TARGET_OS_MAC
		if (this->sourceId != 0)
		{
			alGetSourcef(this->sourceId, AL_SAMPLE_OFFSET, &offset);
		}
#else
		// did not find anything that works on Mac OS X and iOS!
#endif
		return offset;
	}

	void OpenAL_Player::_systemSetOffset(float value)
	{
#if !TARGET_OS_MAC
		// TODO - should be int
		if (this->sourceId != 0)
		{
			alSourcef(this->sourceId, AL_SAMPLE_OFFSET, value);
		}
		//alSourcei(this->sourceId, AL_SAMPLE_OFFSET, value);
#else
		// did not find anything that works on Mac OS X and iOS!
#endif
	}

	bool OpenAL_Player::_systemPreparePlay()
	{
		if (this->sourceId == 0)
		{
			this->sourceId = ((OpenAL_AudioManager*)xal::mgr)->_allocateSourceId();
		}
		return (this->sourceId != 0);
	}

	void OpenAL_Player::_systemPrepareBuffer()
	{
		// making sure all buffer data is loaded before accessing anything
		if (!this->sound->isStreamed())
		{
			this->_fillBuffers(0, 1);
			alSourcei(this->sourceId, AL_BUFFER, this->bufferIds[0]);
			alSourcei(this->sourceId, AL_LOOPING, this->looping);
		}
		else
		{
			alSourcei(this->sourceId, AL_BUFFER, AL_NONE);
			alSourcei(this->sourceId, AL_LOOPING, false);
			int count = STREAM_BUFFER_COUNT;
			if (!this->paused)
			{
				count = this->_fillBuffers(this->bufferIndex, STREAM_BUFFER_COUNT);
			}
			if (count > 0)
			{
				this->_queueBuffers(this->bufferIndex, count);
				this->bufferIndex = (this->bufferIndex + count) % STREAM_BUFFER_COUNT;
			}
		}
	}

	void OpenAL_Player::_systemUpdateGain()
	{
		if (this->sourceId != 0)
		{
			alSourcef(this->sourceId, AL_GAIN, this->_calcGain());
		}
	}

	void OpenAL_Player::_systemUpdateFadeGain()
	{
		if (this->sourceId != 0)
		{
			alSourcef(this->sourceId, AL_GAIN, this->_calcFadeGain());
		}
	}

	void OpenAL_Player::_systemPlay()
	{
		if (this->sourceId != 0)
		{
			alSourcePlay(this->sourceId);
		}
	}

	void OpenAL_Player::_systemStop()
	{
		if (this->sourceId != 0)
		{
			if (!this->sound->isStreamed())
			{
				alSourceStop(this->sourceId);
				alSourcei(this->sourceId, AL_BUFFER, AL_NONE); // necessary to avoid a memory leak in OpenAL
			}
			else
			{
				int processed = this->_getProcessedBuffersCount();
				alSourceStop(this->sourceId);
#ifndef _IOS // hack for ios only, has problems when audio is suspended
				this->_unqueueBuffers();
#endif
				alSourcei(this->sourceId, AL_BUFFER, AL_NONE); // necessary to avoid a memory leak in OpenAL
				if (this->paused)
				{
					this->bufferIndex = (this->bufferIndex + processed) % STREAM_BUFFER_COUNT;
				}
				else
				{
					this->bufferIndex = 0;
					this->buffer->rewind();
				}
			}
			((OpenAL_AudioManager*) xal::mgr)->_releaseSourceId(this->sourceId);
			this->sourceId = 0;
		}
	}

	void OpenAL_Player::_systemUpdateStream()
	{
		int queued = this->_getQueuedBuffersCount();
		if (queued == 0)
		{
			this->_stopSound();
			return;
		}
		int processed = this->_getProcessedBuffersCount();
		if (processed == 0)
		{
			return;
		}
		this->_unqueueBuffers((this->bufferIndex + STREAM_BUFFER_COUNT - queued) % STREAM_BUFFER_COUNT, processed);
		int count = this->_fillBuffers(this->bufferIndex, processed);
		if (count > 0)
		{
			this->_queueBuffers(this->bufferIndex, count);
			this->bufferIndex = (this->bufferIndex + count) % STREAM_BUFFER_COUNT;
			bool playing = (processed < STREAM_BUFFER_COUNT);
			if (playing)
			{
				int state;
				alGetSourcei(this->sourceId, AL_SOURCE_STATE, &state);
				if (state != AL_PLAYING)
				{
					playing = false;
				}
			}
			if (!playing) // underrun happened, sound was stopped by OpenAL so let's reboot it properly
			{
				this->_pause();
				this->_play();
			}
		}
		if (this->_getQueuedBuffersCount() == 0)
		{
			this->_stopSound();
		}
	}

	int OpenAL_Player::_getQueuedBuffersCount()
	{
		int queued = 0;
		if (this->sourceId)
		{
			alGetSourcei(this->sourceId, AL_BUFFERS_QUEUED, &queued);
		}
		return queued;
	}

	int OpenAL_Player::_getProcessedBuffersCount()
	{
		int processed = 0;
		if (this->sourceId)
		{
			alGetSourcei(this->sourceId, AL_BUFFERS_PROCESSED, &processed);
		}
		return processed;
	}

	int OpenAL_Player::_fillBuffers(int index, int count)
	{
		int size = this->buffer->load(this->looping, count * STREAM_BUFFER_SIZE);
		if (!this->sound->isStreamed())
		{
			alBufferData(this->bufferIds[index], (this->buffer->getChannels() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16),
				this->buffer->getStream(), size, this->buffer->getSamplingRate());
			return 1;
		}
		int filled = (size + STREAM_BUFFER_SIZE - 1) / STREAM_BUFFER_SIZE;
		unsigned char* stream = this->buffer->getStream();
		unsigned int format = (this->buffer->getChannels() == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16);
		int samplingRate = this->buffer->getSamplingRate();
		for_iter (i, 0, filled)
		{
			alBufferData(this->bufferIds[(index + i) % STREAM_BUFFER_COUNT], format,
				&stream[i * STREAM_BUFFER_SIZE], hmin(size, STREAM_BUFFER_SIZE), samplingRate);
			size -= STREAM_BUFFER_SIZE;
		}
		return filled;
	}

	void OpenAL_Player::_queueBuffers(int index, int count)
	{
		if (index + count <= STREAM_BUFFER_COUNT)
		{
			alSourceQueueBuffers(this->sourceId, count, &this->bufferIds[index]);
		}
		else
		{
			alSourceQueueBuffers(this->sourceId, STREAM_BUFFER_COUNT - index, &this->bufferIds[index]);
			alSourceQueueBuffers(this->sourceId, count + index - STREAM_BUFFER_COUNT, this->bufferIds);
		}
	}

	void OpenAL_Player::_queueBuffers()
	{
		int queued = this->_getQueuedBuffersCount();
		if (queued < STREAM_BUFFER_COUNT)
		{
			this->_queueBuffers(this->bufferIndex, STREAM_BUFFER_COUNT - queued);
		}
	}

	void OpenAL_Player::_unqueueBuffers(int index, int count)
	{
		if (index + count <= STREAM_BUFFER_COUNT)
		{
#ifdef _IOS // needed for ios because in IOS 5 alSourceUnqueueBuffers doesn't lock the thread and returns before all requested buffers were unqueued
			int n = this->_getQueuedBuffersCount();
#endif
			alSourceUnqueueBuffers(this->sourceId, count, &this->bufferIds[index]);
#ifdef _IOS
			while (n - this->_getQueuedBuffersCount() != count)
			{
				hthread::sleep(1);
			}
#endif
		}
		else
		{
#ifdef _IOS
			int n = this->_getQueuedBuffersCount();
#endif
			alSourceUnqueueBuffers(this->sourceId, STREAM_BUFFER_COUNT - index, &this->bufferIds[index]);
#ifdef _IOS
			while (n - this->_getQueuedBuffersCount() != STREAM_BUFFER_COUNT - index)
			{
				hthread::sleep(1);
			}
			n -= STREAM_BUFFER_COUNT - index;
#endif
			alSourceUnqueueBuffers(this->sourceId, count + index - STREAM_BUFFER_COUNT, this->bufferIds);
#ifdef _IOS
			while (n - this->_getQueuedBuffersCount() != count + index - STREAM_BUFFER_COUNT)
			{
				hthread::sleep(1);
			}
#endif
		}
	}

	void OpenAL_Player::_unqueueBuffers()
	{
		int queued = this->_getQueuedBuffersCount();
		if (queued > 0)
		{
			this->_unqueueBuffers((this->bufferIndex + STREAM_BUFFER_COUNT - queued) % STREAM_BUFFER_COUNT, queued);
		}
	}

}
#endif
<|endoftext|>


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

#include "rpc/config.h"
#include "base/logging.h"

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/filesystem/operations.hpp>

static std::string currentDir = boost::filesystem::current_path().string();

DEFINE_string(name, "default", "human-readable name for this member.");
DEFINE_string(initial_cluster, fmt::format("{}=127.0.0.1:12321", FLAGS_name),
              "initial cluster configuration for bootstrapping. Format: \"<name1>=<ip1>, "
              "<name2>=<ip2>; ...\"");
DEFINE_string(wal_dir, fmt::format("{}/{}.consensus", currentDir, FLAGS_name),
              "path to the dedicated wal directory.");
DEFINE_uint32(heartbeat_interval, 100, "time (in milliseconds) of a heartbeat interval.");
DEFINE_uint32(election_timeout, 1000, "time (in milliseconds) for an election to timeout.");

namespace consensus {
namespace rpc {

#define ERROR_IF_NOT(cond)                                           \
  do {                                                               \
    if (!(cond))                                                     \
      return Status::Make(Error::BadConfig, "Check failed: " #cond); \
  } while (0)

Status ParseClusterMembershipFromGFlags(std::map<std::string, std::string> *peerMap) {
  using namespace silly;

  std::vector<std::string> servers;
  boost::split(servers, FLAGS_initial_cluster, [](char c) -> bool { return c == ';'; });

  for (std::string &server : servers) {
    boost::trim(server);
    if (server.empty()) {
      continue;
    }

    auto sep = std::find(server.begin(), server.end(), '=');
    ERROR_IF_NOT(sep != server.end());
    ERROR_IF_NOT(sep != server.begin());
    ERROR_IF_NOT(sep != std::prev(server.end()));
    size_t sepIndex = std::distance(server.begin(), sep);

    std::string serverName = server.substr(0, sepIndex);
    boost::trim(serverName);

    std::string serverAddress = server.substr(sepIndex + 1, server.length() - sepIndex);
    peerMap->insert(std::make_pair(std::move(serverName), std::move(serverAddress)));
  }
  return Status::OK();
}

}  // namespace rpc
}  // namespace consensus
<commit_msg>rpc/config: fix incorrect default value of wal_dir.<commit_after>// Copyright 2017 Wu Tao
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "rpc/config.h"
#include "base/logging.h"

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/filesystem/operations.hpp>

static std::string currentDir = boost::filesystem::current_path().string();

DEFINE_string(name, "default", "human-readable name for this member.");
DEFINE_string(initial_cluster, fmt::format("{}=127.0.0.1:12321", FLAGS_name),
              "initial cluster configuration for bootstrapping. Format: \"<name1>=<ip1>, "
              "<name2>=<ip2>; ...\"");
DEFINE_uint32(heartbeat_interval, 100, "time (in milliseconds) of a heartbeat interval.");
DEFINE_uint32(election_timeout, 1000, "time (in milliseconds) for an election to timeout.");

DEFINE_string(wal_dir, "", "path to the dedicated wal directory. Default to ${name}.consensus.");
bool FLAGS_wal_dir_Validator(const char* name, const std::string& val) {
  if (val.length() == 0) {
    FLAGS_wal_dir = fmt::format("{}/{}.consensus", currentDir, FLAGS_name);
  }
  return true;
}
DEFINE_validator(wal_dir, &FLAGS_wal_dir_Validator);

namespace consensus {
namespace rpc {

#define ERROR_IF_NOT(cond)                                           \
  do {                                                               \
    if (!(cond))                                                     \
      return Status::Make(Error::BadConfig, "Check failed: " #cond); \
  } while (0)

Status ParseClusterMembershipFromGFlags(std::map<std::string, std::string>* peerMap) {
  using namespace silly;

  std::vector<std::string> servers;
  boost::split(servers, FLAGS_initial_cluster, [](char c) -> bool { return c == ';'; });

  for (std::string& server : servers) {
    boost::trim(server);
    if (server.empty()) {
      continue;
    }

    auto sep = std::find(server.begin(), server.end(), '=');
    ERROR_IF_NOT(sep != server.end());
    ERROR_IF_NOT(sep != server.begin());
    ERROR_IF_NOT(sep != std::prev(server.end()));
    size_t sepIndex = std::distance(server.begin(), sep);

    std::string serverName = server.substr(0, sepIndex);
    boost::trim(serverName);

    std::string serverAddress = server.substr(sepIndex + 1, server.length() - sepIndex);
    peerMap->insert(std::make_pair(std::move(serverName), std::move(serverAddress)));
  }
  return Status::OK();
}

}  // namespace rpc
}  // namespace consensus
<|endoftext|>


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

#include <random>

namespace Headless {
    namespace Logic {
        /**
         * Here are proposed some implementations of General Algorithms.
         * Currently available GAs are:
         *  - Trivial.
         */
        namespace GA {

            /**
             * Trivial GA.
             * 1. Generate first pool.
             * 2. Evaluate pool against a testing environment.
             * 3. Save the elite.
             * 4. Create new pool from elite using set of operators.
             * 5. Back to step 2 until error is superior to specified
             *    or until generation number is inferior to specified.
             *
             * To this purpose, we need the following concepts :
             * @param <C> Candidates to be evaluated and modified.
             */
            template <typename C> class Trivial {

                public:

                    /**
                     * Constructor.
                     * @param pSize Pool Size.
                     */
                    Trivial(unsigned int pSize) : _count(pSize) {
                        _pool = new C*[pSize];
                        _score = new double[pSize];
                    }

                    /**
                     * Destructor.
                     */
                    ~Trivial() {
                        delete []_pool;
                        delete []_score;
                    }

                    /**
                     * Training.
                     * @param <E> Creation and evaluation environment type. It must define
                     *      the following methods:
                     *      - void reserve(C**, unsigned int)
                     *      - void release(C**, unsigned int)
                     *      - double evaluate (const C*)
                     *      - C* clone(const C*)
                     * @param <... M> Set of operators/mutators types. A mutator must define
                     *      the following methods:
                     *      - double threshold()
                     *      - void mutate(C**, unsigned int, C*);
                     * @param env Environment.
                     * @param maxGen Maximum number of generations.
                     * @param minErr Minimal accepable error.
                     * @param eliteSize Percentage of the pool to be taken for creating the next pool.
                     * @param store A store for results.
                     * @param size Size of the storage and maximum number of exit candidate.
                     * @param mutators Set of operators/mutators for new pool creation.
                     * @return The number of candidates stored in the specified buffer.
                     */
                    template <typename E, typename... M> int train(E* env,
                            unsigned int maxGen, double minErr, double eliteSize,
                            C** store, unsigned int size,
                            M... mutators) {
                        unsigned int eliteCount = _count * eliteSize;
                        // We assume that the pool is empty and needs to be filled.
                        env->reserve(_pool, _count);

                        // Loop on generations.
                        for(unsigned int g = 0;
                                (g < maxGen) && (evaluate(env) > minErr);
                                ++g) {
                            // At this point, the pool is full and sorted.
                            // Let's recycle candidates from eliteCount to _count - 1.
                            #pragma omp parallel for
                            for(unsigned int i = eliteCount; i < _count; ++i) {
                                // Randomly choose a mutators.
                                mutate(i, eliteCount, mutators...);
                            }
                        }

                        unsigned int number = eliteCount < size ? eliteCount : size;
                        for(unsigned int i = 0; i < number; ++i) {
                            store[i] = env->clone(_pool[i]);
                        }

                        // Clean-up the pool.
                        env->release(_pool, _count);

                        return number;
                    }

                private:
                    /**
                     * make a new offspring out of the available mutators.
                     */
                    template <typename M, typename... O> void mutate(unsigned int pos, unsigned int count,
                            M mutator, O... others) {
                        std::random_device rd;
                        std::mt19937 mt(rd());
                        std::uniform_real_distribution<double> dist(0.0, 1.0);
                        double rnd = dist(mt);
                        if(rnd < mutator->threshold()) {
                            mutator->mutate(_pool, count, _pool + pos);
                        } else {
                            mutate(pos, count, others...);
                        }
                    }

                    template <typename M> void mutate(unsigned int pos, unsigned int count, M mutator) {
                        mutator->mutate(_pool, count, _pool + pos);
                    }

                    /**
                     * Evaluate the pool against the environment.
                     * @param <E> Environment type.
                     * @param env Environment.
                     * @return Minimal error. At return time, the pool is sorted
                     * using candidates scores.
                     */
                    template <typename E> double evaluate(E* env) {
                        // Evaluate ...
                        #pragma omp parallel for
                        for(unsigned int i = 0; i < _count; ++i) {
                            _score + i = env->evaluate(_pool + i);
                        }

                        // ... and sort.
                        qsort(0, _count - 1);

                        return _score[0];
                    }

                    /**
                     * Simple quick sort for our specific case.
                     * @param lo Lower bound.
                     * @param hi Higher bound.
                     */
                    void qsort(unsigned int lo, unsigned int hi) {
                        if(lo < hi) {
                            // We don't make fat partitionning as we are manipulating
                            // fine-grained over-distributed scores. We should not
                            // have arrays of identical scores.
                            unsigned int pivot = partition(lo, hi);
                            if((pivot - lo) < (hi - (pivot + 1))) {
                                qsort(lo, pivot);
                                qsort(pivot + 1, hi);
                            } else {
                                qsort(pivot + 1, hi);
                                qsort(lo, pivot);
                            }

                        }
                    }

                    unsigned int partition(unsigned int lo, unsigned int hi) {
                        double pivot = _score + lo;
                        unsigned int i = lo - 1;
                        unsigned int j = hi + 1;

                        for(;;) {
                            do {
                                ++i;
                            } while(_score + i < pivot);
                            do {
                                --j;
                            } while(_score + j > pivot);
                            if(i >= j) {
                                return j;
                            }
                            double score = _score + i;
                            C* candidate = _pool + i;
                            _score + i = _score + j;
                            _pool + i = _pool + j;
                            _score + j = score;
                            _pool + j = candidate;
                        }
                        return 0; // Should never happen.
                    }

                private:

                    /**
                     * Candidate pool.
                     */
                    C** _pool;

                    /**
                     * Pool score.
                     */
                    double *_score;

                    /**
                     * Pool count.
                     */
                    unsigned int _count;
            };

        } // Namespace 'GA'
    } // Namespace 'Logic'
} // Namespace 'Headless'

#endif
<commit_msg>Late fix on genetic algorithm engine before stress test.<commit_after>/*
 * Copyright 2016 Stoned Xander
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef HEADLESS_LOGIC_GENETIC_ALGORITHM
#define HEADLESS_LOGIC_GENETIC_ALGORITHM

#include <random>

namespace Headless {
    namespace Logic {
        /**
         * Here are proposed some implementations of General Algorithms.
         * Currently available GAs are:
         *  - Trivial.
         */
        namespace GA {

            /**
             * Trivial GA.
             * 1. Generate first pool.
             * 2. Evaluate pool against a testing environment.
             * 3. Save the elite.
             * 4. Create new pool from elite using set of operators.
             * 5. Back to step 2 until error is superior to specified
             *    or until generation number is inferior to specified.
             *
             * To this purpose, we need the following concepts :
             * @param <C> Candidates to be evaluated and modified.
             */
            template <typename C> class Trivial {

                public:

                    /**
                     * Constructor.
                     * @param pSize Pool Size.
                     */
                    Trivial(unsigned int pSize) : _count(pSize) {
                        _pool = new C*[pSize];
                        _score = new double[pSize];
                    }

                    /**
                     * Destructor.
                     */
                    ~Trivial() {
                        delete []_pool;
                        delete []_score;
                    }

                    /**
                     * Training.
                     * @param <E> Creation and evaluation environment type. It must define
                     *      the following methods:
                     *      - void reserve(C**&, unsigned int)
                     *      - void release(C**, unsigned int)
                     *      - double evaluate (const C*)
                     *      - C* clone(const C*)
                     * @param <... M> Set of operators/mutators types. A mutator must define
                     *      the following methods:
                     *      - double threshold()
                     *      - void mutate(C**, unsigned int, C*);
                     * @param env Environment.
                     * @param maxGen Maximum number of generations.
                     * @param minErr Minimal accepable error.
                     * @param eliteSize Percentage of the pool to be taken for creating the next pool.
                     * @param store A store for results.
                     * @param size Size of the storage and maximum number of exit candidate.
                     * @param mutators Set of operators/mutators for new pool creation.
                     * @return The number of candidates stored in the specified buffer.
                     */
                    template <typename E, typename... M> int train(E* env,
                            unsigned int maxGen, double minErr, double eliteSize,
                            C** store, unsigned int size,
                            M... mutators) {
                        unsigned int eliteCount = _count * eliteSize;
                        // We assume that the pool is empty and needs to be filled.
                        env->reserve(_pool, _count);

                        // Loop on generations.
                        for(unsigned int g = 0;
                                (g < maxGen) && (evaluate(env) > minErr);
                                ++g) {
                            // At this point, the pool is full and sorted.
                            // Let's recycle candidates from eliteCount to _count - 1.
                            #pragma omp parallel for
                            for(unsigned int i = eliteCount; i < _count; ++i) {
                                // Randomly choose a mutators.
                                mutate(i, eliteCount, mutators...);
                            }
                        }

                        unsigned int number = eliteCount < size ? eliteCount : size;
                        for(unsigned int i = 0; i < number; ++i) {
                            store[i] = env->clone(_pool[i]);
                        }

                        // Clean-up the pool.
                        env->release(_pool, _count);

                        return number;
                    }

                private:
                    /**
                     * make a new offspring out of the available mutators.
                     */
                    template <typename M, typename... O> void mutate(unsigned int pos, unsigned int count,
                            M mutator, O... others) {
                        std::random_device rd;
                        std::mt19937 mt(rd());
                        std::uniform_real_distribution<double> dist(0.0, 1.0);
                        double rnd = dist(mt);
                        if(rnd < mutator->threshold()) {
                            mutator->mutate(_pool, count, _pool[pos]);
                        } else {
                            mutate(pos, count, others...);
                        }
                    }

                    template <typename M> void mutate(unsigned int pos, unsigned int count, M mutator) {
                        mutator->mutate(_pool, count, _pool[pos]);
                    }

                    /**
                     * Evaluate the pool against the environment.
                     * @param <E> Environment type.
                     * @param env Environment.
                     * @return Minimal error. At return time, the pool is sorted
                     * using candidates scores.
                     */
                    template <typename E> double evaluate(E* env) {
                        // Evaluate ...
                        #pragma omp parallel for
                        for(unsigned int i = 0; i < _count; ++i) {
                            _score[i] = env->evaluate(_pool[i]);
                        }

                        // ... and sort.
                        qsort(0, _count - 1);

                        return _score[0];
                    }

                    /**
                     * Simple quick sort for our specific case.
                     * @param lo Lower bound.
                     * @param hi Higher bound.
                     */
                    void qsort(unsigned int lo, unsigned int hi) {
                        if(lo < hi) {
                            // We don't make fat partitionning as we are manipulating
                            // fine-grained over-distributed scores. We should not
                            // have arrays of identical scores.
                            unsigned int pivot = partition(lo, hi);
                            if((pivot - lo) < (hi - (pivot + 1))) {
                                qsort(lo, pivot);
                                qsort(pivot + 1, hi);
                            } else {
                                qsort(pivot + 1, hi);
                                qsort(lo, pivot);
                            }

                        }
                    }

                    unsigned int partition(unsigned int lo, unsigned int hi) {
                        double pivot = _score[lo];
                        unsigned int i = lo - 1;
                        unsigned int j = hi + 1;

                        for(;;) {
                            do {
                                ++i;
                            } while(_score[i] < pivot);
                            do {
                                --j;
                            } while(_score[j] > pivot);
                            if(i >= j) {
                                return j;
                            }
                            double score = _score[i];
                            C* candidate = _pool[i];
                            _score[i] = _score[j];
                            _pool[i] = _pool[j];
                            _score[j] = score;
                            _pool[j] = candidate;
                        }
                        return 0; // Should never happen.
                    }

                private:

                    /**
                     * Candidate pool.
                     */
                    C** _pool;

                    /**
                     * Pool score.
                     */
                    double *_score;

                    /**
                     * Pool count.
                     */
                    unsigned int _count;
            };

        } // Namespace 'GA'
    } // Namespace 'Logic'
} // Namespace 'Headless'

#endif
<|endoftext|>