<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program 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 of the License, or (at your option) any later
version.

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

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/

#include <OgreStableHeaders.h>

#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include "OgreILImageCodec.h"
#include <OgreImage.h>
#include <OgreException.h>
#include "OgreILUtil.h"

#include <OgreLogManager.h>
#include <OgreStringConverter.h>

#include <IL/il.h>
#include <IL/ilu.h>

namespace Ogre {

    bool ILImageCodec::_is_initialised = false;
    //---------------------------------------------------------------------

    ILImageCodec::ILImageCodec(const String &type, unsigned int ilType):
        mType(type),
        mIlType(ilType)
    {
        initialiseIL();
    }

    //---------------------------------------------------------------------
    DataStreamPtr ILImageCodec::code(MemoryDataStreamPtr& input, Codec::CodecDataPtr& pData) const
    {

        OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "code to memory not implemented",
            "ILCodec::code");

    }
    //---------------------------------------------------------------------
    void ILImageCodec::codeToFile(MemoryDataStreamPtr& input,
        const String& outFileName, Codec::CodecDataPtr& pData) const
    {

        ILuint ImageName;

        ilGenImages( 1, &ImageName );
        ilBindImage( ImageName );

		ImageData* pImgData = static_cast< ImageData * >( pData.getPointer() );
		PixelBox src(pImgData->width, pImgData->height, pImgData->depth, pImgData->format, input->getPtr());

		// Convert image from OGRE to current IL image
		ILUtil::fromOgre(src);

        iluFlipImage();

        // Implicitly pick DevIL codec
        ilSaveImage(const_cast< char * >( outFileName.c_str() ) );

        // Check if everything was ok
        ILenum PossibleError = ilGetError() ;
        if( PossibleError != IL_NO_ERROR ) {
           ilDeleteImages(1, &ImageName);
           OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED,
                "IL Error, could not save file: " + outFileName,
                iluErrorString(PossibleError) ) ;
        }

        ilDeleteImages(1, &ImageName);

    }
    //---------------------------------------------------------------------
    Codec::DecodeResult ILImageCodec::decode(DataStreamPtr& input) const
    {

        // DevIL variables
        ILuint ImageName;

        ILint ImageFormat, BytesPerPixel, ImageType;
        ImageData* imgData = new ImageData();
        MemoryDataStreamPtr output;

        // Load the image
        ilGenImages( 1, &ImageName );
        ilBindImage( ImageName );

        // Put it right side up
        ilEnable(IL_ORIGIN_SET);
        ilSetInteger(IL_ORIGIN_MODE, IL_ORIGIN_UPPER_LEFT);

        // Keep DXTC(compressed) data if present
        ilSetInteger(IL_KEEP_DXTC_DATA, IL_TRUE);

        // Load image from stream, cache into memory
        MemoryDataStream memInput(input);
        ilLoadL(
            mIlType,
            memInput.getPtr(),
            static_cast< ILuint >(memInput.size()));

        // Check if everything was ok
        ILenum PossibleError = ilGetError() ;
        if( PossibleError != IL_NO_ERROR ) {
            OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED,
                "IL Error",
                iluErrorString(PossibleError) ) ;
        }

        ImageFormat = ilGetInteger( IL_IMAGE_FORMAT );
        ImageType = ilGetInteger( IL_IMAGE_TYPE );

        // Convert image if ImageType is incompatible with us (double or long)
        if(ImageType != IL_BYTE && ImageType != IL_UNSIGNED_BYTE &&
			ImageType != IL_FLOAT &&
			ImageType != IL_UNSIGNED_SHORT && ImageType != IL_SHORT) {
            ilConvertImage(ImageFormat, IL_FLOAT);
			ImageType = IL_FLOAT;
        }
		// Converted paletted images
		if(ImageFormat == IL_COLOUR_INDEX)
		{
			ilConvertImage(IL_BGRA, IL_UNSIGNED_BYTE);
			ImageFormat = IL_BGRA;
			ImageType = IL_UNSIGNED_BYTE;
		}

        // Now sets some variables
        BytesPerPixel = ilGetInteger( IL_IMAGE_BYTES_PER_PIXEL );

        imgData->format = ILUtil::ilFormat2OgreFormat( ImageFormat, ImageType );
        imgData->width = ilGetInteger( IL_IMAGE_WIDTH );
        imgData->height = ilGetInteger( IL_IMAGE_HEIGHT );
        imgData->depth = ilGetInteger( IL_IMAGE_DEPTH );
        imgData->num_mipmaps = ilGetInteger ( IL_NUM_MIPMAPS );
        imgData->flags = 0;

		if(imgData->format == PF_UNKNOWN)
		{
			std::stringstream err;
			err << "Unsupported devil format ImageFormat=" << std::hex << ImageFormat <<
				" ImageType="<< ImageType << std::dec;
			ilDeleteImages( 1, &ImageName );

			OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED,
                err.str(),
                "ILImageCodec::decode" ) ;
		}

        // Check for cubemap
        //ILuint cubeflags = ilGetInteger ( IL_IMAGE_CUBEFLAGS );
		size_t numFaces = ilGetInteger ( IL_NUM_IMAGES ) + 1;
        if(numFaces == 6)
			imgData->flags |= IF_CUBEMAP;
        else
            numFaces = 1; // Support only 1 or 6 face images for now

        // Keep DXT data (if present at all and the GPU supports it)
        ILuint dxtFormat = ilGetInteger( IL_DXTC_DATA_FORMAT );
        if(dxtFormat != IL_DXT_NO_COMP && Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability( RSC_TEXTURE_COMPRESSION_DXT ))
        {
			imgData->format = ILUtil::ilFormat2OgreFormat( dxtFormat, ImageType );
            imgData->flags |= IF_COMPRESSED;

            // Validate that this devil version saves DXT mipmaps
            if(imgData->num_mipmaps>0)
            {
                ilBindImage(ImageName);
                ilActiveMipmap(1);
                if((size_t)ilGetInteger( IL_DXTC_DATA_FORMAT ) != dxtFormat)
                {
                    imgData->num_mipmaps=0;
                    LogManager::getSingleton().logMessage(
                    "Warning: Custom mipmaps for compressed image "+input->getName()+" were ignored because they are not loaded by this DevIL version");
                }
            }
        }

        // Calculate total size from number of mipmaps, faces and size
        imgData->size = Image::calculateSize(imgData->num_mipmaps, numFaces,
            imgData->width, imgData->height, imgData->depth, imgData->format);

        // Bind output buffer
        output.bind(new MemoryDataStream(imgData->size));
        size_t offset = 0;

        // Dimensions of current mipmap
        size_t width = imgData->width;
        size_t height = imgData->height;
        size_t depth = imgData->depth;

        // Transfer data
        for(size_t mip=0; mip<=imgData->num_mipmaps; ++mip)
        {
            for(size_t i = 0; i < numFaces; ++i)
            {
                ilBindImage(ImageName);
                if(numFaces > 1)
                    ilActiveImage(i);
                if(imgData->num_mipmaps > 0)
                    ilActiveMipmap(mip);
                /// Size of this face
                size_t imageSize = PixelUtil::getMemorySize(
                        width, height, depth, imgData->format);
                if(imgData->flags & IF_COMPRESSED)
                {

                    // Compare DXT size returned by DevIL with our idea of the compressed size
                    if(imageSize == ilGetDXTCData(NULL, 0, dxtFormat))
                    {
                        // Retrieve data from DevIL
                        ilGetDXTCData((unsigned char*)output->getPtr()+offset, imageSize, dxtFormat);
                    } else
                    {
                        LogManager::getSingleton().logMessage(
                            "Warning: compressed image "+input->getName()+" size mismatch, devilsize="+StringConverter::toString(ilGetDXTCData(NULL, 0, dxtFormat))+" oursize="+
                            StringConverter::toString(imageSize));
                    }
                }
                else
                {
                    /// Retrieve data from DevIL
                    PixelBox dst(width, height, depth, imgData->format, (unsigned char*)output->getPtr()+offset);
                    ILUtil::toOgre(dst);
                }
                offset += imageSize;
            }
            /// Next mip
            if(width!=1) width /= 2;
            if(height!=1) height /= 2;
            if(depth!=1) depth /= 2;
        }

        // Restore IL state
        ilDisable(IL_ORIGIN_SET);
        ilDisable(IL_FORMAT_SET);

        ilDeleteImages( 1, &ImageName );

        DecodeResult ret;
        ret.first = output;
        ret.second = CodecDataPtr(imgData);

        return ret;
    }
    //---------------------------------------------------------------------
    void ILImageCodec::initialiseIL(void)
    {
        if( !_is_initialised )
        {
            ilInit();
            ilEnable( IL_FILE_OVERWRITE );
            _is_initialised = true;
        }
    }
    //---------------------------------------------------------------------
    String ILImageCodec::getType() const
    {
        return mType;
    }

    //---------------------------------------------------------------------
    String ILImageCodec::magicNumberToFileExt(const char *magicNumberPtr, size_t maxbytes) const
    {
	// DevIL uses magic internally to determine file types when
	// necessary but does not expose the code in its API.
	// This makes it difficult to implement this function, but also
	// reduces its importance. Just for now, here is a kludge to
	// get Ogre to build and ensure that it always tries to load files
	// that DevIL might be able to load.
	return String("jpg");
    }
}
<commit_msg>Patch 2825998: ILImageCodec segfault fix (for those who choose to use it)<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program 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 of the License, or (at your option) any later
version.

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

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/

#include <OgreStableHeaders.h>

#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include "OgreILImageCodec.h"
#include <OgreImage.h>
#include <OgreException.h>
#include "OgreILUtil.h"

#include <OgreLogManager.h>
#include <OgreStringConverter.h>

#include <IL/il.h>
#include <IL/ilu.h>

namespace Ogre {

    bool ILImageCodec::_is_initialised = false;
    //---------------------------------------------------------------------

    ILImageCodec::ILImageCodec(const String &type, unsigned int ilType):
        mType(type),
        mIlType(ilType)
    {
        initialiseIL();
    }

