<commit_before>#include <pistache/stream.h>

#include "gtest/gtest.h"

#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>

using namespace Pistache;

TEST(stream, test_buffer) {
  char str[] = "test_string";
  size_t len = strlen(str);
  RawBuffer buffer1(str, len, false);

  RawBuffer buffer2 = buffer1.detach(0);
  ASSERT_EQ(buffer2.size(), len);
  ASSERT_EQ(buffer2.isDetached(), true);

  RawBuffer buffer3;
  ASSERT_EQ(buffer3.size(), 0u);
  ASSERT_EQ(buffer3.isDetached(), false);

  RawBuffer buffer4 = buffer3.detach(0);
  ASSERT_EQ(buffer4.size(), 0u);
  ASSERT_EQ(buffer4.isDetached(), false);

  ASSERT_THROW(buffer1.detach(2 * len);, std::range_error);
}

TEST(stream, test_file_buffer) {
  char fileName[PATH_MAX] = "/tmp/pistacheioXXXXXX";
  if (!mkstemp(fileName)) {
    std::cerr << "No suitable filename can be generated!" << std::endl;
  }
  std::cout << "Temporary file name: " << fileName << std::endl;

  const std::string dataToWrite("Hello World!");
  std::ofstream tmpFile;
  tmpFile.open(fileName);
  tmpFile << dataToWrite;
  tmpFile.close();

  FileBuffer fileBuffer(fileName);

  ASSERT_NE(fileBuffer.fd(), -1);
  ASSERT_EQ(fileBuffer.size(), dataToWrite.size());

  std::remove(fileName);
}

TEST(stream, test_dyn_buffer) {
  DynamicStreamBuf buf(128);

  {
    std::ostream os(&buf);

    for (unsigned i = 0; i < 128; ++i) {
      os << "A";
    }
  }

  auto rawbuf = buf.buffer();

  ASSERT_EQ(rawbuf.size(), 128u);
  ASSERT_EQ(rawbuf.isDetached(), false);
  ASSERT_EQ(rawbuf.data().size(), 128u);
  ASSERT_EQ(strlen(rawbuf.data().c_str()), 128u);
}

TEST(stream, test_cursor_advance_for_array) {
  ArrayStreamBuf<char> buffer;
  StreamCursor cursor{&buffer};

  const char* part1 = "abcd";
  buffer.feed(part1, strlen(part1));

  ASSERT_EQ(cursor.current(), 'a');

  ASSERT_TRUE(cursor.advance(1));
  ASSERT_EQ(cursor.current(), 'b');

  ASSERT_TRUE(cursor.advance(0));
  ASSERT_EQ(cursor.current(), 'b');

  ASSERT_TRUE(cursor.advance(1));
  ASSERT_EQ(cursor.current(), 'c');

  const char* part2 = "efgh";
  buffer.feed(part2, strlen(part2));

  ASSERT_TRUE(cursor.advance(2));
  ASSERT_EQ(cursor.current(), 'e');

  ASSERT_FALSE(cursor.advance(5));
}

TEST(stream, test_cursor_remaining_for_array) {
  ArrayStreamBuf<char> buffer;
  StreamCursor cursor{&buffer};

  const char* data = "abcd";
  buffer.feed(data, strlen(data));
  ASSERT_EQ(cursor.remaining(), 4u);

  cursor.advance(2);
  ASSERT_EQ(cursor.remaining(), 2u);

  cursor.advance(1);
  ASSERT_EQ(cursor.remaining(), 1u);

  cursor.advance(1);
  ASSERT_EQ(cursor.remaining(), 0u);
}

TEST(stream, test_cursor_eol_eof_for_array) {
  ArrayStreamBuf<char> buffer;
  StreamCursor cursor{&buffer};

  const char* data = "abcd\r\nefgh";
  buffer.feed(data, strlen(data));

  cursor.advance(4);
  ASSERT_TRUE(cursor.eol());
  ASSERT_FALSE(cursor.eof());

  cursor.advance(2);
  ASSERT_FALSE(cursor.eol());
  ASSERT_FALSE(cursor.eof());

  cursor.advance(4);
  ASSERT_FALSE(cursor.eol());
  ASSERT_TRUE(cursor.eof());
}

TEST(stream, test_cursor_offset_for_array) {
  ArrayStreamBuf<char> buffer;
  StreamCursor cursor{&buffer};

  const char* data = "abcdefgh";
  buffer.feed(data, strlen(data));

  cursor.advance(4);

  ASSERT_TRUE(strcmp(cursor.offset(), "efgh"));
}

TEST(stream, test_cursor_diff_for_array) {
  ArrayStreamBuf<char> buffer1;
  StreamCursor first_cursor{&buffer1};
  ArrayStreamBuf<char> buffer2;
  StreamCursor second_cursor{&buffer2};

  const char* data = "abcdefgh";
  buffer1.feed(data, strlen(data));
  buffer2.feed(data, strlen(data));

  ASSERT_EQ(first_cursor.diff(second_cursor), 0u);
  ASSERT_EQ(second_cursor.diff(first_cursor), 0u);

  first_cursor.advance(4);
  ASSERT_EQ(second_cursor.diff(first_cursor), 4u);

  second_cursor.advance(4);
  ASSERT_EQ(second_cursor.diff(first_cursor), 0u);
}<commit_msg>Fix stream unit test<commit_after>#include <pistache/stream.h>

#include "gtest/gtest.h"

#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>

using namespace Pistache;

TEST(stream, test_buffer) {
  char str[] = "test_string";
  size_t len = strlen(str);
  RawBuffer buffer1(str, len, false);

  RawBuffer buffer2 = buffer1.detach(0);
  ASSERT_EQ(buffer2.size(), len);
  ASSERT_EQ(buffer2.isDetached(), true);

  RawBuffer buffer3;
  ASSERT_EQ(buffer3.size(), 0u);
  ASSERT_EQ(buffer3.isDetached(), false);

  RawBuffer buffer4 = buffer3.detach(0);
  ASSERT_EQ(buffer4.size(), 0u);
  ASSERT_EQ(buffer4.isDetached(), false);

  ASSERT_THROW(buffer1.detach(2 * len);, std::range_error);
}

TEST(stream, test_file_buffer) {
  char fileName[PATH_MAX] = "/tmp/pistacheioXXXXXX";
  if (!mkstemp(fileName)) {
    std::cerr << "No suitable filename can be generated!" << std::endl;
  }
  std::cout << "Temporary file name: " << fileName << std::endl;

  const std::string dataToWrite("Hello World!");
  std::ofstream tmpFile;
  tmpFile.open(fileName);
  tmpFile << dataToWrite;
  tmpFile.close();

  FileBuffer fileBuffer(fileName);

  ASSERT_NE(fileBuffer.fd(), -1);
  ASSERT_EQ(fileBuffer.size(), dataToWrite.size());

  std::remove(fileName);
}

TEST(stream, test_dyn_buffer) {
  DynamicStreamBuf buf(128);

  {
    std::ostream os(&buf);

    for (unsigned i = 0; i < 128; ++i) {
      os << "A";
    }
  }

  auto rawbuf = buf.buffer();

  ASSERT_EQ(rawbuf.size(), 128u);
  ASSERT_EQ(rawbuf.isDetached(), false);
  ASSERT_EQ(rawbuf.data().size(), 128u);
  ASSERT_EQ(strlen(rawbuf.data().c_str()), 128u);
}

TEST(stream, test_cursor_advance_for_array) {
  ArrayStreamBuf<char> buffer;
  StreamCursor cursor{&buffer};

  const char* part1 = "abcd";
  buffer.feed(part1, strlen(part1));

  ASSERT_EQ(cursor.current(), 'a');

  ASSERT_TRUE(cursor.advance(1));
  ASSERT_EQ(cursor.current(), 'b');

  ASSERT_TRUE(cursor.advance(0));
  ASSERT_EQ(cursor.current(), 'b');

  ASSERT_TRUE(cursor.advance(1));
  ASSERT_EQ(cursor.current(), 'c');

  const char* part2 = "efgh";
  buffer.feed(part2, strlen(part2));

  ASSERT_TRUE(cursor.advance(2));
  ASSERT_EQ(cursor.current(), 'e');

  ASSERT_FALSE(cursor.advance(5));
}

TEST(stream, test_cursor_remaining_for_array) {
  ArrayStreamBuf<char> buffer;
  StreamCursor cursor{&buffer};

  const char* data = "abcd";
  buffer.feed(data, strlen(data));
  ASSERT_EQ(cursor.remaining(), 4u);

  cursor.advance(2);
  ASSERT_EQ(cursor.remaining(), 2u);

  cursor.advance(1);
  ASSERT_EQ(cursor.remaining(), 1u);

  cursor.advance(1);
  ASSERT_EQ(cursor.remaining(), 0u);
}

TEST(stream, test_cursor_eol_eof_for_array) {
  ArrayStreamBuf<char> buffer;
  StreamCursor cursor{&buffer};

  const char* data = "abcd\r\nefgh";
  buffer.feed(data, strlen(data));

  cursor.advance(4);
  ASSERT_TRUE(cursor.eol());
  ASSERT_FALSE(cursor.eof());

  cursor.advance(2);
  ASSERT_FALSE(cursor.eol());
  ASSERT_FALSE(cursor.eof());

  cursor.advance(4);
  ASSERT_FALSE(cursor.eol());
  ASSERT_TRUE(cursor.eof());
}

TEST(stream, test_cursor_offset_for_array) {
  ArrayStreamBuf<char> buffer;
  StreamCursor cursor{&buffer};

  const char* data = "abcdefgh";
  buffer.feed(data, strlen(data));

  size_t shift = 4u;
  cursor.advance(shift);

  std::string result{cursor.offset(), strlen(data) - shift};
  ASSERT_EQ(result, "efgh");
}

TEST(stream, test_cursor_diff_for_array) {
  ArrayStreamBuf<char> buffer1;
  StreamCursor first_cursor{&buffer1};
  ArrayStreamBuf<char> buffer2;
  StreamCursor second_cursor{&buffer2};

  const char* data = "abcdefgh";
  buffer1.feed(data, strlen(data));
  buffer2.feed(data, strlen(data));

  ASSERT_EQ(first_cursor.diff(second_cursor), 0u);
  ASSERT_EQ(second_cursor.diff(first_cursor), 0u);

  first_cursor.advance(4);
  ASSERT_EQ(second_cursor.diff(first_cursor), 4u);

  second_cursor.advance(4);
  ASSERT_EQ(second_cursor.diff(first_cursor), 0u);
}
<|endoftext|>