    //---------------------------------------------------------------------
    DataStreamPtr ILImageCodec::code(MemoryDataStreamPtr& input, Codec::CodecDataPtr& pData) const
    {

        OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "code to memory not implemented",
            "ILCodec::code");

    }
    //---------------------------------------------------------------------
    void ILImageCodec::codeToFile(MemoryDataStreamPtr& input,
        const String& outFileName, Codec::CodecDataPtr& pData) const
    {

        ILuint ImageName;

        ilGenImages( 1, &ImageName );
        ilBindImage( ImageName );

		ImageData* pImgData = static_cast< ImageData * >( pData.getPointer() );
		PixelBox src(pImgData->width, pImgData->height, pImgData->depth, pImgData->format, input->getPtr());

		// Convert image from OGRE to current IL image
		ILUtil::fromOgre(src);

        iluFlipImage();

        // Implicitly pick DevIL codec
        ilSaveImage(const_cast< char * >( outFileName.c_str() ) );

        // Check if everything was ok
        ILenum PossibleError = ilGetError() ;
        if( PossibleError != IL_NO_ERROR ) {
           ilDeleteImages(1, &ImageName);
           OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED,
                "IL Error, could not save file: " + outFileName,
                iluErrorString(PossibleError) ) ;
        }

        ilDeleteImages(1, &ImageName);

    }
    //---------------------------------------------------------------------
    Codec::DecodeResult ILImageCodec::decode(DataStreamPtr& input) const
    {

        // DevIL variables
        ILuint ImageName;

        ILint ImageFormat, BytesPerPixel, ImageType;
        ImageData* imgData = new ImageData();
        MemoryDataStreamPtr output;

        // Load the image
        ilGenImages( 1, &ImageName );
        ilBindImage( ImageName );

        // Put it right side up
        ilEnable(IL_ORIGIN_SET);
        ilSetInteger(IL_ORIGIN_MODE, IL_ORIGIN_UPPER_LEFT);

        // Keep DXTC(compressed) data if present
        ilSetInteger(IL_KEEP_DXTC_DATA, IL_TRUE);

        // Load image from stream, cache into memory
        MemoryDataStream memInput(input);
        ilLoadL(
            mIlType,
            memInput.getPtr(),
            static_cast< ILuint >(memInput.size()));

        // Check if everything was ok
        ILenum PossibleError = ilGetError() ;
        if( PossibleError != IL_NO_ERROR ) {
            OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED,
                "IL Error",
                iluErrorString(PossibleError) ) ;
        }

        ImageFormat = ilGetInteger( IL_IMAGE_FORMAT );
        ImageType = ilGetInteger( IL_IMAGE_TYPE );

        // Convert image if ImageType is incompatible with us (double or long)
        if(ImageType != IL_BYTE && ImageType != IL_UNSIGNED_BYTE &&
			ImageType != IL_FLOAT &&
			ImageType != IL_UNSIGNED_SHORT && ImageType != IL_SHORT) {
            ilConvertImage(ImageFormat, IL_FLOAT);
			ImageType = IL_FLOAT;
        }
		// Converted paletted images
		if(ImageFormat == IL_COLOUR_INDEX)
		{
			ilConvertImage(IL_BGRA, IL_UNSIGNED_BYTE);
			ImageFormat = IL_BGRA;
			ImageType = IL_UNSIGNED_BYTE;
		}

        // Now sets some variables
        BytesPerPixel = ilGetInteger( IL_IMAGE_BYTES_PER_PIXEL );

        imgData->format = ILUtil::ilFormat2OgreFormat( ImageFormat, ImageType );
        imgData->width = ilGetInteger( IL_IMAGE_WIDTH );
        imgData->height = ilGetInteger( IL_IMAGE_HEIGHT );
        imgData->depth = ilGetInteger( IL_IMAGE_DEPTH );
        imgData->num_mipmaps = ilGetInteger ( IL_NUM_MIPMAPS );
        imgData->flags = 0;

		if(imgData->format == PF_UNKNOWN)
		{
			std::stringstream err;
			err << "Unsupported devil format ImageFormat=" << std::hex << ImageFormat <<
				" ImageType="<< ImageType << std::dec;
			ilDeleteImages( 1, &ImageName );

			OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED,
                err.str(),
                "ILImageCodec::decode" ) ;
		}

        // Check for cubemap
        //ILuint cubeflags = ilGetInteger ( IL_IMAGE_CUBEFLAGS );
		size_t numFaces = ilGetInteger ( IL_NUM_IMAGES ) + 1;
        if(numFaces == 6)
			imgData->flags |= IF_CUBEMAP;
        else
            numFaces = 1; // Support only 1 or 6 face images for now

        // Keep DXT data (if present at all and the GPU supports it)
        ILuint dxtFormat = ilGetInteger( IL_DXTC_DATA_FORMAT );
        if(dxtFormat != IL_DXT_NO_COMP && Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability( RSC_TEXTURE_COMPRESSION_DXT ))
        {
			imgData->format = ILUtil::ilFormat2OgreFormat( dxtFormat, ImageType );
            imgData->flags |= IF_COMPRESSED;

            // Validate that this devil version saves DXT mipmaps
            if(imgData->num_mipmaps>0)
            {
                ilBindImage(ImageName);
                ilActiveMipmap(1);
                if((size_t)ilGetInteger( IL_DXTC_DATA_FORMAT ) != dxtFormat)
                {
                    imgData->num_mipmaps=0;
                    LogManager::getSingleton().logMessage(
                    "Warning: Custom mipmaps for compressed image "+input->getName()+" were ignored because they are not loaded by this DevIL version");
                }
            }
        }

        // Calculate total size from number of mipmaps, faces and size
        imgData->size = Image::calculateSize(imgData->num_mipmaps, numFaces,
            imgData->width, imgData->height, imgData->depth, imgData->format);

        // Bind output buffer
        output.bind(new MemoryDataStream(imgData->size));
        size_t offset = 0;

        // Dimensions of current mipmap
        size_t width = imgData->width;
        size_t height = imgData->height;
        size_t depth = imgData->depth;

        // Transfer data
        for(size_t mip=0; mip<=imgData->num_mipmaps; ++mip)
        {
            for(size_t i = 0; i < numFaces; ++i)
            {
                ilBindImage(ImageName);
                if(numFaces > 1)
                    ilActiveImage(i);
                if(imgData->num_mipmaps > 0)
                    ilActiveMipmap(mip);
                /// Size of this face
                size_t imageSize = PixelUtil::getMemorySize(
                        width, height, depth, imgData->format);
                if(imgData->flags & IF_COMPRESSED)
                {

                    // Compare DXT size returned by DevIL with our idea of the compressed size
                    if(imageSize == ilGetDXTCData(NULL, 0, dxtFormat))
                    {
                        // Retrieve data from DevIL
                        ilGetDXTCData((unsigned char*)output->getPtr()+offset, imageSize, dxtFormat);
                    } else
                    {
                        LogManager::getSingleton().logMessage(
                            "Warning: compressed image "+input->getName()+" size mismatch, devilsize="+StringConverter::toString(ilGetDXTCData(NULL, 0, dxtFormat))+" oursize="+
                            StringConverter::toString(imageSize));
                    }
                }
                else
                {
                    /// Retrieve data from DevIL
                    PixelBox dst(width, height, depth, imgData->format, (unsigned char*)output->getPtr()+offset);
                    ILUtil::toOgre(dst);
                }
                offset += imageSize;
            }
            /// Next mip
            if(width!=1) width /= 2;
            if(height!=1) height /= 2;
            if(depth!=1) depth /= 2;
        }

        // Restore IL state
        ilDisable(IL_ORIGIN_SET);
        ilDisable(IL_FORMAT_SET);

        ilDeleteImages( 1, &ImageName );

        DecodeResult ret;
        ret.first = output;
        ret.second = CodecDataPtr(imgData);

        return ret;
    }
    //---------------------------------------------------------------------
    void ILImageCodec::initialiseIL(void)
    {
        if( !_is_initialised )
        {
            ilInit();
            iluInit();
            ilEnable( IL_FILE_OVERWRITE );
            _is_initialised = true;
        }
    }
    //---------------------------------------------------------------------
    String ILImageCodec::getType() const
    {
        return mType;
    }

    //---------------------------------------------------------------------
    String ILImageCodec::magicNumberToFileExt(const char *magicNumberPtr, size_t maxbytes) const
    {
	// DevIL uses magic internally to determine file types when
	// necessary but does not expose the code in its API.
	// This makes it difficult to implement this function, but also
	// reduces its importance. Just for now, here is a kludge to
	// get Ogre to build and ensure that it always tries to load files
	// that DevIL might be able to load.
	return String("jpg");
    }
}
<|endoftext|>


<commit_before>#include "Browser.h"
#include "Log.h"
#include <map>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cassert>

typedef std::map<const char*, Browser::factory_callback> factory_map;
typedef std::pair<const char*, Browser::factory_callback> pair;
typedef factory_map::iterator iterator;

factory_map* factories = NULL;

Browser::Browser(const browser_context_t& context):
	_bin(0),
	_username(NULL),
	_password(NULL),
	_database(NULL),
	_hostname(NULL){

	set_username(context.user);
	set_password(context.pass);
	set_hostname(context.host);
	set_database(context.name);
}

Browser::~Browser(){
	set_username(NULL);
	set_password(NULL);
	set_hostname(NULL);
	set_database(NULL);
}

void Browser::set_username(const char* username){
	set_string(_username, username);
}

void Browser::set_password(const char* password){
	set_string(_password, password);
}

void Browser::set_database(const char* database){
	set_string(_database, database);
}

void Browser::set_hostname(const char* hostname){
	set_string(_hostname, hostname);
}

void Browser::set_string(char*& dst, const char* src){
	free(dst);
	dst = NULL;

	if ( !src ){
		return;
	}

	dst = (char*)malloc( strlen(src) + 1 );
	strcpy(dst, src);
}

void Browser::register_factory(factory_callback callback, const char* name){
	if ( !factories ){
		factories = new factory_map;
	}

	factories->insert(pair(name, callback));
}

Browser* Browser::factory(const char* string, const char* password){
	if ( !(factories && string) ){
		return NULL;
	}

	browser_context_t context = get_context(string);

	// If the contex doesn't contain a password and a password was passed from stdin (arg password)
	// we set that as the password in the context.
	if ( !context.pass && password ){
		context.pass = (char*)malloc( strlen(password) + 1 );
		strcpy(context.pass, password);
	}

	for ( iterator it = factories->begin(); it != factories->end(); ++it ){
		if ( strcmp(context.provider, it->first) == 0){
			Browser* browser = it->second(context);
			free_context(context);
			return browser;
		}
	}

	Log::message(Log::Warning, "Unknown database provider '%s'\n", context.provider);

	free_context(context);

	return NULL;
}
<commit_msg>Removed some includes<commit_after>#include "Browser.h"
#include "Log.h"
#include <map>
#include <cstring>
#include <cstdlib>

typedef std::map<const char*, Browser::factory_callback> factory_map;
typedef std::pair<const char*, Browser::factory_callback> pair;
typedef factory_map::iterator iterator;

factory_map* factories = NULL;

Browser::Browser(const browser_context_t& context):
	_bin(0),
	_username(NULL),
	_password(NULL),
	_database(NULL),
	_hostname(NULL){

	set_username(context.user);
	set_password(context.pass);
	set_hostname(context.host);
	set_database(context.name);
}

Browser::~Browser(){
	set_username(NULL);
	set_password(NULL);
	set_hostname(NULL);
	set_database(NULL);
}

void Browser::set_username(const char* username){
	set_string(_username, username);
}

void Browser::set_password(const char* password){
	set_string(_password, password);
}

void Browser::set_database(const char* database){
	set_string(_database, database);
}

void Browser::set_hostname(const char* hostname){
	set_string(_hostname, hostname);
}

void Browser::set_string(char*& dst, const char* src){
	free(dst);
	dst = NULL;

	if ( !src ){
		return;
	}

	dst = (char*)malloc( strlen(src) + 1 );
	strcpy(dst, src);
}

void Browser::register_factory(factory_callback callback, const char* name){
	if ( !factories ){
		factories = new factory_map;
	}

	factories->insert(pair(name, callback));
}

Browser* Browser::factory(const char* string, const char* password){
	if ( !(factories && string) ){
		return NULL;
	}

	browser_context_t context = get_context(string);

	// If the contex doesn't contain a password and a password was passed from stdin (arg password)
	// we set that as the password in the context.
	if ( !context.pass && password ){
		context.pass = (char*)malloc( strlen(password) + 1 );
		strcpy(context.pass, password);
	}

	for ( iterator it = factories->begin(); it != factories->end(); ++it ){
		if ( strcmp(context.provider, it->first) == 0){
			Browser* browser = it->second(context);
			free_context(context);
			return browser;
		}
	}

	Log::message(Log::Warning, "Unknown database provider '%s'\n", context.provider);

	free_context(context);

	return NULL;
}
<|endoftext|>


<commit_before>#include "Context.h"

#include <cmath>
#include <iostream>

#ifdef OPENGL
#include <glm/glm.hpp>
#endif

using namespace std;
using namespace canvas;

void
Context::resize(unsigned int _width, unsigned int _height) {
  width = _width;
  height = _height;
  getDefaultSurface().resize(_width, _height);
}

void
Context::rect(double x, double y, double w, double h) {
  moveTo(x, y);
  lineTo(x + w, y);
  lineTo(x + w, y + h);
  lineTo(x, y + h);
  closePath();
}

void
Context::fillRect(double x, double y, double w, double h) {
  save();
  beginPath();
  rect(x, y, w, h);
  fill();
  beginPath(); // tmp fix
  restore();
}

void
Context::strokeRect(double x, double y, double w, double h) {
  beginPath();
  rect(x, y, w, h);
  stroke();
}

void
Context::fillText(const std::string & text, double x, double y) {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * bx, getDefaultSurface().getHeight() + 2 * by);
    Style shadow_style = shadowColor;
    shadow->fillText(font, shadow_style, textBaseline, textAlign, text, x + shadowOffsetX + bx, y + shadowOffsetY + by);
    shadow->gaussianBlur(bx, by);
    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().fillText(font, fillStyle, textBaseline, textAlign, text, x, y);
}

void
Context::strokeText(const std::string & text, double x, double y) {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * bx, getDefaultSurface().getHeight() + 2 * by);
    Style shadow_style = shadowColor;
    shadow->strokeText(font, shadow_style, textBaseline, textAlign, text, x + shadowOffsetX + bx, y + shadowOffsetY + by);
    shadow->gaussianBlur(bx, by);
    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().strokeText(font, strokeStyle, textBaseline, textAlign, text, x, y);
}

void
Context::fill() {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * bx, getDefaultSurface().getHeight() + 2 * by);
    Style shadow_style = shadowColor;
    Path tmp_path = current_path;
    tmp_path.offset(shadowOffsetX + bx, shadowOffsetY + by);

    shadow->fill(tmp_path, shadow_style);
    shadow->gaussianBlur(bx, by);

    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().fill(current_path, fillStyle);
}

void
Context::stroke() {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * bx, getDefaultSurface().getHeight() + 2 * by);
    Style shadow_style = shadowColor;
    Path tmp_path = current_path;
    tmp_path.offset(shadowOffsetX + bx, shadowOffsetY + by);

    shadow->stroke(tmp_path, shadow_style, lineWidth);
    shadow->gaussianBlur(bx, by);

    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().stroke(current_path, strokeStyle, lineWidth);
}

void
Context::drawImage(Surface & img, double x, double y, double w, double h) {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * bx, getDefaultSurface().getHeight() + 2 * by);

    shadow->drawImage(img, x + shadowOffsetX + bx, y + shadowOffsetY + by, w, h, globalAlpha);
    shadow->colorFill(shadowColor);
    shadow->gaussianBlur(bx, by);

    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().drawImage(img, x, y, w, h, globalAlpha);
}
<commit_msg>cast floats to int<commit_after>#include "Context.h"

#include <cmath>
#include <iostream>

#ifdef OPENGL
#include <glm/glm.hpp>
#endif

using namespace std;
using namespace canvas;

void
Context::resize(unsigned int _width, unsigned int _height) {
  width = _width;
  height = _height;
  getDefaultSurface().resize(_width, _height);
}

void
Context::rect(double x, double y, double w, double h) {
  moveTo(x, y);
  lineTo(x + w, y);
  lineTo(x + w, y + h);
  lineTo(x, y + h);
  closePath();
}

void
Context::fillRect(double x, double y, double w, double h) {
  save();
  beginPath();
  rect(x, y, w, h);
  fill();
  beginPath(); // tmp fix
  restore();
}

void
Context::strokeRect(double x, double y, double w, double h) {
  beginPath();
  rect(x, y, w, h);
  stroke();
}

void
Context::fillText(const std::string & text, double x, double y) {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * int(ceil(bx)), getDefaultSurface().getHeight() + 2 * int(ceil(by)));
    Style shadow_style = shadowColor;
    shadow->fillText(font, shadow_style, textBaseline, textAlign, text, x + shadowOffsetX + bx, y + shadowOffsetY + by);
    shadow->gaussianBlur(bx, by);
    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().fillText(font, fillStyle, textBaseline, textAlign, text, x, y);
}

void
Context::strokeText(const std::string & text, double x, double y) {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * int(ceil(bx)), getDefaultSurface().getHeight() + 2 * int(ceil(by)));
    Style shadow_style = shadowColor;
    shadow->strokeText(font, shadow_style, textBaseline, textAlign, text, x + shadowOffsetX + bx, y + shadowOffsetY + by);
    shadow->gaussianBlur(bx, by);
    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().strokeText(font, strokeStyle, textBaseline, textAlign, text, x, y);
}

void
Context::fill() {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * int(ceil(bx)), getDefaultSurface().getHeight() + 2 * int(ceil(by)));
    Style shadow_style = shadowColor;
    Path tmp_path = current_path;
    tmp_path.offset(shadowOffsetX + bx, shadowOffsetY + by);

    shadow->fill(tmp_path, shadow_style);
    shadow->gaussianBlur(bx, by);

    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().fill(current_path, fillStyle);
}

void
Context::stroke() {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * int(ceil(bx)), getDefaultSurface().getHeight() + 2 * int(ceil(by)));
    Style shadow_style = shadowColor;
    Path tmp_path = current_path;
    tmp_path.offset(shadowOffsetX + bx, shadowOffsetY + by);

    shadow->stroke(tmp_path, shadow_style, lineWidth);
    shadow->gaussianBlur(bx, by);

    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().stroke(current_path, strokeStyle, lineWidth);
}