<commit_before><commit_msg>fix unit tests<commit_after><|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2015 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "PipeFile.h"
#include "../stringtools.h"
#include "../Interface/Server.h"
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdlib.h>
#include "../config.h"
#if defined(HAVE_SPAWN_H)
#include <spawn.h>
#endif
#include <sys/stat.h>
#include <fcntl.h>

#if defined(O_CLOEXEC) && !defined(__APPLE__) && !defined(__FreeBSD__)
#define clopipe(x) pipe2(x, O_CLOEXEC)
#else
int clopipe(int* x)
{
        int rc = pipe(x);
        if(rc!=0) return rc;
        fcntl(x[0], F_SETFD, FD_CLOEXEC);
        fcntl(x[1], F_SETFD, FD_CLOEXEC);
        return rc;
}
#endif

PipeFile::PipeFile(const std::string& pCmd)
	: PipeFileBase(pCmd),
		hStderr(0),
		hStdout(0)
{
	int stdout_pipe[2];

	if(clopipe(stdout_pipe) == -1)
	{
		Server->Log("Error creating stdout pipe: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	int stderr_pipe[2];
	if(clopipe(stderr_pipe) == -1)
	{
		Server->Log("Error creating stderr pipe: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

#if defined(HAVE_SPAWN_H)
	posix_spawn_file_actions_t fa;
	if(posix_spawn_file_actions_init(&fa)!=0)
	{
		Server->Log("Error posix_spawn_file_actions_init: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	if(posix_spawn_file_actions_adddup2(&fa, stdout_pipe[1], STDOUT_FILENO)!=0)
	{
		Server->Log("Error posix_spawn_file_actions_adddup2(1): " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	if(posix_spawn_file_actions_adddup2(&fa, stderr_pipe[1], STDERR_FILENO)!=0)
	{
		Server->Log("Error posix_spawn_file_actions_adddup2(2): " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	const char* argv[] = {"sh", "-c", &pCmd[0], NULL};
	const char* envp[] = {NULL};
	if(posix_spawn(&child_pid, "/bin/sh", &fa, NULL, const_cast<char**>(argv), const_cast<char**>(envp))!=0)
	{
		Server->Log("Error executing command: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	close(stdout_pipe[1]);
	close(stderr_pipe[1]);

	hStdout = stdout_pipe[0];
	hStderr = stderr_pipe[0];

	init();
#else
	child_pid = fork();

	if(child_pid==-1)
	{
		Server->Log("Error forking to execute command: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}
	else if(child_pid==0)
	{
		while ((dup2(stdout_pipe[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
		while ((dup2(stderr_pipe[1], STDERR_FILENO) == -1) && (errno == EINTR)) {}

		close(stdout_pipe[0]);
		close(stdout_pipe[1]);
		close(stderr_pipe[0]);
		close(stderr_pipe[1]);

		int rc = system(pCmd.c_str());

		if(rc>127)
		{
			rc = 127;
		}

		_exit(rc);
	}
	else
	{
		close(stdout_pipe[1]);
		close(stderr_pipe[1]);

		hStdout = stdout_pipe[0];
		hStderr = stderr_pipe[0];

		init();
	}
#endif
}

PipeFile::~PipeFile()
{

}

void PipeFile::forceExitWait()
{
	if(child_pid!=-1)
	{
		kill(child_pid, SIGKILL);
		int status;
		waitpid(child_pid, &status, 0);
	}

	close(hStdout);
	close(hStderr);

	waitForExit();
}

bool PipeFile::readIntoBuffer(int hStd, char* buf, size_t buf_avail, size_t& read_bytes)
{
	ssize_t rc = read(hStd, buf, buf_avail);

	if(rc==0 && errno==EINTR)
	{
		return readIntoBuffer(hStd, buf, buf_avail, read_bytes);
	}
	else if(rc<=0)
	{
		return false;
	}
	else
	{
		read_bytes = static_cast<size_t>(rc);
		return true;
	}
}

bool PipeFile::readStdoutIntoBuffer(char* buf, size_t buf_avail, size_t& read_bytes)
{
	return readIntoBuffer(hStdout, buf, buf_avail, read_bytes);
}

bool PipeFile::readStderrIntoBuffer(char* buf, size_t buf_avail, size_t& read_bytes)
{
	return readIntoBuffer(hStderr, buf, buf_avail, read_bytes);
}

bool PipeFile::getExitCode(int& exit_code)
{
	int status;
	int rc = waitpid(child_pid, &status, WNOHANG);

	if(rc==-1)
	{
		Server->Log("Error while waiting for exit code: " + convert(errno), LL_ERROR);
		return false;
	}
	else if(rc==0)
	{
		Server->Log("Process is still active", LL_ERROR);
		return false;
	}
	else
	{
		child_pid=-1;

		if(WIFEXITED(status))
		{
			exit_code = WEXITSTATUS(status);
			return true;
		}
		else if(WIFSIGNALED(status))
		{
			Server->Log("Script was terminated by signal " + convert(WTERMSIG(status)), LL_ERROR);
			return false;
		}
		else if(WCOREDUMP(status))
		{
			Server->Log("Script crashed", LL_ERROR);
			return false;
		}
		else if(WIFSTOPPED(status))
		{
			Server->Log("Script was stopped by signal " + convert(WSTOPSIG(status)), LL_ERROR);
			return false;
		}
		else
		{
			Server->Log("Unknown process status change", LL_ERROR);
			return false;
		}
	}
}
<commit_msg>Fix build<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2015 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include "PipeFile.h"
#include "../stringtools.h"
#include "../Interface/Server.h"
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdlib.h>
#include "../config.h"
#if defined(HAVE_SPAWN_H)
#include <spawn.h>
#endif
#include <sys/stat.h>
#include <fcntl.h>

#if defined(O_CLOEXEC) && !defined(__APPLE__) && !defined(__FreeBSD__)
#define clopipe(x) pipe2(x, O_CLOEXEC)
#else
int clopipe(int* x)
{
        int rc = pipe(x);
        if(rc!=0) return rc;
        fcntl(x[0], F_SETFD, FD_CLOEXEC);
        fcntl(x[1], F_SETFD, FD_CLOEXEC);
        return rc;
}
#endif

PipeFile::PipeFile(const std::string& pCmd)
	: PipeFileBase(pCmd),
		hStderr(0),
		hStdout(0)
{
	int stdout_pipe[2];

	if(clopipe(stdout_pipe) == -1)
	{
		Server->Log("Error creating stdout pipe: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	int stderr_pipe[2];
	if(clopipe(stderr_pipe) == -1)
	{
		Server->Log("Error creating stderr pipe: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

#if defined(HAVE_SPAWN_H)
	posix_spawn_file_actions_t fa;
	if(posix_spawn_file_actions_init(&fa)!=0)
	{
		Server->Log("Error posix_spawn_file_actions_init: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	if(posix_spawn_file_actions_adddup2(&fa, stdout_pipe[1], STDOUT_FILENO)!=0)
	{
		Server->Log("Error posix_spawn_file_actions_adddup2(1): " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	if(posix_spawn_file_actions_adddup2(&fa, stderr_pipe[1], STDERR_FILENO)!=0)
	{
		Server->Log("Error posix_spawn_file_actions_adddup2(2): " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	const char* argv[] = {"sh", "-c", &pCmd[0], NULL};
	const char* envp[] = {NULL};
	if(posix_spawn(&child_pid, "/bin/sh", &fa, NULL, const_cast<char**>(argv), const_cast<char**>(envp))!=0)
	{
		Server->Log("Error executing command: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}

	close(stdout_pipe[1]);
	close(stderr_pipe[1]);

	hStdout = stdout_pipe[0];
	hStderr = stderr_pipe[0];

	init();
#else
	child_pid = fork();

	if(child_pid==-1)
	{
		Server->Log("Error forking to execute command: " + convert(errno), LL_ERROR);
		has_error=true;
		return;
	}
	else if(child_pid==0)
	{
		while ((dup2(stdout_pipe[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
		while ((dup2(stderr_pipe[1], STDERR_FILENO) == -1) && (errno == EINTR)) {}

		close(stdout_pipe[0]);
		close(stdout_pipe[1]);
		close(stderr_pipe[0]);
		close(stderr_pipe[1]);

		int rc = system(pCmd.c_str());

		if(rc>127)
		{
			rc = 127;
		}

		_exit(rc);
	}
	else
	{
		close(stdout_pipe[1]);
		close(stderr_pipe[1]);

		hStdout = stdout_pipe[0];
		hStderr = stderr_pipe[0];

		init();
	}
#endif
}

PipeFile::~PipeFile()
{

}

void PipeFile::forceExitWait()
{
	if(child_pid!=-1)
	{
		kill(child_pid, SIGKILL);
		int status;
		waitpid(child_pid, &status, 0);
	}

	close(hStdout);
	close(hStderr);

	waitForExit();
}

bool PipeFile::readIntoBuffer(int hStd, char* buf, size_t buf_avail, size_t& read_bytes)
{
	ssize_t rc = read(hStd, buf, buf_avail);

	if(rc==0 && errno==EINTR)
	{
		return readIntoBuffer(hStd, buf, buf_avail, read_bytes);
	}
	else if(rc<=0)
	{
		return false;
	}
	else
	{
		read_bytes = static_cast<size_t>(rc);
		return true;
	}
}

bool PipeFile::readStdoutIntoBuffer(char* buf, size_t buf_avail, size_t& read_bytes)
{
	return readIntoBuffer(hStdout, buf, buf_avail, read_bytes);
}

void PipeFile::finishStdout()
{
}

bool PipeFile::readStderrIntoBuffer(char* buf, size_t buf_avail, size_t& read_bytes)
{
	return readIntoBuffer(hStderr, buf, buf_avail, read_bytes);
}

bool PipeFile::getExitCode(int& exit_code)
{
	int status;
	int rc = waitpid(child_pid, &status, WNOHANG);

	if(rc==-1)
	{
		Server->Log("Error while waiting for exit code: " + convert(errno), LL_ERROR);
		return false;
	}
	else if(rc==0)
	{
		Server->Log("Process is still active", LL_ERROR);
		return false;
	}
	else
	{
		child_pid=-1;

		if(WIFEXITED(status))
		{
			exit_code = WEXITSTATUS(status);
			return true;
		}
		else if(WIFSIGNALED(status))
		{
			Server->Log("Script was terminated by signal " + convert(WTERMSIG(status)), LL_ERROR);
			return false;
		}
		else if(WCOREDUMP(status))
		{
			Server->Log("Script crashed", LL_ERROR);
			return false;
		}
		else if(WIFSTOPPED(status))
		{
			Server->Log("Script was stopped by signal " + convert(WSTOPSIG(status)), LL_ERROR);
			return false;
		}
		else
		{
			Server->Log("Unknown process status change", LL_ERROR);
			return false;
		}
	}
}
<|endoftext|>


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

#ifndef PDFEXPORT_HXX
#define PDFEXPORT_HXX

#include "pdffilter.hxx"
#include <tools/multisel.hxx>
#include <vcl/pdfwriter.hxx>
#include <vcl/pdfextoutdevdata.hxx>
#ifndef _COM_SUN_STAR_VIEW_XRENDERABLE_HPP_
#include <com/sun/star/view/XRenderable.hpp>
#endif

class SvEmbeddedObject;
class GDIMetaFile;
class VirtualDevice;
class PolyPolygon;
class Gradient;
class BitmapEx;
class Point;
class Size;

namespace vcl { class PDFWriter; }

// -------------
// - PDFExport -
// -------------

class PDFExport
{
private:

    Reference< XComponent > mxSrcDoc;
    Reference< lang::XMultiServiceFactory > mxMSF;
    Reference< task::XStatusIndicator > mxStatusIndicator;

    sal_Bool                mbUseTaggedPDF;
    sal_Int32               mnPDFTypeSelection;
    sal_Bool                mbExportNotes;
    sal_Bool                mbExportNotesPages;
    sal_Bool                mbEmbedStandardFonts;
    sal_Bool                mbUseTransitionEffects;
    sal_Bool                mbExportBookmarks;
    sal_Int32               mnOpenBookmarkLevels;

    sal_Bool                mbUseLosslessCompression;
    sal_Bool                mbReduceImageResolution;
    sal_Bool                mbSkipEmptyPages;
    sal_Bool                mbAddStream;
    sal_Int32               mnMaxImageResolution;
    sal_Int32               mnQuality;
    sal_Int32               mnFormsFormat;
    sal_Bool                mbExportFormFields;
    sal_Int32               mnProgressValue;

    sal_Bool                mbWatermark;
    uno::Any                maWatermark;

//these variable are here only to have a location in filter/pdf to set the default
//to be used by the macro (when the FilterData are set by the macro itself)
    sal_Bool                mbHideViewerToolbar;
    sal_Bool                mbHideViewerMenubar;
    sal_Bool                mbHideViewerWindowControls;
    sal_Bool                mbFitWindow;
    sal_Bool                mbCenterWindow;
    sal_Bool                mbOpenInFullScreenMode;
    sal_Bool                mbDisplayPDFDocumentTitle;
    sal_Int32               mnPDFDocumentMode;
    sal_Int32               mnPDFDocumentAction;
    sal_Int32               mnZoom;
    sal_Int32               mnInitialPage;
    sal_Int32               mnPDFPageLayout;
    sal_Bool                mbFirstPageLeft;

    sal_Bool                mbEncrypt;
    rtl::OUString           msOpenPassword;
    sal_Bool                mbRestrictPermissions;
    rtl::OUString           msPermissionPassword;
    sal_Int32               mnPrintAllowed;
    sal_Int32               mnChangesAllowed;
    sal_Bool                mbCanCopyOrExtract;
    sal_Bool                mbCanExtractForAccessibility;

    SvtGraphicFill          maCacheFill;
    sal_Int32               mnCachePatternId;

//--->i56629
    sal_Bool                mbExportRelativeFsysLinks;
    sal_Int32               mnDefaultLinkAction;
    sal_Bool                mbConvertOOoTargetToPDFTarget;
    sal_Bool                mbExportBmkToDest;
//<---
    sal_Bool                ImplExportPage( ::vcl::PDFWriter& rWriter, ::vcl::PDFExtOutDevData& rPDFExtOutDevData,
                                                const GDIMetaFile& rMtf );
    sal_Bool                ImplWriteActions( ::vcl::PDFWriter& rWriter, ::vcl::PDFExtOutDevData* pPDFExtOutDevData,
                                                const GDIMetaFile& rMtf, VirtualDevice& rDummyVDev );
    void                    ImplWriteGradient( ::vcl::PDFWriter& rWriter, const PolyPolygon& rPolyPoly,
                                                const Gradient& rGradient, VirtualDevice& rDummyVDev );
    void                    ImplWriteBitmapEx( ::vcl::PDFWriter& rWriter, VirtualDevice& rDummyVDev,
                                                const Point& rPoint, const Size& rSize, const BitmapEx& rBitmap );

    void                    ImplWriteWatermark( ::vcl::PDFWriter& rWriter, const Size& rPageSize );
public:

                            PDFExport( const Reference< XComponent >& rxSrcDoc, Reference< task::XStatusIndicator >& xStatusIndicator, const Reference< lang::XMultiServiceFactory >& xFact );
                            ~PDFExport();

    sal_Bool                ExportSelection( vcl::PDFWriter& rPDFWriter, Reference< com::sun::star::view::XRenderable >& rRenderable, Any& rSelection,
                                MultiSelection aMultiSelection, Sequence< PropertyValue >& rRenderOptions, sal_Int32 nPageCount );

    sal_Bool                Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData );
};

#endif
<commit_msg>INTEGRATION: CWS aquavcl05_DEV300 (1.12.54); FILE MERGED 2008/02/19 10:59:58 pl 1.12.54.1: #i85195# report potential problems during PDF export<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: pdfexport.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: kz $ $Date: 2008-03-05 17:16:59 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef PDFEXPORT_HXX
#define PDFEXPORT_HXX

#include "pdffilter.hxx"
#include <tools/multisel.hxx>
#include <vcl/pdfwriter.hxx>
#include <vcl/pdfextoutdevdata.hxx>
#ifndef _COM_SUN_STAR_VIEW_XRENDERABLE_HPP_
#include <com/sun/star/view/XRenderable.hpp>
#endif

class SvEmbeddedObject;
class GDIMetaFile;
class VirtualDevice;
class PolyPolygon;
class Gradient;
class BitmapEx;
class Point;
class Size;

namespace vcl { class PDFWriter; }

// -------------
// - PDFExport -
// -------------

class PDFExport
{
private:

    Reference< XComponent > mxSrcDoc;
    Reference< lang::XMultiServiceFactory > mxMSF;
    Reference< task::XStatusIndicator > mxStatusIndicator;

    sal_Bool                mbUseTaggedPDF;
    sal_Int32               mnPDFTypeSelection;
    sal_Bool                mbExportNotes;
    sal_Bool                mbExportNotesPages;
    sal_Bool                mbEmbedStandardFonts;
    sal_Bool                mbUseTransitionEffects;
    sal_Bool                mbExportBookmarks;
    sal_Int32               mnOpenBookmarkLevels;

    sal_Bool                mbUseLosslessCompression;
    sal_Bool                mbReduceImageResolution;
    sal_Bool                mbSkipEmptyPages;
    sal_Bool                mbAddStream;
    sal_Int32               mnMaxImageResolution;
    sal_Int32               mnQuality;
    sal_Int32               mnFormsFormat;
    sal_Bool                mbExportFormFields;
    sal_Int32               mnProgressValue;

    sal_Bool                mbWatermark;
    uno::Any                maWatermark;

//these variable are here only to have a location in filter/pdf to set the default
//to be used by the macro (when the FilterData are set by the macro itself)
    sal_Bool                mbHideViewerToolbar;
    sal_Bool                mbHideViewerMenubar;
    sal_Bool                mbHideViewerWindowControls;
    sal_Bool                mbFitWindow;
    sal_Bool                mbCenterWindow;
    sal_Bool                mbOpenInFullScreenMode;
    sal_Bool                mbDisplayPDFDocumentTitle;
    sal_Int32               mnPDFDocumentMode;
    sal_Int32               mnPDFDocumentAction;
    sal_Int32               mnZoom;
    sal_Int32               mnInitialPage;
    sal_Int32               mnPDFPageLayout;
    sal_Bool                mbFirstPageLeft;

    sal_Bool                mbEncrypt;
    rtl::OUString           msOpenPassword;
    sal_Bool                mbRestrictPermissions;
    rtl::OUString           msPermissionPassword;
    sal_Int32               mnPrintAllowed;
    sal_Int32               mnChangesAllowed;
    sal_Bool                mbCanCopyOrExtract;
    sal_Bool                mbCanExtractForAccessibility;

    SvtGraphicFill          maCacheFill;
    sal_Int32               mnCachePatternId;

//--->i56629
    sal_Bool                mbExportRelativeFsysLinks;
    sal_Int32               mnDefaultLinkAction;
    sal_Bool                mbConvertOOoTargetToPDFTarget;
    sal_Bool                mbExportBmkToDest;
//<---
    sal_Bool                ImplExportPage( ::vcl::PDFWriter& rWriter, ::vcl::PDFExtOutDevData& rPDFExtOutDevData,
                                                const GDIMetaFile& rMtf );
    sal_Bool                ImplWriteActions( ::vcl::PDFWriter& rWriter, ::vcl::PDFExtOutDevData* pPDFExtOutDevData,
                                                const GDIMetaFile& rMtf, VirtualDevice& rDummyVDev );
    void                    ImplWriteGradient( ::vcl::PDFWriter& rWriter, const PolyPolygon& rPolyPoly,
                                                const Gradient& rGradient, VirtualDevice& rDummyVDev );
    void                    ImplWriteBitmapEx( ::vcl::PDFWriter& rWriter, VirtualDevice& rDummyVDev,
                                                const Point& rPoint, const Size& rSize, const BitmapEx& rBitmap );

    void                    ImplWriteWatermark( ::vcl::PDFWriter& rWriter, const Size& rPageSize );
public:

                            PDFExport( const Reference< XComponent >& rxSrcDoc, Reference< task::XStatusIndicator >& xStatusIndicator, const Reference< lang::XMultiServiceFactory >& xFact );
                            ~PDFExport();

    sal_Bool                ExportSelection( vcl::PDFWriter& rPDFWriter, Reference< com::sun::star::view::XRenderable >& rRenderable, Any& rSelection,
                                MultiSelection aMultiSelection, Sequence< PropertyValue >& rRenderOptions, sal_Int32 nPageCount );

    sal_Bool                Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData );

    void                    showErrors( const std::set<vcl::PDFWriter::ErrorCode>& );
};

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013  Pascal Giorgi
 *
 * Written by Pascal Giorgi <pascal.giorgi@lirmm.fr>
 *
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 */

#include "linbox/linbox-config.h"

#include "linbox/algorithms/polynomial-matrix/polynomial-fft-transform.h"
#include "linbox/randiter/random-fftprime.h"
#include "linbox/ring/modular.h"

#include <functional>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using namespace LinBox;

/* For pretty printing type */
template<typename T> const char *TypeName();
template<template <typename S> typename T> const char *TypeName();

#define REGISTER_TYPE_NAME(type) \
	template<> const char *TypeName<type>(){return #type;}

REGISTER_TYPE_NAME(double);
REGISTER_TYPE_NAME(uint16_t);
REGISTER_TYPE_NAME(uint32_t);
REGISTER_TYPE_NAME(uint64_t);
REGISTER_TYPE_NAME(uint128_t);
REGISTER_TYPE_NAME(NoSimd);
REGISTER_TYPE_NAME(Simd128);
REGISTER_TYPE_NAME(Simd256);

/******************************************************************************/
template<typename Field>
struct Checker {
	typedef typename Field::Element Elt;
	typedef AlignedAllocator<Elt, Alignment::DEFAULT> _Alignement;
	typedef typename std::vector<Elt, _Alignement> EltVector;

	const Field& _F;
	size_t _k;
	size_t _n;
	FFT_transform<Field> _fft;

	/* ctor */
	Checker (const Field& F, size_t k) : _F(F), _k(k), _n(1<<k), _fft(F,k) {
	}

	/* compute r = P evaluated at x using Horner method */
	void horner_eval (Elt& r, EltVector& P, Elt& x) {
		_F.assign (r, _F.zero);
		for (auto ptr = P.rbegin(); ptr != P.rend(); ptr++ ) {
			_F.mulin (r, x);
			_F.addin (r, *ptr);
		}
	}

	/* return i with its first _k bits reversed */
	size_t bitreversed (size_t i) {
		size_t r = 0;
		for (size_t j = 0; j < _k; j++, i>>=1)
		{
			r <<= 1;
			r |= i & 1;
		}
		return r;
	}

	/* draw random vector and check DIF and DIT for all available SIMD implem */
	bool check (unsigned long seed) {
		EltVector in(_n), in_br(_n), out(_n), out_br(_n), v(_n);
		string s;
		bool passed = true;

		/* Generate random input */
		typename Field::RandIter Gen (_F, 0, seed+_k); /*0 has no meaning here*/
		for (auto elt = in.begin(); elt < in.end(); elt++)
			Gen.random (*elt);

		/* Compute the out vector using a naive polynomial evaluation and set
		 * the bitreversed version of in and out */
		Elt x(1);
		for (size_t i = 0; i < _n; _F.mulin (x, _fft._w), i++) {
			size_t i_br = bitreversed (i);
			in_br[i_br] = in[i];
			horner_eval (out[i], in, x);
			out_br[i_br] = out[i];
		}

		/* DIF : natural order => bitreversed order */
#define DIF_CHECK(method) do {								\
	v = in;													\
	_fft.method (v.data());									\
	for (auto& e: v) /* reduce from < 2p to < p */			\
		if (e > _F._p) e-=_F._p;							\
	bool b = equal (v.begin(), v.end(), out_br.begin());	\
	s = "     "; s.append (#method); s.append (" ");		\
	s.append (string (80-(s.size()+16), '.'));				\
	cout << s << (b ? " success" : " failure") << endl;		\
	passed &= b;											\
	} while (0)

		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative);
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative2x2);
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative3x3);
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative4x1_SSE);
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative4x2_SSE);
#ifdef __LINBOX_HAVE_AVX2_INSTRUCTIONS
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative8x1_AVX);
#endif

		/* DIT : bitreversed order => natural order */
#define DIT_CHECK(method) do {								\
	v = in_br;												\
	_fft.method (v.data());									\
	for (auto& e: v) { /* reduce from < 3p to < p */		\
		if (e > _F._p) e-=_F._p;							\
		if (e > _F._p) e-=_F._p;							\
		if (e > _F._p) e-=_F._p;							\
	}														\
	bool b = equal (v.begin(), v.end(), out.begin());		\
	s = "     "; s.append (#method); s.append (" ");		\
	s.append (string (80-(s.size()+16), '.'));				\
	cout << s << (b ? " success" : " failure") << endl;		\
	passed &= b;											\
	} while (0)

		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative);
		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative2x2);
		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative3x3);
		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative4x1_SSE);
#ifdef __LINBOX_HAVE_AVX2_INSTRUCTIONS
		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative8x1_AVX);
#endif

		return passed;
	}
};

/* Test FFT on polynomial with coefficients in Modular<T1,T2> with a random
 * prime p with the required number of bits and such that 2^k divides p-1
 */
template<typename T1, typename T2>
bool test_one_modular_implem (uint64_t bits, size_t k, unsigned long seed)
{
	typedef typename Givaro::Modular<T1, T2> ModImplem;

	RandomFFTPrime RandomGen (1<<bits, seed);
	T1 p = (T1) RandomGen.randomPrime (k);
	ModImplem GFp(p);

	cout << endl << string (80, '*') << endl;
	cout << "Test FFT with Modular<" << TypeName<T1>() << ", ";
	cout << TypeName<T2>() << ">, p=" << GFp._p << " (" << bits << " bits, 2^";
	cout << k << " divides p-1)" << endl;

	bool b = true;
	for (size_t kc = 1; kc <= k; kc++) {
		cout << "** with n=2^" << kc << endl;
		Checker<ModImplem> C(GFp, kc);
		b &= C.check (seed);
	}

	return b;
}

/******************************************************************************/
/************************************ main ************************************/
/******************************************************************************/
int main (int argc, char *argv[]) {
	bool pass = true;
	unsigned long seed = time (NULL);

	Argument args[] = {
		{ 's', "-s seed", "set the seed.", TYPE_INT, &seed },
		END_OF_ARGUMENTS
	};

	parseArguments (argc, argv, args);

	cout << "# To rerun this test: test-fft-new -s " << seed << endl;
	cout << "# seed = " << seed << endl;

	/* Test with Modular<uint32_t, uint64_t>, and 27-bit prime and k=10 */
	pass &= test_one_modular_implem<uint32_t, uint64_t> (27, 10, seed);

	cout << endl << "Test " << (pass ? "passed" : "failed") << endl;
	return pass ? 0 : 1;
}

// Local Variables:
// mode: C++
// tab-width: 4
// indent-tabs-mode: nil
// c-basic-offset: 4
// End:
// vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
<commit_msg>typo in test-fft-old.C<commit_after>/*
 * Copyright (C) 2013  Pascal Giorgi
 *
 * Written by Pascal Giorgi <pascal.giorgi@lirmm.fr>
 *
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 */

#include "linbox/linbox-config.h"

#include "linbox/algorithms/polynomial-matrix/polynomial-fft-transform.h"
#include "linbox/randiter/random-fftprime.h"
#include "linbox/ring/modular.h"

#include <functional>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using namespace LinBox;

/* For pretty printing type */
template<typename T> const char *TypeName();
template<template <typename S> typename T> const char *TypeName();

#define REGISTER_TYPE_NAME(type) \
	template<> const char *TypeName<type>(){return #type;}

REGISTER_TYPE_NAME(double);
REGISTER_TYPE_NAME(uint16_t);
REGISTER_TYPE_NAME(uint32_t);
REGISTER_TYPE_NAME(uint64_t);
REGISTER_TYPE_NAME(uint128_t);
REGISTER_TYPE_NAME(NoSimd);
REGISTER_TYPE_NAME(Simd128);
REGISTER_TYPE_NAME(Simd256);

/******************************************************************************/
template<typename Field>
struct Checker {
	typedef typename Field::Element Elt;
	typedef AlignedAllocator<Elt, Alignment::DEFAULT> _Alignement;
	typedef typename std::vector<Elt, _Alignement> EltVector;

	const Field& _F;
	size_t _k;
	size_t _n;
	FFT_transform<Field> _fft;

	/* ctor */
	Checker (const Field& F, size_t k) : _F(F), _k(k), _n(1<<k), _fft(F,k) {
	}

	/* compute r = P evaluated at x using Horner method */
	void horner_eval (Elt& r, EltVector& P, Elt& x) {
		_F.assign (r, _F.zero);
		for (auto ptr = P.rbegin(); ptr != P.rend(); ptr++ ) {
			_F.mulin (r, x);
			_F.addin (r, *ptr);
		}
	}

	/* return i with its first _k bits reversed */
	size_t bitreversed (size_t i) {
		size_t r = 0;
		for (size_t j = 0; j < _k; j++, i>>=1)
		{
			r <<= 1;
			r |= i & 1;
		}
		return r;
	}

	/* draw random vector and check DIF and DIT for all available SIMD implem */
	bool check (unsigned long seed) {
		EltVector in(_n), in_br(_n), out(_n), out_br(_n), v(_n);
		string s;
		bool passed = true;

		/* Generate random input */
		typename Field::RandIter Gen (_F, 0, seed+_k); /*0 has no meaning here*/
		for (auto elt = in.begin(); elt < in.end(); elt++)
			Gen.random (*elt);

		/* Compute the out vector using a naive polynomial evaluation and set
		 * the bitreversed version of in and out */
		Elt x(1);
		for (size_t i = 0; i < _n; _F.mulin (x, _fft._w), i++) {
			size_t i_br = bitreversed (i);
			in_br[i_br] = in[i];
			horner_eval (out[i], in, x);
			out_br[i_br] = out[i];
		}

		/* DIF : natural order => bitreversed order */
#define DIF_CHECK(method) do {								\
	v = in;													\
	_fft.method (v.data());									\
	for (auto& e: v) /* reduce from < 2p to < p */			\
		if (e > _F._p) e-=_F._p;							\
	bool b = equal (v.begin(), v.end(), out_br.begin());	\
	s = "     "; s.append (#method); s.append (" ");		\
	s.append (string (80-(s.size()+16), '.'));				\
	cout << s << (b ? " success" : " failure") << endl;		\
	passed &= b;											\
	} while (0)

		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative);
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative2x2);
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative3x3);
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative4x1_SSE);
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative4x2_SSE);
#ifdef __LINBOX_HAVE_AVX2_INSTRUCTIONS
		DIF_CHECK(FFT_DIF_Harvey_mod2p_iterative8x1_AVX);
#endif

		/* DIT : bitreversed order => natural order */
#define DIT_CHECK(method) do {								\
	v = in_br;												\
	_fft.method (v.data());									\
	for (auto& e: v) { /* reduce from < 3p to < p */		\
		if (e > _F._p) e-=_F._p;							\
		if (e > _F._p) e-=_F._p;							\
		if (e > _F._p) e-=_F._p;							\
	}														\
	bool b = equal (v.begin(), v.end(), out.begin());		\
	s = "     "; s.append (#method); s.append (" ");		\
	s.append (string (80-(s.size()+16), '.'));				\
	cout << s << (b ? " success" : " failure") << endl;		\
	passed &= b;											\
	} while (0)

		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative);
		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative2x2);
		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative3x3);
		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative4x1_SSE);
#ifdef __LINBOX_HAVE_AVX2_INSTRUCTIONS
		DIT_CHECK(FFT_DIT_Harvey_mod4p_iterative8x1_AVX);
#endif

		return passed;
	}
};

/* Test FFT on polynomial with coefficients in Modular<T1,T2> with a random
 * prime p with the required number of bits and such that 2^k divides p-1
 */
template<typename T1, typename T2>
bool test_one_modular_implem (uint64_t bits, size_t k, unsigned long seed)
{
	typedef typename Givaro::Modular<T1, T2> ModImplem;

	RandomFFTPrime RandomGen (1<<bits, seed);
	T1 p = (T1) RandomGen.randomPrime (k);
	ModImplem GFp(p);

	cout << endl << string (80, '*') << endl;
	cout << "Test FFT with Modular<" << TypeName<T1>() << ", ";
	cout << TypeName<T2>() << ">, p=" << GFp._p << " (" << bits << " bits, 2^";
	cout << k << " divides p-1)" << endl;

	bool b = true;
	for (size_t kc = 1; kc <= k; kc++) {
		cout << "** with n=2^" << kc << endl;
		Checker<ModImplem> C(GFp, kc);
		b &= C.check (seed);
	}

	return b;
}

/******************************************************************************/
/************************************ main ************************************/
/******************************************************************************/
int main (int argc, char *argv[]) {
	bool pass = true;
	unsigned long seed = time (NULL);

	Argument args[] = {
		{ 's', "-s seed", "set the seed.", TYPE_INT, &seed },
		END_OF_ARGUMENTS
	};

	parseArguments (argc, argv, args);

	cout << "# To rerun this test: test-fft-old -s " << seed << endl;
	cout << "# seed = " << seed << endl;

	/* Test with Modular<uint32_t, uint64_t>, and 27-bit prime and k=10 */
	pass &= test_one_modular_implem<uint32_t, uint64_t> (27, 10, seed);

	cout << endl << "Test " << (pass ? "passed" : "failed") << endl;
	return pass ? 0 : 1;
}

// Local Variables:
// mode: C++
// tab-width: 4
// indent-tabs-mode: nil
// c-basic-offset: 4
// End:
// vim:sts=4:sw=4:ts=4:et:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2017, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifdef GRPC_UV

#include "server.h"

#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/support/time.h"

#include "call.h"
#include "completion_queue.h"

namespace grpc {
namespace node {

using Nan::Callback;
using Nan::MaybeLocal;

using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Local;
using v8::Object;
using v8::Value;

static Callback *shutdown_callback = NULL;

class ServerShutdownOp : public Op {
 public:
  ServerShutdownOp(grpc_server *server): server(server) {
  }

  ~ServerShutdownOp() {
  }

  Local<Value> GetNodeValue() const {
    return Nan::New<External>(reinterpret_cast<void *>(server));
  }

  bool ParseOp(Local<Value> value, grpc_op *out) {
    return true;
  }
  bool IsFinalOp() {
    return false;
  }
  void OnComplete() {
  }

  grpc_server *server;

 protected:
  std::string GetTypeString() const { return "shutdown"; }
};

Server::Server(grpc_server *server) : wrapped_server(server) {
}

Server::~Server() {
  this->ShutdownServer();
}

NAN_METHOD(ServerShutdownCallback) {
  if (!info[0]->IsNull()) {
    return Nan::ThrowError("forceShutdown failed somehow");
  }
  MaybeLocal<Object> maybe_result = Nan::To<Object>(info[1]);
  Local<Object> result = maybe_result.ToLocalChecked();
  Local<Value> server_val = Nan::Get(
      result, Nan::New("shutdown").ToLocalChecked()).ToLocalChecked();
  Local<External> server_extern = server_val.As<External>();
  grpc_server *server = reinterpret_cast<grpc_server *>(server_extern->Value());
  grpc_server_destroy(server);
}

void Server::ShutdownServer() {
  Nan::HandleScope scope;
  if (this->wrapped_server != NULL) {
    if (shutdown_callback == NULL) {
      Local<FunctionTemplate>callback_tpl =
          Nan::New<FunctionTemplate>(ServerShutdownCallback);
      shutdown_callback = new Callback(
          Nan::GetFunction(callback_tpl).ToLocalChecked());
    }

    ServerShutdownOp *op = new ServerShutdownOp(this->wrapped_server);
    unique_ptr<OpVec> ops(new OpVec());
    ops->push_back(unique_ptr<Op>(op));

    grpc_server_shutdown_and_notify(
        this->wrapped_server, GetCompletionQueue(),
        new struct tag(new Callback(**shutdown_callback), ops.release(), NULL,
                       Nan::Null()));
    grpc_server_cancel_all_calls(this->wrapped_server);
    CompletionQueueNext();
    this->wrapped_server = NULL;
  }
}

}  // namespace grpc
}  // namespace node

#endif /* GRPC_UV */
<commit_msg>Move ForceShutdown completion handling to new OnComplete method<commit_after>/*
 *
 * Copyright 2017, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifdef GRPC_UV

#include "server.h"

#include <node.h>
#include <nan.h>
#include "grpc/grpc.h"
#include "grpc/support/time.h"

#include "call.h"
#include "completion_queue.h"

namespace grpc {
namespace node {

using Nan::Callback;
using Nan::MaybeLocal;

using v8::External;
using v8::Function;
using v8::FunctionTemplate;
using v8::Local;
using v8::Object;
using v8::Value;

static Callback *shutdown_callback = NULL;

class ServerShutdownOp : public Op {
 public:
  ServerShutdownOp(grpc_server *server): server(server) {
  }

  ~ServerShutdownOp() {
  }

  Local<Value> GetNodeValue() const {
    return Nan::Null();
  }

  bool ParseOp(Local<Value> value, grpc_op *out) {
    return true;
  }
  bool IsFinalOp() {
    return false;
  }
  void OnComplete() {
    grpc_server_destroy(server);
  }

  grpc_server *server;

 protected:
  std::string GetTypeString() const { return "shutdown"; }
};

Server::Server(grpc_server *server) : wrapped_server(server) {
}

Server::~Server() {
  this->ShutdownServer();
}

NAN_METHOD(ServerShutdownCallback) {
  if (!info[0]->IsNull()) {
    return Nan::ThrowError("forceShutdown failed somehow");
  }
}

void Server::ShutdownServer() {
  Nan::HandleScope scope;
  if (this->wrapped_server != NULL) {
    if (shutdown_callback == NULL) {
      Local<FunctionTemplate>callback_tpl =
          Nan::New<FunctionTemplate>(ServerShutdownCallback);
      shutdown_callback = new Callback(
          Nan::GetFunction(callback_tpl).ToLocalChecked());
    }

    ServerShutdownOp *op = new ServerShutdownOp(this->wrapped_server);
    unique_ptr<OpVec> ops(new OpVec());
    ops->push_back(unique_ptr<Op>(op));

    grpc_server_shutdown_and_notify(
        this->wrapped_server, GetCompletionQueue(),
        new struct tag(new Callback(**shutdown_callback), ops.release(), NULL,
                       Nan::Null()));
    grpc_server_cancel_all_calls(this->wrapped_server);
    CompletionQueueNext();
    this->wrapped_server = NULL;
  }
}

}  // namespace grpc
}  // namespace node

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


<commit_before>#include <ruby.h>
#include <set>
#include <algorithm>

#include <boost/tuple/tuple.hpp>

using namespace boost;
using namespace std;

static VALUE cValueSet;
static ID id_new;

typedef std::set<VALUE> ValueSet;
static ValueSet& get_wrapped_set(VALUE self)
{
    ValueSet* object = 0;
    Data_Get_Struct(self, ValueSet, object);
    return *object;
}

static void value_set_mark(ValueSet const* set) { std::for_each(set->begin(), set->end(), rb_gc_mark); }
static void value_set_free(ValueSet const* set) { delete set; }
static VALUE value_set_alloc(VALUE klass)
{
    ValueSet* cxx_set = new ValueSet;
    return Data_Wrap_Struct(klass, value_set_mark, value_set_free, cxx_set);
}
/* call-seq:
 *  set.empty?			    => true or false
 *
 * Checks if this set is empty
 */
static VALUE value_set_empty_p(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    return set.empty() ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.size			    => size
 *
 * Returns this set size
 */
static VALUE value_set_size(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    return INT2NUM(set.size());
}

/* call-seq:
 *  set.each { |obj| ... }	    => set
 *
 */
static VALUE value_set_each(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    for (ValueSet::iterator it = set.begin(); it != set.end();)
    {
	// Increment before calling yield() so that
	// the current element can be deleted safely
	ValueSet::iterator this_it = it++;
	rb_yield(*this_it);
    }
    return self;
}

/* call-seq:
 *  set.delete_if { |obj| ... }		=> set
 *
 * Deletes all objects for which the block returns true
 */
static VALUE value_set_delete_if(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    for (ValueSet::iterator it = set.begin(); it != set.end();)
    {
	// Increment before calling yield() so that
	// the current element can be deleted safely
	ValueSet::iterator this_it = it++;
	bool do_delete = RTEST(rb_yield(*this_it));
	if (do_delete)
	    set.erase(this_it);
    }
    return self;
}

/* call-seq:
 *  set.include?(value)	    => true or false
 *
 * Checks if +value+ is in +set+
 */
static VALUE value_set_include_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    return self.find(vother) == self.end() ? Qfalse : Qtrue;
}

/* call-seq:
 *  set.to_value_set		    => set
 */
static VALUE value_set_to_value_set(VALUE self) { return self; }

/* call-seq:
 *  set.include_all?(other)		=> true or false
 *
 * Checks if all elements of +other+ are in +set+
 */
static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);
    return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.union(other)		=> union_set
 *  set | other			=> union_set
 *
 * Computes the union of +set+ and +other+. This operation is O(N + M)
 * is +other+ is a ValueSet
 */
static VALUE value_set_union(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_union(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.merge(other)		=> set
 *
 * Merges the elements of +other+ into +self+. If +other+ is a ValueSet, the operation is O(N + M)
 */
static VALUE value_set_merge(VALUE vself, VALUE vother)
{
    ValueSet& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    self.insert(other.begin(), other.end());
    return vself;
}

/* call-seq:
 *   set.intersection(other)	=> intersection_set
 *   set & other		=> intersection_set
 *
 * Computes the intersection of +set+ and +other+. This operation
 * is O(N + M) if +other+ is a ValueSet
 */
static VALUE value_set_intersection(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.intersects?(other)	=> true or false
 *
 * Returns true if there is elements in +set+ that are also in +other
 */
static VALUE value_set_intersects(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    ValueSet::const_iterator
	self_it   = self.begin(),
	self_end  = self.end(),
	other_it  = other.begin(),
	other_end = other.end();

    while(self_it != self_end && other_it != other_end)
    {
	if (*self_it < *other_it)
	    ++self_it;
	else if (*other_it < *self_it)
	    ++other_it;
	else
	    return Qtrue;
    }
    return Qfalse;
}

/* call-seq:
 *   set.difference(other)	=> difference_set
 *   set - other		=> difference_set
 *
 * Computes the set of all elements of +set+ not in +other+. This operation
 * is O(N + M) if +other+ is a ValueSet
 */
static VALUE value_set_difference(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.insert(value)		=> true or false
 *
 * Inserts +value+ into +set+. Returns true if the value did not exist
 * in the set yet (it has actually been inserted), and false otherwise.
 * This operation is O(log N)
 */
static VALUE value_set_insert(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    bool exists;
    tie(tuples::ignore, exists) = self.insert(v);
    return exists ? Qtrue : Qfalse;
}
/* call-seq:
 *  set.delete(value)		=> true or false
 *
 * Removes +value+ from +set+. Returns true if the value did exist
 * in the set yet (it has actually been removed), and false otherwise.
 */
static VALUE value_set_delete(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    size_t count = self.erase(v);
    return count > 0 ? Qtrue : Qfalse;
}

/* call-seq:
 *  set == other		=> true or false
 *
 * Equality
 */
static VALUE value_set_equal(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	return Qfalse;
    ValueSet const& other = get_wrapped_set(vother);
    return (self == other) ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.clear			=> set
 *
 * Remove all elements of this set
 */
static VALUE value_set_clear(VALUE self)
{
    get_wrapped_set(self).clear();
    return self;
}

/* call-seq:
 *  set.initialize_copy(other)  => set
 *
 * Initializes +set+ with the values in +other+. Needed by #dup
 */
static VALUE value_set_initialize_copy(VALUE vself, VALUE vother)
{
    ValueSet const& other = get_wrapped_set(vother);
    set<VALUE> new_set(other.begin(), other.end());
    get_wrapped_set(vself).swap(new_set);
    return vself;
}

static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
{
    ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
    result.insert(i);
    return Qnil;
}

/* call-seq:
 *  enum.to_value_set		=> value_set
 *
 * Builds a ValueSet object from this enumerable
 */
static VALUE enumerable_to_value_set(VALUE self)
{
    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);

    rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
    return vresult;
}

/*
 * Document-class: ValueSet
 *
 * ValueSet is a wrapper around the C++ set<> template. set<> is an ordered container,
 * for which union(), intersection() and difference() is done in linear time. For performance
 * reasons, in the case of ValueSet, the values are ordered by their VALUE, which roughly is
 * their object_id.
 */

extern "C" void Init_value_set()
{
    rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);

    cValueSet = rb_define_class("ValueSet", rb_cObject);
    id_new = rb_intern("new");
    rb_define_alloc_func(cValueSet, value_set_alloc);
    rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
    rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
    rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
    rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
    rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
    rb_define_method(cValueSet, "intersects?", RUBY_METHOD_FUNC(value_set_intersects), 1);
    rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
    rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
    rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
    rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
    rb_define_method(cValueSet, "==", RUBY_METHOD_FUNC(value_set_equal), 1);
    rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
    rb_define_method(cValueSet, "empty?", RUBY_METHOD_FUNC(value_set_empty_p), 0);
    rb_define_method(cValueSet, "size", RUBY_METHOD_FUNC(value_set_size), 0);
    rb_define_method(cValueSet, "clear", RUBY_METHOD_FUNC(value_set_clear), 0);
    rb_define_method(cValueSet, "initialize_copy", RUBY_METHOD_FUNC(value_set_initialize_copy), 1);
    rb_define_method(cValueSet, "delete_if", RUBY_METHOD_FUNC(value_set_delete_if), 0);
}

<commit_msg>[value_set] define a more efficient ValueSet#dup<commit_after>#include <ruby.h>
#include <set>
#include <algorithm>

#include <boost/tuple/tuple.hpp>

using namespace boost;
using namespace std;

static VALUE cValueSet;
static ID id_new;

typedef std::set<VALUE> ValueSet;
static ValueSet& get_wrapped_set(VALUE self)
{
    ValueSet* object = 0;
    Data_Get_Struct(self, ValueSet, object);
    return *object;
}

static void value_set_mark(ValueSet const* set) { std::for_each(set->begin(), set->end(), rb_gc_mark); }
static void value_set_free(ValueSet const* set) { delete set; }
static VALUE value_set_alloc(VALUE klass)
{
    ValueSet* cxx_set = new ValueSet;
    return Data_Wrap_Struct(klass, value_set_mark, value_set_free, cxx_set);
}
/* call-seq:
 *  set.empty?			    => true or false
 *
 * Checks if this set is empty
 */
static VALUE value_set_empty_p(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    return set.empty() ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.size			    => size
 *
 * Returns this set size
 */
static VALUE value_set_size(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    return INT2NUM(set.size());
}

/* call-seq:
 *  set.each { |obj| ... }	    => set
 *
 */
static VALUE value_set_each(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    for (ValueSet::iterator it = set.begin(); it != set.end();)
    {
	// Increment before calling yield() so that
	// the current element can be deleted safely
	ValueSet::iterator this_it = it++;
	rb_yield(*this_it);
    }
    return self;
}

/* call-seq:
 *  set.delete_if { |obj| ... }		=> set
 *
 * Deletes all objects for which the block returns true
 */
static VALUE value_set_delete_if(VALUE self)
{
    ValueSet& set = get_wrapped_set(self);
    for (ValueSet::iterator it = set.begin(); it != set.end();)
    {
	// Increment before calling yield() so that
	// the current element can be deleted safely
	ValueSet::iterator this_it = it++;
	bool do_delete = RTEST(rb_yield(*this_it));
	if (do_delete)
	    set.erase(this_it);
    }
    return self;
}

/* call-seq:
 *  set.include?(value)	    => true or false
 *
 * Checks if +value+ is in +set+
 */
static VALUE value_set_include_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    return self.find(vother) == self.end() ? Qfalse : Qtrue;
}

/* call-seq:
 *  set.to_value_set		    => set
 */
static VALUE value_set_to_value_set(VALUE self) { return self; }

/* call-seq:
 *  set.dup => other_set
 *
 * Duplicates this set, without duplicating the pointed-to objects
 */
static VALUE value_set_dup(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    for (ValueSet::const_iterator it = self.begin(); it != self.end(); ++it)
	result.insert(result.end(), *it);

    return vresult;
}

/* call-seq:
 *  set.include_all?(other)		=> true or false
 *
 * Checks if all elements of +other+ are in +set+
 */
static VALUE value_set_include_all_p(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);
    return std::includes(self.begin(), self.end(), other.begin(), other.end()) ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.union(other)		=> union_set
 *  set | other			=> union_set
 *
 * Computes the union of +set+ and +other+. This operation is O(N + M)
 * is +other+ is a ValueSet
 */
static VALUE value_set_union(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_union(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.merge(other)		=> set
 *
 * Merges the elements of +other+ into +self+. If +other+ is a ValueSet, the operation is O(N + M)
 */
static VALUE value_set_merge(VALUE vself, VALUE vother)
{
    ValueSet& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    self.insert(other.begin(), other.end());
    return vself;
}

/* call-seq:
 *   set.intersection(other)	=> intersection_set
 *   set & other		=> intersection_set
 *
 * Computes the intersection of +set+ and +other+. This operation
 * is O(N + M) if +other+ is a ValueSet
 */
static VALUE value_set_intersection(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_intersection(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.intersects?(other)	=> true or false
 *
 * Returns true if there is elements in +set+ that are also in +other
 */
static VALUE value_set_intersects(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    ValueSet::const_iterator
	self_it   = self.begin(),
	self_end  = self.end(),
	other_it  = other.begin(),
	other_end = other.end();

    while(self_it != self_end && other_it != other_end)
    {
	if (*self_it < *other_it)
	    ++self_it;
	else if (*other_it < *self_it)
	    ++other_it;
	else
	    return Qtrue;
    }
    return Qfalse;
}

/* call-seq:
 *   set.difference(other)	=> difference_set
 *   set - other		=> difference_set
 *
 * Computes the set of all elements of +set+ not in +other+. This operation
 * is O(N + M) if +other+ is a ValueSet
 */
static VALUE value_set_difference(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	rb_raise(rb_eArgError, "expected a ValueSet");
    ValueSet const& other = get_wrapped_set(vother);

    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);
    std::set_difference(self.begin(), self.end(), other.begin(), other.end(),
	    std::inserter(result, result.end()));
    return vresult;
}

/* call-seq:
 *  set.insert(value)		=> true or false
 *
 * Inserts +value+ into +set+. Returns true if the value did not exist
 * in the set yet (it has actually been inserted), and false otherwise.
 * This operation is O(log N)
 */
static VALUE value_set_insert(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    bool exists;
    tie(tuples::ignore, exists) = self.insert(v);
    return exists ? Qtrue : Qfalse;
}
/* call-seq:
 *  set.delete(value)		=> true or false
 *
 * Removes +value+ from +set+. Returns true if the value did exist
 * in the set yet (it has actually been removed), and false otherwise.
 */
static VALUE value_set_delete(VALUE vself, VALUE v)
{
    ValueSet& self  = get_wrapped_set(vself);
    size_t count = self.erase(v);
    return count > 0 ? Qtrue : Qfalse;
}

/* call-seq:
 *  set == other		=> true or false
 *
 * Equality
 */
static VALUE value_set_equal(VALUE vself, VALUE vother)
{
    ValueSet const& self  = get_wrapped_set(vself);
    if (!RTEST(rb_obj_is_kind_of(vother, cValueSet)))
	return Qfalse;
    ValueSet const& other = get_wrapped_set(vother);
    return (self == other) ? Qtrue : Qfalse;
}

/* call-seq:
 *  set.clear			=> set
 *
 * Remove all elements of this set
 */
static VALUE value_set_clear(VALUE self)
{
    get_wrapped_set(self).clear();
    return self;
}

/* call-seq:
 *  set.initialize_copy(other)  => set
 *
 * Initializes +set+ with the values in +other+. Needed by #dup
 */
static VALUE value_set_initialize_copy(VALUE vself, VALUE vother)
{
    ValueSet const& other = get_wrapped_set(vother);
    set<VALUE> new_set(other.begin(), other.end());
    get_wrapped_set(vself).swap(new_set);
    return vself;
}

static VALUE enumerable_to_value_set_i(VALUE i, VALUE* memo)
{
    ValueSet& result = *reinterpret_cast<ValueSet*>(memo);
    result.insert(i);
    return Qnil;
}

/* call-seq:
 *  enum.to_value_set		=> value_set
 *
 * Builds a ValueSet object from this enumerable
 */
static VALUE enumerable_to_value_set(VALUE self)
{
    VALUE vresult = rb_funcall(cValueSet, id_new, 0);
    ValueSet& result = get_wrapped_set(vresult);

    rb_iterate(rb_each, self, RUBY_METHOD_FUNC(enumerable_to_value_set_i), reinterpret_cast<VALUE>(&result));
    return vresult;
}

/*
 * Document-class: ValueSet
 *
 * ValueSet is a wrapper around the C++ set<> template. set<> is an ordered container,
 * for which union(), intersection() and difference() is done in linear time. For performance
 * reasons, in the case of ValueSet, the values are ordered by their VALUE, which roughly is
 * their object_id.
 */

extern "C" void Init_value_set()
{
    rb_define_method(rb_mEnumerable, "to_value_set", RUBY_METHOD_FUNC(enumerable_to_value_set), 0);

    cValueSet = rb_define_class("ValueSet", rb_cObject);
    id_new = rb_intern("new");
    rb_define_alloc_func(cValueSet, value_set_alloc);
    rb_define_method(cValueSet, "each", RUBY_METHOD_FUNC(value_set_each), 0);
    rb_define_method(cValueSet, "include?", RUBY_METHOD_FUNC(value_set_include_p), 1);
    rb_define_method(cValueSet, "include_all?", RUBY_METHOD_FUNC(value_set_include_all_p), 1);
    rb_define_method(cValueSet, "union", RUBY_METHOD_FUNC(value_set_union), 1);
    rb_define_method(cValueSet, "intersection", RUBY_METHOD_FUNC(value_set_intersection), 1);
    rb_define_method(cValueSet, "intersects?", RUBY_METHOD_FUNC(value_set_intersects), 1);
    rb_define_method(cValueSet, "difference", RUBY_METHOD_FUNC(value_set_difference), 1);
    rb_define_method(cValueSet, "insert", RUBY_METHOD_FUNC(value_set_insert), 1);
    rb_define_method(cValueSet, "merge", RUBY_METHOD_FUNC(value_set_merge), 1);
    rb_define_method(cValueSet, "delete", RUBY_METHOD_FUNC(value_set_delete), 1);
    rb_define_method(cValueSet, "==", RUBY_METHOD_FUNC(value_set_equal), 1);
    rb_define_method(cValueSet, "to_value_set", RUBY_METHOD_FUNC(value_set_to_value_set), 0);
    rb_define_method(cValueSet, "dup", RUBY_METHOD_FUNC(value_set_dup), 0);
    rb_define_method(cValueSet, "empty?", RUBY_METHOD_FUNC(value_set_empty_p), 0);
    rb_define_method(cValueSet, "size", RUBY_METHOD_FUNC(value_set_size), 0);
    rb_define_method(cValueSet, "clear", RUBY_METHOD_FUNC(value_set_clear), 0);
    rb_define_method(cValueSet, "initialize_copy", RUBY_METHOD_FUNC(value_set_initialize_copy), 1);
    rb_define_method(cValueSet, "delete_if", RUBY_METHOD_FUNC(value_set_delete_if), 0);
}

<|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                              SOFA :: Framework                              *
*                                                                             *
* Authors: The SOFA Team (see Authors.txt)                                    *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <sofa/helper/Utils.h>
#include <sofa/helper/system/FileSystem.h>
#include <sofa/helper/system/Locale.h>
#include <sofa/helper/Logger.h>

#ifdef WIN32
# include <Windows.h>
# include <StrSafe.h>
#elif defined _XBOX
# include <xtl.h>
#elif defined __APPLE__
# include <mach-o/dyld.h>       // for _NSGetExecutablePath()
# include <errno.h>
#else
# include <unistd.h>            // for readlink()
# include <errno.h>
# include <linux/limits.h>      // for PATH_MAX
#endif

#include <cstdlib>
#include <vector>
#include <iostream>
#include <fstream>

using sofa::helper::system::FileSystem;

namespace sofa
{
namespace helper
{

std::wstring Utils::widenString(const std::string& s)
{
    // Set LC_CTYPE according to the environnement variable, for mbsrtowcs().
    system::TemporaryLocale locale(LC_CTYPE, "");

    const char * src = s.c_str();
    // Call mbsrtowcs() once to find out the length of the converted string.
    size_t length = mbsrtowcs(NULL, &src, 0, NULL);
    if (length == size_t(-1)) {
        int error = errno;
        Logger::getMainLogger().log(Logger::Warning, strerror(error), "Utils::widenString()");
        return L"";
    }

    // Call mbsrtowcs() again with a correctly sized buffer to actually do the conversion.
    wchar_t * buffer = new wchar_t[length + 1];
    length = mbsrtowcs(buffer, &src, length + 1, NULL);
    if (length == size_t(-1)) {
        int error = errno;
        Logger::getMainLogger().log(Logger::Warning, strerror(error), "Utils::widenString()");
        delete[] buffer;
        return L"";
    }

    if (src != NULL) {
        Logger::getMainLogger().log(Logger::Warning, "Conversion failed (\"" + s + "\")", "Utils::widenString()");
        delete[] buffer;
        return L"";
    }

    std::wstring result(buffer);
    delete[] buffer;
    return result;
}

std::string Utils::narrowString(const std::wstring& ws)
{
    // Set LC_CTYPE according to the environnement variable, for wcstombs().
    system::TemporaryLocale locale(LC_CTYPE, "");

    const wchar_t * src = ws.c_str();
    // Call wcstombs() once to find out the length of the converted string.
    size_t length = wcstombs(NULL, src, 0);
    if (length == size_t(-1)) {
        Logger::getMainLogger().log(Logger::Warning, "Conversion failed", "Utils::narrowString()");
        return "";
    }

    // Call wcstombs() again with a correctly sized buffer to actually do the conversion.
    char * buffer = new char[length + 1];
    length = wcstombs(buffer, src, length + 1);
    if (length == size_t(-1)) {
        Logger::getMainLogger().log(Logger::Warning, "Conversion failed", "Utils::narrowString()");
        delete[] buffer;
        return "";
    }

    std::string result(buffer);
    delete[] buffer;
    return result;
}

std::string Utils::downcaseString(const std::string& s)
{
    std::string result = s;
    std::transform(result.begin(), result.end(), result.begin(), ::tolower);
    return result;
}

std::string Utils::upcaseString(const std::string& s)
{
    std::string result = s;
    std::transform(result.begin(), result.end(), result.begin(), ::toupper);
    return result;
}

#if defined WIN32 || defined _XBOX
# ifdef WIN32
std::string Utils::GetLastError() {
    LPVOID lpErrMsgBuf;
    LPVOID lpMessageBuf;
    DWORD dwErrorCode = ::GetLastError();

    // Get the string corresponding to the error code
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
                  | FORMAT_MESSAGE_FROM_SYSTEM
                  | FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  dwErrorCode,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPTSTR)&lpErrMsgBuf,
                  0,
                  NULL);
    // Allocate a bigger buffer
    lpMessageBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
                                      (lstrlen((LPCTSTR)lpErrMsgBuf)+40)*sizeof(TCHAR));
    // Format the message like so: "error 'code': 'message'"
    StringCchPrintf((LPTSTR)lpMessageBuf,
                    LocalSize(lpMessageBuf) / sizeof(TCHAR),
                    TEXT("error %d: %s"),
                    dwErrorCode, lpErrMsgBuf);

    std::wstring wsMessage((LPCTSTR)lpMessageBuf);
    LocalFree(lpErrMsgBuf);
    LocalFree(lpMessageBuf);
    return narrowString(wsMessage);
}
# else  // XBOX
std::string Utils::GetLastError() {
    DWORD dwErrorCode = ::GetLastError();
    char buffer[32];
    sprintf_s(buffer, 32, "0x%08.8X", dwErrorCode);
    return buffer;
}
# endif
#endif

static std::string computeExecutablePath()
{
    std::string path = "";

#if defined(_XBOX) || defined(PS3)
    Logger::getMainLogger().log(Logger::Error, "Utils::getExecutablePath() is not implemented on this platform.");

#elif defined(WIN32)
    std::vector<TCHAR> lpFilename(MAX_PATH);
    int ret = GetModuleFileName(NULL, /* NULL --> executable of the current process */
        &lpFilename[0],
        MAX_PATH);
    if (ret == 0 || ret == MAX_PATH) {
        Logger::getMainLogger().log(Logger::Error, Utils::GetLastError(), "Utils::getExecutablePath()");
    } else {
        path = Utils::narrowString(std::wstring(&lpFilename[0]));
    }

#elif defined(__APPLE__)
    std::vector<char> buffer(PATH_MAX);
    std::vector<char> real_path(PATH_MAX);
    uint32_t size = buffer.size();
    if (_NSGetExecutablePath(&buffer[0], &size) != 0) {
        Logger::getMainLogger().log(Logger::Error, "_NSGetExecutablePath() failed", "Utils::getExecutablePath()");
    }
    if (realpath(&buffer[0], &real_path[0]) == 0) {
        Logger::getMainLogger().log(Logger::Error, "realpath() failed", "Utils::getExecutablePath()");
    }
    path = std::string(&real_path[0]);

#else  // Linux
    std::vector<char> buffer(PATH_MAX);
    if (readlink("/proc/self/exe", &buffer[0], buffer.size()) == -1) {
        int error = errno;
        Logger::getMainLogger().log(Logger::Error, strerror(error), "Utils::getExecutablePath()");
    } else {
        path = std::string(&buffer[0]);
    }
#endif

    return FileSystem::cleanPath(path);
}

const std::string& Utils::getExecutablePath()
{
    static const std::string path = computeExecutablePath();
    return path;
}

const std::string& Utils::getExecutableDirectory()
{
    static const std::string path = FileSystem::getParentDirectory(getExecutablePath());
    return path;
}

static std::string computeSofaPathPrefix()
{
    const std::string exePath = Utils::getExecutablePath();
    std::size_t pos = exePath.rfind("/bin/");
    if (pos == std::string::npos) {
        Logger::getMainLogger().log(Logger::Error, "failed to deduce the root path of Sofa from the application path: (" + exePath + ")", "Utils::getSofaPathPrefix()");
        // Safest thing to return in this case, I guess.
        return Utils::getExecutableDirectory();
    }
    else {
        return exePath.substr(0, pos);
    }
}

const std::string& Utils::getSofaPathPrefix()
{
    static const std::string prefix = computeSofaPathPrefix();
    return prefix;
}

std::map<std::string, std::string> Utils::readBasicIniFile(const std::string& path)
{
    std::map<std::string, std::string> map;
    std::ifstream iniFile(path.c_str());
    if (!iniFile.good())
    {
        Logger::getMainLogger().log(Logger::Error, "Error while trying to read file (" + path + ")", "Utils::readBasicIniFile()");
    }

    std::string line;
    while (std::getline(iniFile, line))
    {
        size_t equalPos = line.find_first_of('=');
        if (equalPos != std::string::npos)
        {
            const std::string key = line.substr(0, equalPos);
            const std::string value = line.substr(equalPos + 1, std::string::npos);
            map[key] = value;
        }
    }

    return map;
}

} // namespace helper
} // namespace sofa

<commit_msg>[helper] if environment variable SOFA_ROOT is defined, this value will be used to compute the SofaPathPrefix<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This library is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This library is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this library; if not, write to the Free Software Foundation,     *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
*******************************************************************************
*                              SOFA :: Framework                              *
*                                                                             *
* Authors: The SOFA Team (see Authors.txt)                                    *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <sofa/helper/Utils.h>
#include <sofa/helper/system/FileSystem.h>
#include <sofa/helper/system/Locale.h>
#include <sofa/helper/Logger.h>

#ifdef WIN32
# include <Windows.h>
# include <StrSafe.h>
#elif defined _XBOX
# include <xtl.h>
#elif defined __APPLE__
# include <mach-o/dyld.h>       // for _NSGetExecutablePath()
# include <errno.h>
#else
# include <unistd.h>            // for readlink()
# include <errno.h>
# include <linux/limits.h>      // for PATH_MAX
#endif

#include <cstdlib>
#include <vector>
#include <iostream>
#include <fstream>

using sofa::helper::system::FileSystem;

namespace sofa
{
namespace helper
{

std::wstring Utils::widenString(const std::string& s)
{
    // Set LC_CTYPE according to the environnement variable, for mbsrtowcs().
    system::TemporaryLocale locale(LC_CTYPE, "");

    const char * src = s.c_str();
    // Call mbsrtowcs() once to find out the length of the converted string.
    size_t length = mbsrtowcs(NULL, &src, 0, NULL);
    if (length == size_t(-1)) {
        int error = errno;
        Logger::getMainLogger().log(Logger::Warning, strerror(error), "Utils::widenString()");
        return L"";
    }

    // Call mbsrtowcs() again with a correctly sized buffer to actually do the conversion.
    wchar_t * buffer = new wchar_t[length + 1];
    length = mbsrtowcs(buffer, &src, length + 1, NULL);
    if (length == size_t(-1)) {
        int error = errno;
        Logger::getMainLogger().log(Logger::Warning, strerror(error), "Utils::widenString()");
        delete[] buffer;
        return L"";
    }

    if (src != NULL) {
        Logger::getMainLogger().log(Logger::Warning, "Conversion failed (\"" + s + "\")", "Utils::widenString()");
        delete[] buffer;
        return L"";
    }

    std::wstring result(buffer);
    delete[] buffer;
    return result;
}

std::string Utils::narrowString(const std::wstring& ws)
{
    // Set LC_CTYPE according to the environnement variable, for wcstombs().
    system::TemporaryLocale locale(LC_CTYPE, "");

    const wchar_t * src = ws.c_str();
    // Call wcstombs() once to find out the length of the converted string.
    size_t length = wcstombs(NULL, src, 0);
    if (length == size_t(-1)) {
        Logger::getMainLogger().log(Logger::Warning, "Conversion failed", "Utils::narrowString()");
        return "";
    }

    // Call wcstombs() again with a correctly sized buffer to actually do the conversion.
    char * buffer = new char[length + 1];
    length = wcstombs(buffer, src, length + 1);
    if (length == size_t(-1)) {
        Logger::getMainLogger().log(Logger::Warning, "Conversion failed", "Utils::narrowString()");
        delete[] buffer;
        return "";
    }

    std::string result(buffer);
    delete[] buffer;
    return result;
}

std::string Utils::downcaseString(const std::string& s)
{
    std::string result = s;
    std::transform(result.begin(), result.end(), result.begin(), ::tolower);
    return result;
}

std::string Utils::upcaseString(const std::string& s)
{
    std::string result = s;
    std::transform(result.begin(), result.end(), result.begin(), ::toupper);
    return result;
}

#if defined WIN32 || defined _XBOX
# ifdef WIN32
std::string Utils::GetLastError() {
    LPVOID lpErrMsgBuf;
    LPVOID lpMessageBuf;
    DWORD dwErrorCode = ::GetLastError();

    // Get the string corresponding to the error code
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
                  | FORMAT_MESSAGE_FROM_SYSTEM
                  | FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  dwErrorCode,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                  (LPTSTR)&lpErrMsgBuf,
                  0,
                  NULL);
    // Allocate a bigger buffer
    lpMessageBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
                                      (lstrlen((LPCTSTR)lpErrMsgBuf)+40)*sizeof(TCHAR));
    // Format the message like so: "error 'code': 'message'"
    StringCchPrintf((LPTSTR)lpMessageBuf,
                    LocalSize(lpMessageBuf) / sizeof(TCHAR),
                    TEXT("error %d: %s"),
                    dwErrorCode, lpErrMsgBuf);

    std::wstring wsMessage((LPCTSTR)lpMessageBuf);
    LocalFree(lpErrMsgBuf);
    LocalFree(lpMessageBuf);
    return narrowString(wsMessage);
}
# else  // XBOX
std::string Utils::GetLastError() {
    DWORD dwErrorCode = ::GetLastError();
    char buffer[32];
    sprintf_s(buffer, 32, "0x%08.8X", dwErrorCode);
    return buffer;
}
# endif
#endif

static std::string computeExecutablePath()
{
    std::string path = "";

#if defined(_XBOX) || defined(PS3)
    Logger::getMainLogger().log(Logger::Error, "Utils::getExecutablePath() is not implemented on this platform.");

#elif defined(WIN32)
    std::vector<TCHAR> lpFilename(MAX_PATH);
    int ret = GetModuleFileName(NULL, /* NULL --> executable of the current process */
        &lpFilename[0],
        MAX_PATH);
    if (ret == 0 || ret == MAX_PATH) {
        Logger::getMainLogger().log(Logger::Error, Utils::GetLastError(), "Utils::getExecutablePath()");
    } else {
        path = Utils::narrowString(std::wstring(&lpFilename[0]));
    }

#elif defined(__APPLE__)
    std::vector<char> buffer(PATH_MAX);
    std::vector<char> real_path(PATH_MAX);
    uint32_t size = buffer.size();
    if (_NSGetExecutablePath(&buffer[0], &size) != 0) {
        Logger::getMainLogger().log(Logger::Error, "_NSGetExecutablePath() failed", "Utils::getExecutablePath()");
    }
    if (realpath(&buffer[0], &real_path[0]) == 0) {
        Logger::getMainLogger().log(Logger::Error, "realpath() failed", "Utils::getExecutablePath()");
    }
    path = std::string(&real_path[0]);

#else  // Linux
    std::vector<char> buffer(PATH_MAX);
    if (readlink("/proc/self/exe", &buffer[0], buffer.size()) == -1) {
        int error = errno;
        Logger::getMainLogger().log(Logger::Error, strerror(error), "Utils::getExecutablePath()");
    } else {
        path = std::string(&buffer[0]);
    }
#endif

    return FileSystem::cleanPath(path);
}

const std::string& Utils::getExecutablePath()
{
    static const std::string path = computeExecutablePath();
    return path;
}

const std::string& Utils::getExecutableDirectory()
{
    static const std::string path = FileSystem::getParentDirectory(getExecutablePath());
    return path;
}

static std::string computeSofaPathPrefix()
{
    char* pathVar = getenv("SOFA_ROOT");
    if (pathVar != NULL && FileSystem::exists(pathVar))
    {
        return std::string(pathVar);
    }
    else {
        const std::string exePath = Utils::getExecutablePath();
        std::size_t pos = exePath.rfind("/bin/");
        if (pos == std::string::npos) {
            Logger::getMainLogger().log(Logger::Error, "failed to deduce the root path of Sofa from the application path: (" + exePath + ")", "Utils::getSofaPathPrefix()");
            // Safest thing to return in this case, I guess.
            return Utils::getExecutableDirectory();
        }
        else {
            return exePath.substr(0, pos);
        }
    }
}

const std::string& Utils::getSofaPathPrefix()
{
    static const std::string prefix = computeSofaPathPrefix();
    return prefix;
}

std::map<std::string, std::string> Utils::readBasicIniFile(const std::string& path)
{
    std::map<std::string, std::string> map;
    std::ifstream iniFile(path.c_str());
    if (!iniFile.good())
    {
        Logger::getMainLogger().log(Logger::Error, "Error while trying to read file (" + path + ")", "Utils::readBasicIniFile()");
    }

    std::string line;
    while (std::getline(iniFile, line))
    {
        size_t equalPos = line.find_first_of('=');
        if (equalPos != std::string::npos)
        {
            const std::string key = line.substr(0, equalPos);
            const std::string value = line.substr(equalPos + 1, std::string::npos);
            map[key] = value;
        }
    }

    return map;
}

} // namespace helper
} // namespace sofa

<|endoftext|>