void
Context::drawImage(Surface & img, double x, double y, double w, double h) {
  if (hasShadow()) {
    float bx = shadowBlurX ? shadowBlurX : shadowBlur, by = shadowBlurY ? shadowBlurY : shadowBlur;
    auto shadow = createSurface(getDefaultSurface().getWidth() + 2 * int(ceil(bx)), getDefaultSurface().getHeight() + 2 * int(ceil(by)));

    shadow->drawImage(img, x + shadowOffsetX + bx, y + shadowOffsetY + by, w, h, globalAlpha);
    shadow->colorFill(shadowColor);
    shadow->gaussianBlur(bx, by);

    getDefaultSurface().drawImage(*shadow, -bx, -by, shadow->getWidth(), shadow->getHeight());
  }
  getDefaultSurface().drawImage(img, x, y, w, h, globalAlpha);
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"

TEST(Test, FIRST) {
  EXPECT_EQ(2,1+1);
}
TEST(Test, SECOND) {
  EXPECT_EQ(2,1);
}<commit_msg>[NSTL]fix a test care<commit_after>#include "gtest/gtest.h"

TEST(Test, FIRST) {
  EXPECT_EQ(2,1+1);
}
TEST(Test, SECOND) {
  EXPECT_EQ(2,2*1);
}<|endoftext|>


<commit_before>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <coli/debug.h>
#include <coli/core.h>

#include <string.h>
#include <Halide.h>

/* Halide code.
Func blurxy(Func input, Func blur_y) {
	Func blur_x;
	Var x, y, xi, yi;

	// The algorithm - no storage or order
	blur_x(x, y) = input(x, y) + input(x, y);
	blur_y(x, y) = blur_x(x, y) + blur_x(x, y);

	// The schedule - defines order, locality; implies storage
	blur_y.tile(x, y, xi, yi, 256, 32)
		.vectorize(xi, 8).parallel(y);
	blur_x.compute_at(blur_y, x).vectorize(x, 8);
  }
*/

int main(int argc, char **argv)
{
	// Set default coli options.
	coli::global::set_default_coli_options();

	/*
	 * Declare a function fct.
	 * Declare two arguments (coli buffers) for the function: input and blur_y
	 * Declare an invariant for the function.
	 */
	coli::function fct("blurxy");
	coli::argument a_input(coli::inputarg, "a_input", 2, {100,100}, Halide::Int(8), NULL, &fct);
	coli::argument a_blury(coli::outputarg, "a_blury", 2, {100,100}, Halide::Int(8), NULL, &fct);
	coli::invariant p0("N", Halide::Expr((int32_t) 100), &fct);

	// Declare the computations of the function fct.
	coli::computation computation0("[N]->{c_input[i,j]: 0<=i<N and 0<=j<N}", &a_input, &fct);
	coli::computation computation1("[N]->{c_blurx[i,j]: 0<=i<N and 0<=j<N}", Halide::Expr((uint8_t) 3), &fct);
	coli::computation computation2("[N]->{c_blury[i,j]: 0<=i<N and 0<=j<N}", Halide::Expr((uint8_t) 7), &a_blury, &fct);

	// Create a memory buffer (2 dimensional).
	coli::buffer buf0("b_blurx", 2, {100,100}, Halide::Int(8), NULL, &fct);

	// Map the computations to a buffer (i.e. where each computation
	// should be stored in the buffer).
	// This mapping will be updated automaticall when the schedule
	// is applied.  To disable automatic data mapping updates use
	// coli::global::set_auto_data_mapping(false).
	computation0.set_access("{c_input[i,j]->b_input[i,j]}");
	computation0.set_access("{c_blurx[i,j]->b_blurx[i,j]}");
	computation0.set_access("{c_blury[i,j]->b_blury[i,j]}");

	// Dump the iteration domain (input) for the function.
	fct.dump_iteration_domain();

	// Set the schedule of each computation.
	// The identity schedule means that the program order is not modified
	// (i.e. no optimization is applied).
	c_blurx.tile(0,1,2,2);
	c_blurx.tag_parallel_dimension(0);
	c_blury.set_schedule("{blury[i,j]->[i,j]}");
	c_blury.after(c_blurx, coli::computation::root_dimension);

	// Generate the time-processor domain of the computation
	// and dump it on stdout.
	fct.gen_time_processor_domain();
	fct.dump_time_processor_domain();

	// Generate an AST (abstract Syntax Tree)
	fct.gen_isl_ast();

	// Generate Halide statement for the function.
	fct.gen_halide_stmt();

	// If you want to get the generated halide statements, call
	// fct.get_halide_stmts().

	// Dump the Halide stmt generated by gen_halide_stmt()
	// for the function.
	fct.dump_halide_stmt();

	// Generate an object file from the function.
	fct.gen_halide_obj("build/generated_lib_tutorial_01.o");

	return 0;
}
<commit_msg>Update tutorial<commit_after>#include <isl/set.h>
#include <isl/union_map.h>
#include <isl/union_set.h>
#include <isl/ast_build.h>
#include <isl/schedule.h>
#include <isl/schedule_node.h>

#include <coli/debug.h>
#include <coli/core.h>

#include <string.h>
#include <Halide.h>

/* Halide code.
Func blurxy(Func input, Func blur_y) {
	Func blur_x;
	Var x, y, xi, yi;

	// The algorithm - no storage or order
	blur_x(x, y) = input(x, y) + input(x, y);
	blur_y(x, y) = blur_x(x, y) + blur_x(x, y);

	// The schedule - defines order, locality; implies storage
	blur_y.tile(x, y, xi, yi, 256, 32)
		.vectorize(xi, 8).parallel(y);
	blur_x.compute_at(blur_y, x).vectorize(x, 8);
  }
*/

int main(int argc, char **argv)
{
	// Set default coli options.
	coli::global::set_default_coli_options();

	/*
	 * Declare a function fct.
	 * Declare two arguments (coli buffers) for the function: input and blur_y
	 * Declare an invariant for the function.
	 */
	coli::function blurxy("blurxy");
	coli::argument a_input(coli::inputarg, "a_input", 2, {100,100}, Halide::Int(8), NULL, &fct);
	coli::argument a_blury(coli::outputarg, "a_blury", 2, {100,100}, Halide::Int(8), NULL, &fct);
	coli::invariant N("N", Halide::Expr((int32_t) 100), &fct);

	// Declare the computations of the function fct.
	coli::computation computation0("[N]->{c_input[i,j]: 0<=i<N and 0<=j<N}", &a_input, &fct);
	coli::computation computation1("[N]->{c_blurx[i,j]: 0<=i<N and 0<=j<N}", Halide::Expr((uint8_t) 3), &fct);
	coli::computation computation2("[N]->{c_blury[i,j]: 0<=i<N and 0<=j<N}", Halide::Expr((uint8_t) 7), &a_blury, &fct);

	// Create a memory buffer (2 dimensional).
	coli::buffer buf0("b_blurx", 2, {100,100}, Halide::Int(8), NULL, &fct);

	// Map the computations to a buffer (i.e. where each computation
	// should be stored in the buffer).
	// This mapping will be updated automaticall when the schedule
	// is applied.  To disable automatic data mapping updates use
	// coli::global::set_auto_data_mapping(false).
	computation0.set_access("{c_input[i,j]->b_input[i,j]}");
	computation0.set_access("{c_blurx[i,j]->b_blurx[i,j]}");
	computation0.set_access("{c_blury[i,j]->b_blury[i,j]}");

	// Dump the iteration domain (input) for the function.
	fct.dump_iteration_domain();

	// Set the schedule of each computation.
	// The identity schedule means that the program order is not modified
	// (i.e. no optimization is applied).
	c_blurx.tile(0,1,2,2);
	c_blurx.tag_parallel_dimension(0);
	c_blury.set_schedule("{blury[i,j]->[i,j]}");
	c_blury.after(c_blurx, coli::computation::root_dimension);

	// Generate the time-processor domain of the computation
	// and dump it on stdout.
	fct.gen_time_processor_domain();
	fct.dump_time_processor_domain();

	// Generate an AST (abstract Syntax Tree)
	fct.gen_isl_ast();

	// Generate Halide statement for the function.
	fct.gen_halide_stmt();

	// If you want to get the generated halide statements, call
	// fct.get_halide_stmts().

	// Dump the Halide stmt generated by gen_halide_stmt()
	// for the function.
	fct.dump_halide_stmt();

	// Generate an object file from the function.
	fct.gen_halide_obj("build/generated_lib_tutorial_01.o");

	return 0;
}
<|endoftext|>


<commit_before>#include <climits>
#include <elevator/elevator.h>
#include <elevator/restartwrapper.h>
#include <elevator/test.h>
#include <wibble/raii.h>

namespace elevator {

std::vector< Button > genFloorButtons( const BasicDriverInfo &bi ) {
    std::vector< Button > btns;
    for ( int i = bi.minFloor(); i <= bi.maxFloor(); ++i ) {
        btns.push_back( Button( ButtonType::TargetFloor, i ) );
        if ( i < bi.maxFloor() )
            btns.push_back( Button( ButtonType::CallUp, i ) );
        if ( i > bi.minFloor() )
            btns.push_back( Button( ButtonType::CallDown, i ) );
    }
    return btns;
}

Elevator::Elevator(
        int id,
        HeartBeat &heartbeat,
        ConcurrentQueue< Command > &inCommands,
        ConcurrentQueue< StateChange > &outState
    ) : _terminate( false ),
        _inCommands( inCommands ),
        _outState( outState ),
        _heartbeat( heartbeat ),
        _previousDirection( Direction::None ),
        _lastStateUpdate( 0 ),
        _floorButtons( genFloorButtons( _driver ) )
{
    _elevState.lastFloor = _driver.minFloor();
    _elevState.id = id;
}

Elevator::~Elevator() {
    if ( _thread.joinable() )
        terminate();
}

void Elevator::terminate() {
    assert( _thread.joinable(), "control loop not running" );
    _terminate = true;
    _thread.join();
}

void Elevator::run() {
    _thread = std::thread( restartWrapper( &Elevator::_loop ), this );
}

void Elevator::_addTargetFloor( int floor ) {
    _elevState.insideButtons.set( true, floor, _driver );
}

void Elevator::_removeTargetFloor( int floor ) {
    _elevState.insideButtons.set( false, floor, _driver );
}

void Elevator::assertConsistency() {
    assert_lt( _driver.minFloor(), _driver.maxFloor(), "invalid floor bounds" );
    assert( _previousDirection == Direction::Up || _previousDirection == Direction::Down
            || _previousDirection == Direction::None, "invalid direction" );
    _elevState.assertConsistency( _driver );
    assert_leq( _driver.minFloor(), _elevState.lastFloor, "last floor out of bounds" );
    assert_leq( _elevState.lastFloor, _driver.maxFloor(), "last floor out of bounds" );
}

Button buttonByDirection( Direction dir, int floor ) {
    assert_neq( dir, Direction::None, "Need direction" );

    return dir == Direction::Down
        ? Button( ButtonType::CallDown, floor )
        : Button( ButtonType::CallUp, floor );
}

int Elevator::_updateAndGetFloor() {
    int f = _driver.getFloor();
    if ( f != INT_MIN )
        _elevState.lastFloor = f;
    return f;
}

void Elevator::_stopElevator() {
    if ( _elevState.direction != Direction::None )
        _previousDirection = _elevState.direction;
    _elevState.direction = Direction::None;
    _driver.stopElevator();
}

void Elevator::_startElevator() {
    _startElevator( Direction::None );
}

void Elevator::_startElevator( Direction direction ) {
    _elevState.direction = direction;
    // we may not have current information in _elevState.lastFloor, on the other hand
    // sensor never lies but may not know
    _updateAndGetFloor(); // update information if sensor senses floor
    if ( _elevState.lastFloor == _driver.minFloor() )
        _elevState.direction = Direction::Up;
    else if ( _elevState.lastFloor == _driver.maxFloor() )
        _elevState.direction = Direction::Down;
    // if we have no clue select direction by requests
    if ( _elevState.direction == Direction::None )
        _elevState.direction = _optimalDirection();
    _driver.setMotorSpeed( _elevState.direction, _speed );
    _driver.setDoorOpenLamp( false );
}

Direction Elevator::_optimalDirection() const {
    int lowerThan{ 0 }, higherThan { 0 };
    FloorSet floorsToServe = _elevState.insideButtons;
    if ( !floorsToServe.hasAny() ) {
        floorsToServe |= _elevState.upButtons;
        floorsToServe |= _elevState.downButtons;
    }
    for ( int i = _driver.minFloor(); i <= _driver.maxFloor(); ++i ) {
        if ( floorsToServe.get( i, _driver ) ) {
            if ( i > _elevState.lastFloor )
                ++higherThan;
            if ( i < _elevState.lastFloor )
                ++lowerThan;
        }
    }
    return higherThan >= lowerThan ? Direction::Up : Direction::Down;
}

/* we want to prioritize inside buttons, imagine:
 * - elevator is on floor 3 and last went up, inside is pressed 2, outside 4
 *   normally we preffer continuing withing last direction to avoid malicious
 *   co-travellers from calling elevator to other direction from inside,
 *   but this must work only for inside buttons, we don't want elevator
 *   to be called to floor 4 in this situation
 */
bool Elevator::_priorityFloorsInDirection( Direction direction ) const {
    if ( direction == Direction::Down )
        return _elevState.insideButtons.anyLower( _elevState.lastFloor, _driver );
    if ( direction == Direction::Up )
        return _elevState.insideButtons.anyHigher( _elevState.lastFloor, _driver );
    return false;
}

void Elevator::_emitStateChange( ChangeType type, int floor ) {
    StateChange change;
    change.state = _elevState;
    change.changeType = type;
    change.changeFloor = floor;
    _lastStateUpdate = change.state.timestamp = now();
    _outState.enqueue( change );
}

void Elevator::_setButtonLampAndFlag( Button btn, bool val ) {
    _driver.setButtonLamp( btn, val );
    if ( btn.type() == ButtonType::TargetFloor )
        _elevState.insideButtons.set( val, btn.floor(), _driver );
}

ChangeType changeTypeByButton( ButtonType btnt ) {
    switch ( btnt ) {
        case ButtonType::CallUp:
            return ChangeType::ButtonDownPressed;
        case ButtonType::CallDown:
            return ChangeType::ButtonUpPressed;
        case ButtonType::TargetFloor:
            return ChangeType::InsideButtonPresed;
        default: assert_unreachable();
    }
}

FloorSet Elevator::_allButtons() const {
    return _elevState.insideButtons | _elevState.upButtons | _elevState.downButtons;
}

bool Elevator::_shouldStop( int currentFloor ) const {
    /* stop if this floor was requested from inside or if we are moving
     * in direction of pressed outside button
     * the special case of topmost/bottommost floor need not to be
     * handled as elevator stops there anyway
     */
    return   _elevState.insideButtons.get( currentFloor, _driver )
        || ( _elevState.direction == Direction::Up
                && _elevState.upButtons.get( currentFloor, _driver ) )
        || ( _elevState.direction == Direction::Down
                && _elevState.downButtons.get( currentFloor, _driver ) );
}

void Elevator::_clearDirectionButtonLamp() {
    Button b;
    if ( _elevState.lastFloor == _driver.maxFloor() )
        b = Button{ ButtonType::CallDown, _driver.maxFloor() };
    else if ( _elevState.lastFloor == _driver.minFloor() )
        b = Button{ ButtonType::CallUp, _driver.minFloor() };
    else
        b = buttonByDirection( _elevState.direction, _elevState.lastFloor );

    if ( b.type() == ButtonType::CallUp ) {
        if ( _elevState.upButtons.set( false, b.floor(), _driver ) )
            _emitStateChange( ChangeType::ServedUp, b.floor() );
    } else {
        if ( _elevState.downButtons.set( false, b.floor(), _driver ) )
            _emitStateChange( ChangeType::ServedDown, b.floor() );
    }
    _driver.setButtonLamp( b, false );
}

void Elevator::_initializeElevator() {
    // initialize according to lights
    for ( auto b : _floorButtons ) {
        if ( _driver.getButtonLamp( b ) ) {
            if ( b.type() == ButtonType::TargetFloor )
                _addTargetFloor( b.floor() );
            else if ( b.type() == ButtonType::CallDown )
                _elevState.downButtons.set( true, b.floor(), _driver );
            else if ( b.type() == ButtonType::CallUp )
                _elevState.upButtons.set( true, b.floor(), _driver );
        }
    }
}

void Elevator::_loop() {
    // no matter whether exit is caused by terminate flag or exception
    // we want to stop elevator (ok, it works only for exceptions caught somewhere
    // above, but nothing better exists and we are catching assertions and
    // restarting)
    auto d_stop = wibble::raii::defer( [&]() { _stopElevator(); } );

    // for some buttons, we need to keep track about changes, so that we
    // can detect button press/release event no just the fact that button
    // is now activated
    FloorSet inFloorButtons, inFloorButtonsLast;
    bool stopLast{ false }, stopNow{ false };

    int prevFloor{ INT_MIN }; // to keep track when to send state update

    MillisecondTime doorWaitingStarted{ 0 }; // for closing doors

    enum class State { Normal, WaitingForInButton, Stopped };
    State state = State::Normal;

    _initializeElevator();
    if ( _driver.getStopLamp() )
        state = State::Stopped;

    while ( !_terminate.load( std::memory_order::memory_order_relaxed ) ) {
        // initialize cycle
        inFloorButtonsLast = inFloorButtons;
        inFloorButtons.reset();
        stopLast = stopNow;

        assertConsistency();

        // handle buttons and lamps
        for ( auto b : _floorButtons ) {
            if ( _driver.getButtonSignal( b ) ) {
                if ( !_driver.getButtonLamp( b ) ) { // new press
                    _setButtonLampAndFlag( b, true );
                    if ( b.type() == ButtonType::TargetFloor ) {
                        // we need to serve this one on this elevator
                        _addTargetFloor( b.floor() );
                    }
                    _emitStateChange( changeTypeByButton( b.type() ), b.floor() );
                }
                // furthermore we need to keep track of pressed inside buttons
                // regardless if they were already lit, this is for the purpose
                // of detection re-pressing inside button to get elevator moving
                // after entering
                if ( b.type() == ButtonType::TargetFloor ) {
                    inFloorButtons.set( true, b.floor(), _driver );
                }
            }
        }

        if ( (stopNow = _driver.getStop()) && stopNow != stopLast ) {
            _elevState.stopped = !_driver.getStopLamp();
            _driver.setStopLamp( _elevState.stopped );

            /* stop button will (surprise) stop the elevator right where it is
             * movement is resumed once button is presses again */
            if ( _elevState.stopped ) {
                _stopElevator();
                state = State::Stopped;
                _emitStateChange( ChangeType::OtherChange, _updateAndGetFloor() );
            } else {
                _startElevator( _previousDirection );
                state = State::Normal;
                _emitStateChange( ChangeType::OtherChange, _updateAndGetFloor() );
            }
        }

        if ( _driver.getObstruction() ) {
            _driver.shutdown();
            while ( _driver.getObstruction() ) {
                /* obstruction causes infinite loop which it turn causes
                 * heartbeat timeout and terminates whole process */
            }
        }

        // must be nonblocking
        auto maybeCommand = _inCommands.tryDequeue();
        if ( !maybeCommand.isNothing() ) {
            auto command = maybeCommand.value();
            assert( command.targetElevatorId == _elevState.id
                    || command.targetElevatorId == Command::ANY_ID, "command to other elevator" );
            switch ( command.commandType ) {
            case CommandType::Empty:
                break;
            case CommandType::CallToFloorAndGoUp:
                _elevState.upButtons.set( true, command.targetFloor, _driver );
                _driver.setButtonLamp( Button{ ButtonType::CallUp, command.targetFloor }, true );
                break;
            case CommandType::CallToFloorAndGoDown:
                _elevState.downButtons.set( true, command.targetFloor, _driver );
                _driver.setButtonLamp( Button{ ButtonType::CallDown, command.targetFloor }, true );
                break;
            case CommandType::TurnOnLightUp:
                _driver.setButtonLamp( Button{ ButtonType::CallUp, command.targetFloor }, true );
                break;
            case CommandType::TurnOffLightUp:
                _driver.setButtonLamp( Button{ ButtonType::CallUp, command.targetFloor }, false );
                break;
            case CommandType::TurnOnLightDown:
                _driver.setButtonLamp( Button{ ButtonType::CallDown, command.targetFloor }, true );
                break;
            case CommandType::TurnOffLightDown:
                _driver.setButtonLamp( Button{ ButtonType::CallDown, command.targetFloor }, false );
                break;
            }
        }

        int currentFloor = _updateAndGetFloor();
        // safety precautions
        if ( currentFloor == _driver.maxFloor() && _elevState.direction == Direction::Up )
            _stopElevator();
        if ( currentFloor == _driver.minFloor() && _elevState.direction == Direction::Down )
            _stopElevator();

        if ( currentFloor != INT_MIN )
            _driver.setFloorIndicator( currentFloor );

        if ( currentFloor != prevFloor )
            _emitStateChange( ChangeType::OtherChange, currentFloor );

        // note: we are here working wich _floorsToServe shared atomic variable
        // it can change between subsequent loads, but only this thread
        // ever removes any floor from it, so there is nothing dangerous in this

        // now do what is needed depending on state
        if ( state == State::Normal ) {

            // check if we arrived at any floor which was scheduled for us
            if ( currentFloor != INT_MIN && _shouldStop( currentFloor ) ) {
                // turn off button lights
                _setButtonLampAndFlag( Button( ButtonType::TargetFloor, currentFloor ), false );
                // open doors
                _driver.setDoorOpenLamp( true );
                state = State::WaitingForInButton;
                doorWaitingStarted = now();
                _stopElevator();
                // this floor is served
                _removeTargetFloor( currentFloor );
                _emitStateChange( ChangeType::Served, currentFloor );
            } else if ( _elevState.direction == Direction::None && _allButtons().hasAny() ) {
                // we are not moving but we can
                if ( _priorityFloorsInDirection( _previousDirection ) )
                    _startElevator( _previousDirection );
                else
                    _startElevator(); // decides which direction is better itself

                _emitStateChange( ChangeType::OtherChange, currentFloor );
                _clearDirectionButtonLamp();
            }

        } else if ( state == State::WaitingForInButton ) {
            if ( FloorSet::hasAdditional( inFloorButtonsLast, inFloorButtons )
                    || (doorWaitingStarted + _waitThreshold) < now() )
            {
                _driver.setDoorOpenLamp( false );
                state = State::Normal;
            }
        } else if ( state == State::Stopped ) {
            // nothing to do
        } else {
            assert_unreachable();
        }

        if ( _lastStateUpdate + _keepAlive <= now() )
            _emitStateChange( ChangeType::KeepAlive, currentFloor );

        // it is important to do heartbeat at the end so that we don't end up
        // beating even in case we are repeatedlay auto-restarted due to assertion
        // we don't need to care about beating too often, it is cheap and safe
        _heartbeat.beat();
        prevFloor = currentFloor;
    }
}

}
<commit_msg>elevator: Tweak outside button turnoff contidions.<commit_after>#include <climits>
#include <elevator/elevator.h>
#include <elevator/restartwrapper.h>
#include <elevator/test.h>
#include <wibble/raii.h>

namespace elevator {

std::vector< Button > genFloorButtons( const BasicDriverInfo &bi ) {
    std::vector< Button > btns;
    for ( int i = bi.minFloor(); i <= bi.maxFloor(); ++i ) {
        btns.push_back( Button( ButtonType::TargetFloor, i ) );
        if ( i < bi.maxFloor() )
            btns.push_back( Button( ButtonType::CallUp, i ) );
        if ( i > bi.minFloor() )
            btns.push_back( Button( ButtonType::CallDown, i ) );
    }
    return btns;
}

Elevator::Elevator(
        int id,
        HeartBeat &heartbeat,
        ConcurrentQueue< Command > &inCommands,
        ConcurrentQueue< StateChange > &outState
    ) : _terminate( false ),
        _inCommands( inCommands ),
        _outState( outState ),
        _heartbeat( heartbeat ),
        _previousDirection( Direction::None ),
        _lastStateUpdate( 0 ),
        _floorButtons( genFloorButtons( _driver ) )
{
    _elevState.lastFloor = _driver.minFloor();
    _elevState.id = id;
}

Elevator::~Elevator() {
    if ( _thread.joinable() )
        terminate();
}

void Elevator::terminate() {
    assert( _thread.joinable(), "control loop not running" );
    _terminate = true;
    _thread.join();
}

void Elevator::run() {
    _thread = std::thread( restartWrapper( &Elevator::_loop ), this );
}

void Elevator::_addTargetFloor( int floor ) {
    _elevState.insideButtons.set( true, floor, _driver );
}

void Elevator::_removeTargetFloor( int floor ) {
    _elevState.insideButtons.set( false, floor, _driver );
}

void Elevator::assertConsistency() {
    assert_lt( _driver.minFloor(), _driver.maxFloor(), "invalid floor bounds" );
    assert( _previousDirection == Direction::Up || _previousDirection == Direction::Down
            || _previousDirection == Direction::None, "invalid direction" );
    _elevState.assertConsistency( _driver );
    assert_leq( _driver.minFloor(), _elevState.lastFloor, "last floor out of bounds" );
    assert_leq( _elevState.lastFloor, _driver.maxFloor(), "last floor out of bounds" );
}

Button buttonByDirection( Direction dir, int floor ) {
    assert_neq( dir, Direction::None, "Need direction" );

    return dir == Direction::Down
        ? Button( ButtonType::CallDown, floor )
        : Button( ButtonType::CallUp, floor );
}

int Elevator::_updateAndGetFloor() {
    int f = _driver.getFloor();
    if ( f != INT_MIN )
        _elevState.lastFloor = f;
    return f;
}

void Elevator::_stopElevator() {
    if ( _elevState.direction != Direction::None )
        _previousDirection = _elevState.direction;
    _elevState.direction = Direction::None;
    _driver.stopElevator();
}

void Elevator::_startElevator() {
    _startElevator( Direction::None );
}

void Elevator::_startElevator( Direction direction ) {
    _elevState.direction = direction;
    // we may not have current information in _elevState.lastFloor, on the other hand
    // sensor never lies but may not know
    _updateAndGetFloor(); // update information if sensor senses floor
    if ( _elevState.lastFloor == _driver.minFloor() )
        _elevState.direction = Direction::Up;
    else if ( _elevState.lastFloor == _driver.maxFloor() )
        _elevState.direction = Direction::Down;
    // if we have no clue select direction by requests
    if ( _elevState.direction == Direction::None )
        _elevState.direction = _optimalDirection();
    _driver.setMotorSpeed( _elevState.direction, _speed );
    _driver.setDoorOpenLamp( false );
}

Direction Elevator::_optimalDirection() const {
    int lowerThan{ 0 }, higherThan { 0 };
    FloorSet floorsToServe = _elevState.insideButtons;
    if ( !floorsToServe.hasAny() ) {
        floorsToServe |= _elevState.upButtons;
        floorsToServe |= _elevState.downButtons;
    }
    for ( int i = _driver.minFloor(); i <= _driver.maxFloor(); ++i ) {
        if ( floorsToServe.get( i, _driver ) ) {
            if ( i > _elevState.lastFloor )
                ++higherThan;
            if ( i < _elevState.lastFloor )
                ++lowerThan;
        }
    }
    return higherThan >= lowerThan ? Direction::Up : Direction::Down;
}

/* we want to prioritize inside buttons, imagine:
 * - elevator is on floor 3 and last went up, inside is pressed 2, outside 4
 *   normally we preffer continuing withing last direction to avoid malicious
 *   co-travellers from calling elevator to other direction from inside,
 *   but this must work only for inside buttons, we don't want elevator
 *   to be called to floor 4 in this situation
 */
bool Elevator::_priorityFloorsInDirection( Direction direction ) const {
    if ( direction == Direction::Down )
        return _elevState.insideButtons.anyLower( _elevState.lastFloor, _driver );
    if ( direction == Direction::Up )
        return _elevState.insideButtons.anyHigher( _elevState.lastFloor, _driver );
    return false;
}

void Elevator::_emitStateChange( ChangeType type, int floor ) {
    StateChange change;
    change.state = _elevState;
    change.changeType = type;
    change.changeFloor = floor;
    _lastStateUpdate = change.state.timestamp = now();
    _outState.enqueue( change );
}

void Elevator::_setButtonLampAndFlag( Button btn, bool val ) {
    _driver.setButtonLamp( btn, val );
    if ( btn.type() == ButtonType::TargetFloor )
        _elevState.insideButtons.set( val, btn.floor(), _driver );
}

ChangeType changeTypeByButton( ButtonType btnt ) {
    switch ( btnt ) {
        case ButtonType::CallUp:
            return ChangeType::ButtonDownPressed;
        case ButtonType::CallDown:
            return ChangeType::ButtonUpPressed;
        case ButtonType::TargetFloor:
            return ChangeType::InsideButtonPresed;
        default: assert_unreachable();
    }
}

FloorSet Elevator::_allButtons() const {
    return _elevState.insideButtons | _elevState.upButtons | _elevState.downButtons;
}

bool Elevator::_shouldStop( int currentFloor ) const {
    /* stop if this floor was requested from inside or if we are moving
     * in direction of pressed outside button
     * the special case of topmost/bottommost floor need not to be
     * handled as elevator stops there anyway
     */
    return   _elevState.insideButtons.get( currentFloor, _driver )
        || ( _elevState.direction == Direction::Up
                && _elevState.upButtons.get( currentFloor, _driver ) )
        || ( _elevState.direction == Direction::Down
                && _elevState.downButtons.get( currentFloor, _driver ) );
}

void Elevator::_clearDirectionButtonLamp() {
    Button b;
    if ( _elevState.lastFloor == _driver.maxFloor() )
        b = Button{ ButtonType::CallDown, _driver.maxFloor() };
    else if ( _elevState.lastFloor == _driver.minFloor() )
        b = Button{ ButtonType::CallUp, _driver.minFloor() };
    else
        b = buttonByDirection( _elevState.direction, _elevState.lastFloor );

    if ( b.type() == ButtonType::CallUp ) {
        if ( _elevState.upButtons.set( false, b.floor(), _driver ) )
            _emitStateChange( ChangeType::ServedUp, b.floor() );
    } else {
        if ( _elevState.downButtons.set( false, b.floor(), _driver ) )
            _emitStateChange( ChangeType::ServedDown, b.floor() );
    }
    _driver.setButtonLamp( b, false );
}

void Elevator::_initializeElevator() {
    // initialize according to lights
    for ( auto b : _floorButtons ) {
        if ( _driver.getButtonLamp( b ) ) {
            if ( b.type() == ButtonType::TargetFloor )
                _addTargetFloor( b.floor() );
            else if ( b.type() == ButtonType::CallDown )
                _elevState.downButtons.set( true, b.floor(), _driver );
            else if ( b.type() == ButtonType::CallUp )
                _elevState.upButtons.set( true, b.floor(), _driver );
        }
    }
}

void Elevator::_loop() {
    // no matter whether exit is caused by terminate flag or exception
    // we want to stop elevator (ok, it works only for exceptions caught somewhere
    // above, but nothing better exists and we are catching assertions and
    // restarting)
    auto d_stop = wibble::raii::defer( [&]() { _stopElevator(); } );

    // for some buttons, we need to keep track about changes, so that we
    // can detect button press/release event no just the fact that button
    // is now activated
    FloorSet inFloorButtons, inFloorButtonsLast;
    bool stopLast{ false }, stopNow{ false };

    int prevFloor{ INT_MIN }; // to keep track when to send state update

    MillisecondTime doorWaitingStarted{ 0 }; // for closing doors

    enum class State { Normal, WaitingForInButton, Stopped };
    State state = State::Normal;

    _initializeElevator();
    if ( _driver.getStopLamp() )
        state = State::Stopped;

    while ( !_terminate.load( std::memory_order::memory_order_relaxed ) ) {
        // initialize cycle
        inFloorButtonsLast = inFloorButtons;
        inFloorButtons.reset();
        stopLast = stopNow;

        assertConsistency();

        // handle buttons and lamps
        for ( auto b : _floorButtons ) {
            if ( _driver.getButtonSignal( b ) ) {
                if ( !_driver.getButtonLamp( b ) ) { // new press
                    _setButtonLampAndFlag( b, true );
                    if ( b.type() == ButtonType::TargetFloor ) {
                        // we need to serve this one on this elevator
                        _addTargetFloor( b.floor() );
                    }
                    _emitStateChange( changeTypeByButton( b.type() ), b.floor() );
                }
                // furthermore we need to keep track of pressed inside buttons
                // regardless if they were already lit, this is for the purpose
                // of detection re-pressing inside button to get elevator moving
                // after entering
                if ( b.type() == ButtonType::TargetFloor ) {
                    inFloorButtons.set( true, b.floor(), _driver );
                }
            }
        }

        if ( (stopNow = _driver.getStop()) && stopNow != stopLast ) {
            _elevState.stopped = !_driver.getStopLamp();
            _driver.setStopLamp( _elevState.stopped );

            /* stop button will (surprise) stop the elevator right where it is
             * movement is resumed once button is presses again */
            if ( _elevState.stopped ) {
                _stopElevator();
                state = State::Stopped;
                _emitStateChange( ChangeType::OtherChange, _updateAndGetFloor() );
            } else {
                _startElevator( _previousDirection );
                state = State::Normal;
                _emitStateChange( ChangeType::OtherChange, _updateAndGetFloor() );
            }
        }

        if ( _driver.getObstruction() ) {
            _driver.shutdown();
            while ( _driver.getObstruction() ) {
                /* obstruction causes infinite loop which it turn causes
                 * heartbeat timeout and terminates whole process */
            }
        }

        // must be nonblocking
        auto maybeCommand = _inCommands.tryDequeue();
        if ( !maybeCommand.isNothing() ) {
            auto command = maybeCommand.value();
            assert( command.targetElevatorId == _elevState.id
                    || command.targetElevatorId == Command::ANY_ID, "command to other elevator" );
            switch ( command.commandType ) {
            case CommandType::Empty:
                break;
            case CommandType::CallToFloorAndGoUp:
                _elevState.upButtons.set( true, command.targetFloor, _driver );
                _driver.setButtonLamp( Button{ ButtonType::CallUp, command.targetFloor }, true );
                break;
            case CommandType::CallToFloorAndGoDown:
                _elevState.downButtons.set( true, command.targetFloor, _driver );
                _driver.setButtonLamp( Button{ ButtonType::CallDown, command.targetFloor }, true );
                break;
            case CommandType::TurnOnLightUp:
                _driver.setButtonLamp( Button{ ButtonType::CallUp, command.targetFloor }, true );
                break;
            case CommandType::TurnOffLightUp:
                _driver.setButtonLamp( Button{ ButtonType::CallUp, command.targetFloor }, false );
                break;
            case CommandType::TurnOnLightDown:
                _driver.setButtonLamp( Button{ ButtonType::CallDown, command.targetFloor }, true );
                break;
            case CommandType::TurnOffLightDown:
                _driver.setButtonLamp( Button{ ButtonType::CallDown, command.targetFloor }, false );
                break;
            }
        }

        int currentFloor = _updateAndGetFloor();
        // safety precautions
        if ( currentFloor == _driver.maxFloor() && _elevState.direction == Direction::Up )
            _stopElevator();
        if ( currentFloor == _driver.minFloor() && _elevState.direction == Direction::Down )
            _stopElevator();

        if ( currentFloor != INT_MIN )
            _driver.setFloorIndicator( currentFloor );

        if ( currentFloor != prevFloor )
            _emitStateChange( ChangeType::OtherChange, currentFloor );

        // note: we are here working wich _floorsToServe shared atomic variable
        // it can change between subsequent loads, but only this thread
        // ever removes any floor from it, so there is nothing dangerous in this

        // now do what is needed depending on state
        if ( state == State::Normal ) {

            // check if we arrived at any floor which was scheduled for us
            if ( currentFloor != INT_MIN && _shouldStop( currentFloor ) ) {
                // turn off button lights
                _setButtonLampAndFlag( Button( ButtonType::TargetFloor, currentFloor ), false );
                // open doors
                _driver.setDoorOpenLamp( true );
                state = State::WaitingForInButton;
                doorWaitingStarted = now();
                _stopElevator();
                // this floor is served
                _removeTargetFloor( currentFloor );
                _emitStateChange( ChangeType::Served, currentFloor );
            } else if ( _elevState.direction == Direction::None ) {
                if ( _allButtons().hasAny() ) {
                    // we are not moving but we can
                    if ( _priorityFloorsInDirection( _previousDirection ) )
                        _startElevator( _previousDirection );
                    else
                        _startElevator(); // decides which direction is better itself

                    _emitStateChange( ChangeType::OtherChange, currentFloor );
                }
                _clearDirectionButtonLamp();
            }

        } else if ( state == State::WaitingForInButton ) {
            bool timeout = (doorWaitingStarted + _waitThreshold) < now();
            if ( FloorSet::hasAdditional( inFloorButtonsLast, inFloorButtons ) || timeout )
            {
                _driver.setDoorOpenLamp( false );
                state = State::Normal;
                if ( timeout ) {
                    _elevState.downButtons.set( false, currentFloor, _driver );
                    _elevState.upButtons.set( false, currentFloor, _driver );
                    _driver.setButtonLamp( Button{ ButtonType::CallUp, currentFloor }, false );
                    _driver.setButtonLamp( Button{ ButtonType::CallDown, currentFloor }, false );
                }
            }
        } else if ( state == State::Stopped ) {
            // nothing to do
        } else {
            assert_unreachable();
        }

        if ( _lastStateUpdate + _keepAlive <= now() )
            _emitStateChange( ChangeType::KeepAlive, currentFloor );

        // it is important to do heartbeat at the end so that we don't end up
        // beating even in case we are repeatedlay auto-restarted due to assertion
        // we don't need to care about beating too often, it is cheap and safe
        _heartbeat.beat();
        prevFloor = currentFloor;
    }
}

}
<|endoftext|>


<commit_before>/*
 * $Id$
 *
 * Copyright(C) 1998-2005 Satoshi Nakamura
 * All rights reserved.
 *
 */

#include <qsconv.h>
#include <qsstream.h>

using namespace qs;

/****************************************************************************
 *
 * Writer
 *
 */

qs::Writer::~Writer()
{
}

/****************************************************************************
 *
 * OutputStreamWriterImpl
 *
 */

struct qs::OutputStreamWriterImpl
{
	enum {
		BUFFER_SIZE	= 8192
	};

	bool flushBuffer();
	bool write(const WCHAR* p,
			   size_t nSize);

	OutputStream* pOutputStream_;
	bool bDelete_;
	std::auto_ptr<Converter> pConverter_;
	WCHAR* pBuf_;
	WCHAR* pBufEnd_;
	WCHAR* pCurrent_;
};

bool qs::OutputStreamWriterImpl::flushBuffer()
{
	if (pCurrent_ != pBuf_) {
		size_t nLen = pCurrent_ - pBuf_;
		xstring_size_ptr encoded(pConverter_->encode(pBuf_, &nLen));
		if (!encoded.get())
			return false;

		if (pOutputStream_->write(
			reinterpret_cast<unsigned char*>(encoded.get()), encoded.size()) == -1)
			return false;

		if (nLen != static_cast<size_t>(pCurrent_ - pBuf_))
			memmove(pBuf_, pCurrent_, (pCurrent_ - pBuf_ - nLen)*sizeof(WCHAR));
		pCurrent_ -= nLen;
	}

	return true;
}

bool qs::OutputStreamWriterImpl::write(const WCHAR* p,
									   size_t nSize)
{
	assert(p);
	assert(nSize > static_cast<size_t>(pBufEnd_ - pCurrent_));

	while (nSize != 0) {
		if (pCurrent_ == pBuf_) {
			size_t nLen = nSize;
			xstring_size_ptr encoded(pConverter_->encode(p, &nLen));
			if (!encoded.get())
				return false;
			assert(nSize - nLen < BUFFER_SIZE);

			if (pOutputStream_->write(
				reinterpret_cast<unsigned char*>(encoded.get()), encoded.size()) == -1)
				return false;

			if (nLen != nSize)
				memcpy(pBuf_, p + nLen, nSize - nLen);
			pCurrent_ = pBuf_ + (nSize - nLen);

			nSize = 0;
		}
		else {
			size_t nRest = pCurrent_ - pBuf_;
			size_t nLen = QSMAX(static_cast<size_t>(pBufEnd_ - pCurrent_), nSize);
			memcpy(pCurrent_, p, nLen);

			WCHAR* pCurrentOld = pCurrent_;
			if (!flushBuffer())
				return false;

			if (pCurrent_ != pBuf_ &&
				static_cast<size_t>(pCurrentOld - pCurrent_) >= nRest) {
				p += pCurrentOld - pCurrent_ - nRest;
				nSize -= pCurrentOld - pCurrent_ - nRest;
				pCurrent_ = pBuf_;
			}
			else {
				p += nLen;
				nSize -= nLen;
			}
		}
	}

	return true;
}

/****************************************************************************
 *
 * OutputStreamWriter
 *
 */

qs::OutputStreamWriter::OutputStreamWriter(OutputStream* pOutputStream,
										   bool bDelete,
										   const WCHAR* pwszEncoding) :
	pImpl_(0)
{
	assert(pOutputStream);

	malloc_ptr<WCHAR> pBuf(static_cast<WCHAR*>(
		malloc(OutputStreamWriterImpl::BUFFER_SIZE*sizeof(WCHAR))));
	if (!pBuf.get())
		return;

	if (!pwszEncoding)
		pwszEncoding = getSystemEncoding();
	std::auto_ptr<Converter> pConverter(ConverterFactory::getInstance(pwszEncoding));
	if (!pConverter.get())
		return;

	pImpl_ = new OutputStreamWriterImpl();
	pImpl_->pOutputStream_ = pOutputStream;
	pImpl_->bDelete_ = bDelete;
	pImpl_->pConverter_ = pConverter;
	pImpl_->pBuf_ = pBuf.release();
	pImpl_->pBufEnd_ = pImpl_->pBuf_ + OutputStreamWriterImpl::BUFFER_SIZE;
	pImpl_->pCurrent_ = pImpl_->pBuf_;
}

qs::OutputStreamWriter::~OutputStreamWriter()
{
	if (pImpl_) {
		if (pImpl_->bDelete_)
			delete pImpl_->pOutputStream_;
		free(pImpl_->pBuf_);
		delete pImpl_;
		pImpl_ = 0;
	}
}

bool qs::OutputStreamWriter::operator!() const
{
	return pImpl_ == 0;
}

bool qs::OutputStreamWriter::close()
{
	if (!pImpl_->flushBuffer())
		return false;
	return pImpl_->pOutputStream_->close();
}

size_t qs::OutputStreamWriter::write(const WCHAR* p, size_t nWrite)
{
	assert(p);

	if (static_cast<size_t>(pImpl_->pBufEnd_ - pImpl_->pCurrent_) >= nWrite) {
		memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
		pImpl_->pCurrent_ += nWrite;
	}
	else {
		if (!pImpl_->flushBuffer())
			return -1;

		if (nWrite > static_cast<size_t>(pImpl_->pBufEnd_ - pImpl_->pCurrent_)) {
			if (!pImpl_->write(p, nWrite))
				return -1;
		}
		else {
			memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
			pImpl_->pCurrent_ += nWrite;
		}
	}

	return nWrite;
}

/****************************************************************************
 *
 * StringWriterImpl
 *
 */

struct qs::StringWriterImpl
{
	enum {
		BUFFER_SIZE	= 256
	};

	bool allocBuffer(size_t nSize);

	wxstring_ptr wstr_;
	WCHAR* pEnd_;
	WCHAR* pCurrent_;
};

bool qs::StringWriterImpl::allocBuffer(size_t nSize)
{
	size_t nNewSize = 0;
	if (!wstr_.get()) {
		nNewSize = QSMAX(static_cast<size_t>(BUFFER_SIZE), nSize);
	}
	else {
		nNewSize = pEnd_ - wstr_.get();
		nNewSize += QSMAX(nNewSize, nSize);
	}

	size_t nLen = pCurrent_ - wstr_.get();
	if (!wstr_.get())
		wstr_ = allocWXString(nNewSize);
	else
		wstr_ = reallocWXString(wstr_, nNewSize);
	if (!wstr_.get())
		return false;
	pEnd_ = wstr_.get() + nNewSize;
	pCurrent_ = wstr_.get() + nLen;

	return true;
}

/****************************************************************************
 *
 * StringWriter
 *
 */

qs::StringWriter::StringWriter() :
	pImpl_(0)
{
	pImpl_ = new StringWriterImpl();
	pImpl_->pEnd_ = 0;
	pImpl_->pCurrent_ = 0;
}

qs::StringWriter::~StringWriter()
{
	delete pImpl_;
	pImpl_ = 0;
}

bool qs::StringWriter::close()
{
	return true;
}

size_t qs::StringWriter::write(const WCHAR* p, size_t nWrite)
{
	if (static_cast<size_t>(pImpl_->pEnd_ - pImpl_->pCurrent_) < nWrite) {
		if (!pImpl_->allocBuffer(nWrite))
			return -1;
	}
	memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
	pImpl_->pCurrent_ += nWrite;

	return nWrite;
}

/****************************************************************************
 *
 * BufferedWriterImpl
 *
 */

struct qs::BufferedWriterImpl
{
	enum {
		BUFFER_SIZE	= 4096
	};

	bool flushBuffer();

	Writer* pWriter_;
	bool bDelete_;
	auto_ptr_array<WCHAR> pBuf_;
	WCHAR* pBufEnd_;
	WCHAR* pCurrent_;
};

bool qs::BufferedWriterImpl::flushBuffer()
{
	if (pCurrent_ != pBuf_.get()) {
		if (pWriter_->write(pBuf_.get(), pCurrent_ - pBuf_.get()) == -1)
			return false;
		pCurrent_ = pBuf_.get();
	}
	return true;
}

/****************************************************************************
 *
 * BufferedWriter
 *
 */

qs::BufferedWriter::BufferedWriter(Writer* pWriter,
								   bool bDelete) :
	pImpl_(0)
{
	auto_ptr_array<WCHAR> pBuf(new WCHAR[BufferedWriterImpl::BUFFER_SIZE]);

	pImpl_ = new BufferedWriterImpl();
	pImpl_->pWriter_ = pWriter;
	pImpl_->bDelete_ = bDelete;
	pImpl_->pBuf_ = pBuf;
	pImpl_->pBufEnd_ = pImpl_->pBuf_.get() + BufferedWriterImpl::BUFFER_SIZE;
	pImpl_->pCurrent_ = pImpl_->pBuf_.get();
}

qs::BufferedWriter::~BufferedWriter()
{
	if (pImpl_) {
		if (pImpl_->bDelete_)
			delete pImpl_->pWriter_;
		delete pImpl_;
		pImpl_ = 0;
	}
}

bool qs::BufferedWriter::newLine()
{
	return write(L"\r\n", 2) == 2;
}

bool qs::BufferedWriter::close()
{
	if (!pImpl_->flushBuffer())
		return false;
	return pImpl_->pWriter_->close();
}

size_t qs::BufferedWriter::write(const WCHAR* p,
								 size_t nWrite)
{
	assert(p);

	if (static_cast<size_t>(pImpl_->pBufEnd_ - pImpl_->pCurrent_) >= nWrite) {
		memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
		pImpl_->pCurrent_ += nWrite;
	}
	else {
		if (!pImpl_->flushBuffer())
			return -1;

		if (nWrite > BufferedWriterImpl::BUFFER_SIZE/2) {
			if (pImpl_->pWriter_->write(p, nWrite) == -1)
				return -1;
		}
		else {
			memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
			pImpl_->pCurrent_ += nWrite;
		}
	}
	return nWrite;
}
<commit_msg>OutputStreamWriter converts new lines.<commit_after>/*
 * $Id$
 *
 * Copyright(C) 1998-2005 Satoshi Nakamura
 * All rights reserved.
 *
 */

#include <qsconv.h>
#include <qsstream.h>

using namespace qs;

/****************************************************************************
 *
 * Writer
 *
 */

qs::Writer::~Writer()
{
}

/****************************************************************************
 *
 * OutputStreamWriterImpl
 *
 */

struct qs::OutputStreamWriterImpl
{
	enum {
		BUFFER_SIZE	= 8192
	};

	bool flushBuffer();
	bool write(const WCHAR* p,
			   size_t nSize);
	bool writeToStream(const unsigned char* p,
					   size_t nLen);

	OutputStream* pOutputStream_;
	bool bDelete_;
	std::auto_ptr<Converter> pConverter_;
	WCHAR* pBuf_;
	WCHAR* pBufEnd_;
	WCHAR* pCurrent_;
};

bool qs::OutputStreamWriterImpl::flushBuffer()
{
	if (pCurrent_ != pBuf_) {
		size_t nLen = pCurrent_ - pBuf_;
		xstring_size_ptr encoded(pConverter_->encode(pBuf_, &nLen));
		if (!encoded.get())
			return false;

		if (!writeToStream(reinterpret_cast<unsigned char*>(encoded.get()), encoded.size()))
			return false;

		if (nLen != static_cast<size_t>(pCurrent_ - pBuf_))
			memmove(pBuf_, pCurrent_, (pCurrent_ - pBuf_ - nLen)*sizeof(WCHAR));
		pCurrent_ -= nLen;
	}

	return true;
}

bool qs::OutputStreamWriterImpl::write(const WCHAR* p,
									   size_t nSize)
{
	assert(p);
	assert(nSize > static_cast<size_t>(pBufEnd_ - pCurrent_));

	while (nSize != 0) {
		if (pCurrent_ == pBuf_) {
			size_t nLen = nSize;
			xstring_size_ptr encoded(pConverter_->encode(p, &nLen));
			if (!encoded.get())
				return false;
			assert(nSize - nLen < BUFFER_SIZE);

			if (!writeToStream(reinterpret_cast<unsigned char*>(encoded.get()), encoded.size()))
				return false;

			if (nLen != nSize)
				memcpy(pBuf_, p + nLen, nSize - nLen);
			pCurrent_ = pBuf_ + (nSize - nLen);

			nSize = 0;
		}
		else {
			size_t nRest = pCurrent_ - pBuf_;
			size_t nLen = QSMAX(static_cast<size_t>(pBufEnd_ - pCurrent_), nSize);
			memcpy(pCurrent_, p, nLen);

			WCHAR* pCurrentOld = pCurrent_;
			if (!flushBuffer())
				return false;

			if (pCurrent_ != pBuf_ &&
				static_cast<size_t>(pCurrentOld - pCurrent_) >= nRest) {
				p += pCurrentOld - pCurrent_ - nRest;
				nSize -= pCurrentOld - pCurrent_ - nRest;
				pCurrent_ = pBuf_;
			}
			else {
				p += nLen;
				nSize -= nLen;
			}
		}
	}

	return true;
}

bool qs::OutputStreamWriterImpl::writeToStream(const unsigned char* p,
											   size_t nLen)
{
	const unsigned char* pszNewLine = reinterpret_cast<const unsigned char*>("\r\n");

	const unsigned char* pBegin = p;
	const unsigned char* pEnd = p + nLen;
	while (true) {
		if (p == pEnd || *p == '\r' || *p == '\n') {
			if (p != pBegin) {
				if (pOutputStream_->write(pBegin, p - pBegin) == -1)
					return false;
			}
			if (p == pEnd) {
				break;
			}
			else if (*p == '\n') {
				if (pOutputStream_->write(pszNewLine, 2) == -1)
					return false;
			}
			pBegin = p + 1;
		}
		++p;
	}

	return true;
}

/****************************************************************************
 *
 * OutputStreamWriter
 *
 */

qs::OutputStreamWriter::OutputStreamWriter(OutputStream* pOutputStream,
										   bool bDelete,
										   const WCHAR* pwszEncoding) :
	pImpl_(0)
{
	assert(pOutputStream);

	malloc_ptr<WCHAR> pBuf(static_cast<WCHAR*>(
		malloc(OutputStreamWriterImpl::BUFFER_SIZE*sizeof(WCHAR))));
	if (!pBuf.get())
		return;

	if (!pwszEncoding)
		pwszEncoding = getSystemEncoding();
	std::auto_ptr<Converter> pConverter(ConverterFactory::getInstance(pwszEncoding));
	if (!pConverter.get())
		return;

	pImpl_ = new OutputStreamWriterImpl();
	pImpl_->pOutputStream_ = pOutputStream;
	pImpl_->bDelete_ = bDelete;
	pImpl_->pConverter_ = pConverter;
	pImpl_->pBuf_ = pBuf.release();
	pImpl_->pBufEnd_ = pImpl_->pBuf_ + OutputStreamWriterImpl::BUFFER_SIZE;
	pImpl_->pCurrent_ = pImpl_->pBuf_;
}

qs::OutputStreamWriter::~OutputStreamWriter()
{
	if (pImpl_) {
		if (pImpl_->bDelete_)
			delete pImpl_->pOutputStream_;
		free(pImpl_->pBuf_);
		delete pImpl_;
		pImpl_ = 0;
	}
}

bool qs::OutputStreamWriter::operator!() const
{
	return pImpl_ == 0;
}

bool qs::OutputStreamWriter::close()
{
	if (!pImpl_->flushBuffer())
		return false;
	return pImpl_->pOutputStream_->close();
}

size_t qs::OutputStreamWriter::write(const WCHAR* p,
									 size_t nWrite)
{
	assert(p);

	if (static_cast<size_t>(pImpl_->pBufEnd_ - pImpl_->pCurrent_) >= nWrite) {
		memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
		pImpl_->pCurrent_ += nWrite;
	}
	else {
		if (!pImpl_->flushBuffer())
			return -1;

		if (nWrite > static_cast<size_t>(pImpl_->pBufEnd_ - pImpl_->pCurrent_)) {
			if (!pImpl_->write(p, nWrite))
				return -1;
		}
		else {
			memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
			pImpl_->pCurrent_ += nWrite;
		}
	}

	return nWrite;
}

/****************************************************************************
 *
 * StringWriterImpl
 *
 */

struct qs::StringWriterImpl
{
	enum {
		BUFFER_SIZE	= 256
	};

	bool allocBuffer(size_t nSize);

	wxstring_ptr wstr_;
	WCHAR* pEnd_;
	WCHAR* pCurrent_;
};

bool qs::StringWriterImpl::allocBuffer(size_t nSize)
{
	size_t nNewSize = 0;
	if (!wstr_.get()) {
		nNewSize = QSMAX(static_cast<size_t>(BUFFER_SIZE), nSize);
	}
	else {
		nNewSize = pEnd_ - wstr_.get();
		nNewSize += QSMAX(nNewSize, nSize);
	}

	size_t nLen = pCurrent_ - wstr_.get();
	if (!wstr_.get())
		wstr_ = allocWXString(nNewSize);
	else
		wstr_ = reallocWXString(wstr_, nNewSize);
	if (!wstr_.get())
		return false;
	pEnd_ = wstr_.get() + nNewSize;
	pCurrent_ = wstr_.get() + nLen;

	return true;
}

/****************************************************************************
 *
 * StringWriter
 *
 */

qs::StringWriter::StringWriter() :
	pImpl_(0)
{
	pImpl_ = new StringWriterImpl();
	pImpl_->pEnd_ = 0;
	pImpl_->pCurrent_ = 0;
}

qs::StringWriter::~StringWriter()
{
	delete pImpl_;
	pImpl_ = 0;
}

bool qs::StringWriter::close()
{
	return true;
}

size_t qs::StringWriter::write(const WCHAR* p, size_t nWrite)
{
	if (static_cast<size_t>(pImpl_->pEnd_ - pImpl_->pCurrent_) < nWrite) {
		if (!pImpl_->allocBuffer(nWrite))
			return -1;
	}
	memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
	pImpl_->pCurrent_ += nWrite;

	return nWrite;
}

/****************************************************************************
 *
 * BufferedWriterImpl
 *
 */

struct qs::BufferedWriterImpl
{
	enum {
		BUFFER_SIZE	= 4096
	};

	bool flushBuffer();

	Writer* pWriter_;
	bool bDelete_;
	auto_ptr_array<WCHAR> pBuf_;
	WCHAR* pBufEnd_;
	WCHAR* pCurrent_;
};

bool qs::BufferedWriterImpl::flushBuffer()
{
	if (pCurrent_ != pBuf_.get()) {
		if (pWriter_->write(pBuf_.get(), pCurrent_ - pBuf_.get()) == -1)
			return false;
		pCurrent_ = pBuf_.get();
	}
	return true;
}

/****************************************************************************
 *
 * BufferedWriter
 *
 */

qs::BufferedWriter::BufferedWriter(Writer* pWriter,
								   bool bDelete) :
	pImpl_(0)
{
	auto_ptr_array<WCHAR> pBuf(new WCHAR[BufferedWriterImpl::BUFFER_SIZE]);

	pImpl_ = new BufferedWriterImpl();
	pImpl_->pWriter_ = pWriter;
	pImpl_->bDelete_ = bDelete;
	pImpl_->pBuf_ = pBuf;
	pImpl_->pBufEnd_ = pImpl_->pBuf_.get() + BufferedWriterImpl::BUFFER_SIZE;
	pImpl_->pCurrent_ = pImpl_->pBuf_.get();
}

qs::BufferedWriter::~BufferedWriter()
{
	if (pImpl_) {
		if (pImpl_->bDelete_)
			delete pImpl_->pWriter_;
		delete pImpl_;
		pImpl_ = 0;
	}
}

bool qs::BufferedWriter::newLine()
{
	return write(L"\r\n", 2) == 2;
}

bool qs::BufferedWriter::close()
{
	if (!pImpl_->flushBuffer())
		return false;
	return pImpl_->pWriter_->close();
}

size_t qs::BufferedWriter::write(const WCHAR* p,
								 size_t nWrite)
{
	assert(p);

	if (static_cast<size_t>(pImpl_->pBufEnd_ - pImpl_->pCurrent_) >= nWrite) {
		memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
		pImpl_->pCurrent_ += nWrite;
	}
	else {
		if (!pImpl_->flushBuffer())
			return -1;

		if (nWrite > BufferedWriterImpl::BUFFER_SIZE/2) {
			if (pImpl_->pWriter_->write(p, nWrite) == -1)
				return -1;
		}
		else {
			memcpy(pImpl_->pCurrent_, p, nWrite*sizeof(WCHAR));
			pImpl_->pCurrent_ += nWrite;
		}
	}
	return nWrite;
}
<|endoftext|>


<commit_before>#include "Genetic.hpp"
#include "Util.hpp"

#include <iostream>

#define GAME_SPEED 0
#define MUT_PROB 0.01

ai::Genetic::Genetic(logic::Game *game, ui::UI *uiPtr)
{
	gameInstance = game;
	ui = uiPtr;

	for (int i = 0; i < POPULATION_SIZE; i++)
	{
		generateRandomCrom(population[i].chromosome, CHROM_LENGTH);
		population[i].fitness = gameInstance->run(population[i].chromosome, GAME_SPEED);
	}
}

void ai::Genetic::run()
{
	int iterations = 0;
	double avg = 0;

	while (iterations < 20000 && avg < 0.99)
	{
		ai::Individual &parent1 = selection();
		ai::Individual &parent2 = selection();

		std::vector<ai::Individual> children;

		crossover(parent1, parent2, children);

		mutation(children[0], MUT_PROB);
		mutation(children[1], MUT_PROB);

		children[0].fitness = gameInstance->run(children[0].chromosome, GAME_SPEED);
		children[1].fitness = gameInstance->run(children[1].chromosome, GAME_SPEED);

		replacement(children[0]);
		replacement(children[1]);

		iterations++;

		avg = ui->showGeneticStats();
	}

	ui->showGeneticStats();
}

ai::Individual& ai::Genetic::selection()
{
	/* Rank-selection (steps):
	// 1. Two chromosomes are chosen randomly.
	// 2. Each chromosome is given a probability (proportionally to their fitness) to be chosen.
	// 3. A random number R [0, 1] is generated.
	// 4. A chromosome is chosen.
	*/

	int first = 0;
	int second = 0;

	while (first == second)
	{
		first = getRandomInteger(0, POPULATION_SIZE - 1);
		second = getRandomInteger(0, POPULATION_SIZE - 1);
	}

	Individual &crom1 = population[first];
	Individual &crom2 = population[second];

	double fitSum = crom1.fitness + crom2.fitness;

	double prob1 = crom1.fitness / fitSum;

	double r = getRandomReal(0, 1);

	if (r < prob1)
	{
		return crom1;
	}

	return crom2;
}

void ai::Genetic::crossover(ai::Individual &parent1, ai::Individual &parent2, std::vector<ai::Individual> &children)
{
	/* Uniform crossover is performed.
	// a random binary mask is generated of the same size of the cromosome
	// for each gen i, if the ith value of the mask is 1, the first child will
	// copy its ith gene from his first parent, and the second child from his second
	// parent. Otherwise if the ith value of the mask is 0.
	*/

	std::vector<bool> mask;
	generateRandomCrom(mask, CHROM_LENGTH);

	ai::Individual child1;
	ai::Individual child2;

	children.push_back(child1);
	children.push_back(child2);

	for (std::size_t i = 0; i < CHROM_LENGTH; i++)
	{
		if (mask[i] == 1)
		{
			children[0].chromosome.push_back(parent1.chromosome[i]);
			children[1].chromosome.push_back(parent2.chromosome[i]);
		}
		else
		{
			children[0].chromosome.push_back(parent2.chromosome[i]);
			children[1].chromosome.push_back(parent1.chromosome[i]);
		}
	}
}

void ai::Genetic::mutation(ai::Individual &ind, double mutationProbability)
{
	for (std::size_t i = 0; i < ind.chromosome.size(); i++)
	{
		double z = getRandomReal(0, 1);

		if (z <= mutationProbability)
		{
			// Value is fliiped.
			ind.chromosome[i] = !ind.chromosome[i];
		}
	}
}

void ai::Genetic::replacement(ai::Individual &ind)
{
	int randIndex = getRandomInteger(0, POPULATION_SIZE - 1);

	if (population[randIndex].fitness < ind.fitness)
	{
		population[randIndex].chromosome = ind.chromosome;
		population[randIndex].fitness = ind.fitness;
	}
}

const ai::Individual* ai::Genetic::getPopulation()
{
	return population;
}<commit_msg>The number of iterations done are now displayed.<commit_after>#include "Genetic.hpp"
#include "Util.hpp"

#include <iostream>

#define GAME_SPEED 0
#define MUT_PROB 0.01

ai::Genetic::Genetic(logic::Game *game, ui::UI *uiPtr)
{
	gameInstance = game;
	ui = uiPtr;

	for (int i = 0; i < POPULATION_SIZE; i++)
	{
		generateRandomCrom(population[i].chromosome, CHROM_LENGTH);
		population[i].fitness = gameInstance->run(population[i].chromosome, GAME_SPEED);
	}
}

void ai::Genetic::run()
{
	int iterations = 0;
	double avg = 0;

	while (iterations < 20000 && avg < 0.99)
	{
		ai::Individual &parent1 = selection();
		ai::Individual &parent2 = selection();

		std::vector<ai::Individual> children;

		crossover(parent1, parent2, children);

		mutation(children[0], MUT_PROB);
		mutation(children[1], MUT_PROB);

		children[0].fitness = gameInstance->run(children[0].chromosome, GAME_SPEED);
		children[1].fitness = gameInstance->run(children[1].chromosome, GAME_SPEED);

		replacement(children[0]);
		replacement(children[1]);

		iterations++;

		avg = ui->showGeneticStats();
	}

	ui->showGeneticStats();
	std::cout << "Number of iterations: " << iterations + 1 << std::endl;
}

ai::Individual& ai::Genetic::selection()
{
	/* Rank-selection (steps):
	// 1. Two chromosomes are chosen randomly.
	// 2. Each chromosome is given a probability (proportionally to their fitness) to be chosen.
	// 3. A random number R [0, 1] is generated.
	// 4. A chromosome is chosen.
	*/

	int first = 0;
	int second = 0;

	while (first == second)
	{
		first = getRandomInteger(0, POPULATION_SIZE - 1);
		second = getRandomInteger(0, POPULATION_SIZE - 1);
	}

	Individual &crom1 = population[first];
	Individual &crom2 = population[second];

	double fitSum = crom1.fitness + crom2.fitness;

	double prob1 = crom1.fitness / fitSum;

	double r = getRandomReal(0, 1);

	if (r < prob1)
	{
		return crom1;
	}

	return crom2;
}

void ai::Genetic::crossover(ai::Individual &parent1, ai::Individual &parent2, std::vector<ai::Individual> &children)
{
	/* Uniform crossover is performed.
	// a random binary mask is generated of the same size of the cromosome
	// for each gen i, if the ith value of the mask is 1, the first child will
	// copy its ith gene from his first parent, and the second child from his second
	// parent. Otherwise if the ith value of the mask is 0.
	*/

	std::vector<bool> mask;
	generateRandomCrom(mask, CHROM_LENGTH);

	ai::Individual child1;
	ai::Individual child2;

	children.push_back(child1);
	children.push_back(child2);

	for (std::size_t i = 0; i < CHROM_LENGTH; i++)
	{
		if (mask[i] == 1)
		{
			children[0].chromosome.push_back(parent1.chromosome[i]);
			children[1].chromosome.push_back(parent2.chromosome[i]);
		}
		else
		{
			children[0].chromosome.push_back(parent2.chromosome[i]);
			children[1].chromosome.push_back(parent1.chromosome[i]);
		}
	}
}

void ai::Genetic::mutation(ai::Individual &ind, double mutationProbability)
{
	for (std::size_t i = 0; i < ind.chromosome.size(); i++)
	{
		double z = getRandomReal(0, 1);

		if (z <= mutationProbability)
		{
			// Value is fliiped.
			ind.chromosome[i] = !ind.chromosome[i];
		}
	}
}

void ai::Genetic::replacement(ai::Individual &ind)
{
	int randIndex = getRandomInteger(0, POPULATION_SIZE - 1);

	if (population[randIndex].fitness < ind.fitness)
	{
		population[randIndex].chromosome = ind.chromosome;
		population[randIndex].fitness = ind.fitness;
	}
}

const ai::Individual* ai::Genetic::getPopulation()
{
	return population;
}<|endoftext|>