<commit_before>// ffmpeg player output (portaudio)
// part of MusicPlayer, https://github.com/albertz/music-player
// Copyright (c) 2012, Albert Zeyer, www.az2000.de
// All rights reserved.
// This code is under the 2-clause BSD license, see License.txt in the root directory of this project.

#include "ffmpeg.h"

#include <portaudio.h>
#include <boost/bind.hpp>

#ifdef __APPLE__
// PortAudio specific Mac stuff
#include "pa_mac_core.h"
#endif

// For setting the thread priority to realtime on MacOSX.
#ifdef __APPLE__
#include <mach/mach_init.h>
#include <mach/thread_policy.h>
#include <mach/thread_act.h> // the doc says mach/sched.h but that seems outdated...
#include <pthread.h>
#include <mach/mach_error.h>
#include <mach/mach_time.h>
#endif
static void setRealtime();

#define USE_PORTAUDIO_CALLBACK 0

int initPlayerOutput() {
	PaError ret = Pa_Initialize();
	if(ret != paNoError)
		Py_FatalError("PortAudio init failed");
	return 0;
}

template<typename T> struct OutPaSampleFormat{};
template<> struct OutPaSampleFormat<int16_t> {
	static const PaSampleFormat format = paInt16;
};
template<> struct OutPaSampleFormat<float32_t> {
	static const PaSampleFormat format = paFloat32;
};

struct PlayerObject::OutStream {
	PlayerObject* const player;
	PaStream* stream;
	bool needRealtimeReset; // PortAudio callback thread must set itself to realtime

	OutStream(PlayerObject* p) : player(p), stream(NULL), needRealtimeReset(false) {
		mlock(this, sizeof(*this));
	}
	~OutStream() { close(); }

#if USE_PORTAUDIO_CALLBACK
	static int paStreamCallback(
		const void *input, void *output,
		unsigned long frameCount,
		const PaStreamCallbackTimeInfo* timeInfo,
		PaStreamCallbackFlags statusFlags,
		void *userData )
	{
		OutStream* outStream = (OutStream*) userData;

		// We must not hold the PyGIL here!
		PyScopedLock lock(outStream->player->lock);

		if(outStream->needRealtimeReset) {
			outStream->needRealtimeReset = false;
			setRealtime();
		}

		outStream->player->readOutStream((OUTSAMPLE_t*) output, frameCount * outStream->player->outNumChannels, NULL);
		return paContinue;
	}
#else
	PyThread audioThread;
	void audioThreadProc(PyMutex& threadLock, bool& stopSignal) {
		while(true) {
			{
				PyScopedLock l(threadLock);
				if(stopSignal) return;
			}

			if(needRealtimeReset) {
				needRealtimeReset = false;
				setRealtime();
			}

			OUTSAMPLE_t buffer[4800 * 2]; // 100ms stereo in 48khz
			size_t frameCount = 0;
			{
				PyScopedLock lock(player->lock);
				if(stopSignal) return;
				player->readOutStream(buffer, sizeof(buffer)/sizeof(OUTSAMPLE_t), NULL);
				frameCount = sizeof(buffer)/sizeof(OUTSAMPLE_t) / player->outNumChannels;
			}

			PaError ret = Pa_WriteStream(stream, buffer, frameCount);
			if(ret == paOutputUnderflowed)
				printf("warning: paOutputUnderflowed\n");
			else if(ret != paNoError) {
				printf("Pa_WriteStream error %i (%s)\n", ret, Pa_GetErrorText(ret));
				// sleep half a second to avoid spamming
				for(int i = 0; i < 50; ++i) {
					usleep(10 * 1000);
					PyScopedLock l(threadLock);
					if(stopSignal) return;
				}
			}
		}
	}
#endif

	bool open() {
		if(stream) close();
		assert(stream == NULL);

		PaStreamParameters outputParameters;

#if defined(__APPLE__)
		PaMacCoreStreamInfo macInfo;
		PaMacCore_SetupStreamInfo( &macInfo,
			paMacCorePlayNice | paMacCorePro );
		outputParameters.hostApiSpecificStreamInfo = &macInfo;
#elif defined(__LINUX__)
		// TODO: if we have PaAlsa_EnableRealtimeScheduling in portaudio,
		// we can call that to enable RT priority with ALSA.
		// We could check dynamically via dsym.
		outputParameters.hostApiSpecificStreamInfo = NULL;
#else
		outputParameters.hostApiSpecificStreamInfo = NULL;
#endif

		outputParameters.device = Pa_GetDefaultOutputDevice();
		if (outputParameters.device == paNoDevice) {
			PyErr_SetString(PyExc_RuntimeError, "Pa_GetDefaultOutputDevice didn't returned a device");
			return false;
		}
		outputParameters.channelCount = player->outNumChannels;
		outputParameters.sampleFormat = OutPaSampleFormat<OUTSAMPLE_t>::format;
		outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;

		// Note about framesPerBuffer:
		// Earlier, we used (2048 * 5 * OUTSAMPLEBYTELEN) which caused
		// some random more or less rare cracking noises.
		// See here: https://github.com/albertz/music-player/issues/35
		// This doesn't seem to happen with paFramesPerBufferUnspecified.

		PaError ret = Pa_OpenStream(
			&stream,
			NULL, // no input
			&outputParameters,
			player->outSamplerate, // sampleRate
			paFramesPerBufferUnspecified, // framesPerBuffer,
			paClipOff | paDitherOff,
#if USE_PORTAUDIO_CALLBACK
			&paStreamCallback,
#else
			NULL,
#endif
			this //void *userData
			);

		if(ret != paNoError) {
			PyErr_Format(PyExc_RuntimeError, "Pa_OpenStream failed: (err %i) %s", ret, Pa_GetErrorText(ret));
			if(stream)
				close();
			return false;
		}

		needRealtimeReset = true;
		Pa_StartStream(stream);

#if !USE_PORTAUDIO_CALLBACK
		audioThread.func = boost::bind(&OutStream::audioThreadProc, this, _1, _2);
		audioThread.start();
#endif
		return true;
	}

	void close() {
		if(this->stream == NULL) return;
		// we expect that we have the player lock here.
		// reset fader.
		player->fader.init(0,0);
		// we must release the player lock so that any thread-join can be done.
		PaStream* stream = NULL;
		std::swap(stream, this->stream);
		PyScopedUnlock unlock(player->lock);
		audioThread.stop();
		Pa_CloseStream(stream);
	}

	bool isOpen() const { return stream != NULL; }

};

int PlayerObject::setPlaying(bool playing) {
	PlayerObject* player = this;
	bool oldplayingstate = false;
	PyScopedGIL gil;
	{
		PyScopedGIUnlock gunlock;

		player->workerThread.start(); // if not running yet, start
		if(!player->outStream.get())
			player->outStream.reset(new OutStream(this));
		assert(player->outStream.get() != NULL);

		if(soundcardOutputEnabled) {
			if(playing && !player->outStream->stream) {
				if(!player->outStream->open())
					playing = false;
			}
		}

		oldplayingstate = player->playing;
		if(soundcardOutputEnabled && player->outStream.get() && player->outStream->isOpen() && oldplayingstate != playing)
			fader.init(playing ? 1 : -1, outSamplerate);
		player->playing = playing;
	}

	if(!PyErr_Occurred() && player->dict) {
		Py_INCREF(player->dict);
		PyObject* onPlayingStateChange = PyDict_GetItemString(player->dict, "onPlayingStateChange");
		if(onPlayingStateChange && onPlayingStateChange != Py_None) {
			Py_INCREF(onPlayingStateChange);

			PyObject* kwargs = PyDict_New();
			assert(kwargs);
			PyDict_SetItemString_retain(kwargs, "oldState", PyBool_FromLong(oldplayingstate));
			PyDict_SetItemString_retain(kwargs, "newState", PyBool_FromLong(playing));

			PyObject* retObj = PyEval_CallObjectWithKeywords(onPlayingStateChange, NULL, kwargs);
			Py_XDECREF(retObj);

			// errors are not fatal from the callback, so handle it now and go on
			if(PyErr_Occurred())
				PyErr_Print();

			Py_DECREF(kwargs);
			Py_DECREF(onPlayingStateChange);
		}
		Py_DECREF(player->dict);
	}

	return PyErr_Occurred() ? -1 : 0;
}

#ifdef __APPLE__
// https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html
// Also, from Google Native Client, osx/nacl_thread_nice.c has some related code.
// Or, from Google Chrome, platform_thread_mac.mm.
void setRealtime() {
	kern_return_t ret;
	thread_port_t threadport = pthread_mach_thread_np(pthread_self());

	thread_extended_policy_data_t policy;
	policy.timeshare = 0;
	ret = thread_policy_set(threadport,
							THREAD_EXTENDED_POLICY,
							(thread_policy_t)&policy,
							THREAD_EXTENDED_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_EXTENDED_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}

	thread_precedence_policy_data_t precedence;
	precedence.importance = 63;
	ret = thread_policy_set(threadport,
							THREAD_PRECEDENCE_POLICY,
							(thread_policy_t)&precedence,
							THREAD_PRECEDENCE_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_PRECEDENCE_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}

	mach_timebase_info_data_t tb_info;
	mach_timebase_info(&tb_info);
	double timeFact = ((double)tb_info.denom / (double)tb_info.numer) * 1000000;

	thread_time_constraint_policy_data_t ttcpolicy;
	ttcpolicy.period = 2.9 * timeFact; // about 128 frames @44.1KHz
	ttcpolicy.computation = 0.75 * 2.9 * timeFact;
	ttcpolicy.constraint = 0.85 * 2.9 * timeFact;
	ttcpolicy.preemptible = 1;

	ret = thread_policy_set(threadport,
							THREAD_TIME_CONSTRAINT_POLICY,
							(thread_policy_t)&ttcpolicy,
							THREAD_TIME_CONSTRAINT_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_TIME_CONSTRAINT_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}
}
#else
void setRealtime() {} // not implemented yet
#endif

<commit_msg>comment<commit_after>// ffmpeg player output (portaudio)
// part of MusicPlayer, https://github.com/albertz/music-player
// Copyright (c) 2012, Albert Zeyer, www.az2000.de
// All rights reserved.
// This code is under the 2-clause BSD license, see License.txt in the root directory of this project.

#include "ffmpeg.h"

#include <portaudio.h>
#include <boost/bind.hpp>

#ifdef __APPLE__
// PortAudio specific Mac stuff
#include "pa_mac_core.h"
#endif

// For setting the thread priority to realtime on MacOSX.
#ifdef __APPLE__
#include <mach/mach_init.h>
#include <mach/thread_policy.h>
#include <mach/thread_act.h> // the doc says mach/sched.h but that seems outdated...
#include <pthread.h>
#include <mach/mach_error.h>
#include <mach/mach_time.h>
#endif
static void setRealtime();

/*
The implementation with the PortAudio callback was there first.
For testing, I implemented also the blocking PortAudio interface.
I had some issues which small hiccups in the audio output -
maybe the blocking PortAudio implementation can avoid them better.
For the callback, we need to minimize the locks - or better, avoid
them fully. I'm not sure it is good to depend on thread context
switches in case it is locked. This however needs some heavy redesign.
*/
#define USE_PORTAUDIO_CALLBACK 0

int initPlayerOutput() {
	PaError ret = Pa_Initialize();
	if(ret != paNoError)
		Py_FatalError("PortAudio init failed");
	return 0;
}

template<typename T> struct OutPaSampleFormat{};
template<> struct OutPaSampleFormat<int16_t> {
	static const PaSampleFormat format = paInt16;
};
template<> struct OutPaSampleFormat<float32_t> {
	static const PaSampleFormat format = paFloat32;
};

struct PlayerObject::OutStream {
	PlayerObject* const player;
	PaStream* stream;
	bool needRealtimeReset; // PortAudio callback thread must set itself to realtime

	OutStream(PlayerObject* p) : player(p), stream(NULL), needRealtimeReset(false) {
		mlock(this, sizeof(*this));
	}
	~OutStream() { close(); }

#if USE_PORTAUDIO_CALLBACK
	static int paStreamCallback(
		const void *input, void *output,
		unsigned long frameCount,
		const PaStreamCallbackTimeInfo* timeInfo,
		PaStreamCallbackFlags statusFlags,
		void *userData )
	{
		OutStream* outStream = (OutStream*) userData;

		// We must not hold the PyGIL here!
		PyScopedLock lock(outStream->player->lock);

		if(outStream->needRealtimeReset) {
			outStream->needRealtimeReset = false;
			setRealtime();
		}

		outStream->player->readOutStream((OUTSAMPLE_t*) output, frameCount * outStream->player->outNumChannels, NULL);
		return paContinue;
	}
#else
	PyThread audioThread;
	void audioThreadProc(PyMutex& threadLock, bool& stopSignal) {
		while(true) {
			{
				PyScopedLock l(threadLock);
				if(stopSignal) return;
			}

			if(needRealtimeReset) {
				needRealtimeReset = false;
				setRealtime();
			}

			OUTSAMPLE_t buffer[4800 * 2]; // 100ms stereo in 48khz
			size_t frameCount = 0;
			{
				PyScopedLock lock(player->lock);
				if(stopSignal) return;
				player->readOutStream(buffer, sizeof(buffer)/sizeof(OUTSAMPLE_t), NULL);
				frameCount = sizeof(buffer)/sizeof(OUTSAMPLE_t) / player->outNumChannels;
			}

			PaError ret = Pa_WriteStream(stream, buffer, frameCount);
			if(ret == paOutputUnderflowed)
				printf("warning: paOutputUnderflowed\n");
			else if(ret != paNoError) {
				printf("Pa_WriteStream error %i (%s)\n", ret, Pa_GetErrorText(ret));
				// sleep half a second to avoid spamming
				for(int i = 0; i < 50; ++i) {
					usleep(10 * 1000);
					PyScopedLock l(threadLock);
					if(stopSignal) return;
				}
			}
		}
	}
#endif

	bool open() {
		if(stream) close();
		assert(stream == NULL);

		PaStreamParameters outputParameters;

#if defined(__APPLE__)
		PaMacCoreStreamInfo macInfo;
		PaMacCore_SetupStreamInfo( &macInfo,
			paMacCorePlayNice | paMacCorePro );
		outputParameters.hostApiSpecificStreamInfo = &macInfo;
#elif defined(__LINUX__)
		// TODO: if we have PaAlsa_EnableRealtimeScheduling in portaudio,
		// we can call that to enable RT priority with ALSA.
		// We could check dynamically via dsym.
		outputParameters.hostApiSpecificStreamInfo = NULL;
#else
		outputParameters.hostApiSpecificStreamInfo = NULL;
#endif

		outputParameters.device = Pa_GetDefaultOutputDevice();
		if (outputParameters.device == paNoDevice) {
			PyErr_SetString(PyExc_RuntimeError, "Pa_GetDefaultOutputDevice didn't returned a device");
			return false;
		}
		outputParameters.channelCount = player->outNumChannels;
		outputParameters.sampleFormat = OutPaSampleFormat<OUTSAMPLE_t>::format;
		outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;

		// Note about framesPerBuffer:
		// Earlier, we used (2048 * 5 * OUTSAMPLEBYTELEN) which caused
		// some random more or less rare cracking noises.
		// See here: https://github.com/albertz/music-player/issues/35
		// This doesn't seem to happen with paFramesPerBufferUnspecified.

		PaError ret = Pa_OpenStream(
			&stream,
			NULL, // no input
			&outputParameters,
			player->outSamplerate, // sampleRate
			paFramesPerBufferUnspecified, // framesPerBuffer,
			paClipOff | paDitherOff,
#if USE_PORTAUDIO_CALLBACK
			&paStreamCallback,
#else
			NULL,
#endif
			this //void *userData
			);

		if(ret != paNoError) {
			PyErr_Format(PyExc_RuntimeError, "Pa_OpenStream failed: (err %i) %s", ret, Pa_GetErrorText(ret));
			if(stream)
				close();
			return false;
		}

		needRealtimeReset = true;
		Pa_StartStream(stream);

#if !USE_PORTAUDIO_CALLBACK
		audioThread.func = boost::bind(&OutStream::audioThreadProc, this, _1, _2);
		audioThread.start();
#endif
		return true;
	}

	void close() {
		if(this->stream == NULL) return;
		// we expect that we have the player lock here.
		// reset fader.
		player->fader.init(0,0);
		// we must release the player lock so that any thread-join can be done.
		PaStream* stream = NULL;
		std::swap(stream, this->stream);
		PyScopedUnlock unlock(player->lock);
		audioThread.stop();
		Pa_CloseStream(stream);
	}

	bool isOpen() const { return stream != NULL; }

};

int PlayerObject::setPlaying(bool playing) {
	PlayerObject* player = this;
	bool oldplayingstate = false;
	PyScopedGIL gil;
	{
		PyScopedGIUnlock gunlock;

		player->workerThread.start(); // if not running yet, start
		if(!player->outStream.get())
			player->outStream.reset(new OutStream(this));
		assert(player->outStream.get() != NULL);

		if(soundcardOutputEnabled) {
			if(playing && !player->outStream->stream) {
				if(!player->outStream->open())
					playing = false;
			}
		}

		oldplayingstate = player->playing;
		if(soundcardOutputEnabled && player->outStream.get() && player->outStream->isOpen() && oldplayingstate != playing)
			fader.init(playing ? 1 : -1, outSamplerate);
		player->playing = playing;
	}

	if(!PyErr_Occurred() && player->dict) {
		Py_INCREF(player->dict);
		PyObject* onPlayingStateChange = PyDict_GetItemString(player->dict, "onPlayingStateChange");
		if(onPlayingStateChange && onPlayingStateChange != Py_None) {
			Py_INCREF(onPlayingStateChange);

			PyObject* kwargs = PyDict_New();
			assert(kwargs);
			PyDict_SetItemString_retain(kwargs, "oldState", PyBool_FromLong(oldplayingstate));
			PyDict_SetItemString_retain(kwargs, "newState", PyBool_FromLong(playing));

			PyObject* retObj = PyEval_CallObjectWithKeywords(onPlayingStateChange, NULL, kwargs);
			Py_XDECREF(retObj);

			// errors are not fatal from the callback, so handle it now and go on
			if(PyErr_Occurred())
				PyErr_Print();

			Py_DECREF(kwargs);
			Py_DECREF(onPlayingStateChange);
		}
		Py_DECREF(player->dict);
	}

	return PyErr_Occurred() ? -1 : 0;
}

#ifdef __APPLE__
// https://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html
// Also, from Google Native Client, osx/nacl_thread_nice.c has some related code.
// Or, from Google Chrome, platform_thread_mac.mm.
void setRealtime() {
	kern_return_t ret;
	thread_port_t threadport = pthread_mach_thread_np(pthread_self());

	thread_extended_policy_data_t policy;
	policy.timeshare = 0;
	ret = thread_policy_set(threadport,
							THREAD_EXTENDED_POLICY,
							(thread_policy_t)&policy,
							THREAD_EXTENDED_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_EXTENDED_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}

	thread_precedence_policy_data_t precedence;
	precedence.importance = 63;
	ret = thread_policy_set(threadport,
							THREAD_PRECEDENCE_POLICY,
							(thread_policy_t)&precedence,
							THREAD_PRECEDENCE_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_PRECEDENCE_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}

	mach_timebase_info_data_t tb_info;
	mach_timebase_info(&tb_info);
	double timeFact = ((double)tb_info.denom / (double)tb_info.numer) * 1000000;

	thread_time_constraint_policy_data_t ttcpolicy;
	ttcpolicy.period = 2.9 * timeFact; // about 128 frames @44.1KHz
	ttcpolicy.computation = 0.75 * 2.9 * timeFact;
	ttcpolicy.constraint = 0.85 * 2.9 * timeFact;
	ttcpolicy.preemptible = 1;

	ret = thread_policy_set(threadport,
							THREAD_TIME_CONSTRAINT_POLICY,
							(thread_policy_t)&ttcpolicy,
							THREAD_TIME_CONSTRAINT_POLICY_COUNT);
	if(ret != KERN_SUCCESS) {
		fprintf(stderr, "setRealtime() THREAD_TIME_CONSTRAINT_POLICY failed: %d, %s\n", ret, mach_error_string(ret));
		return;
	}
}
#else
void setRealtime() {} // not implemented yet
#endif

<|endoftext|>


<commit_before>// Copyright © 2011, Université catholique de Louvain
// 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.
//
// 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 HOLDER 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.

#ifndef __MODSYSTEM_H
#define __MODSYSTEM_H

#include "../mozartcore.hh"

#include <iostream>

#ifndef MOZART_GENERATOR

namespace mozart {

namespace builtins {

///////////////////
// System module //
///////////////////

class ModSystem: public Module {
public:
  ModSystem(): Module("System") {}

  class PrintRepr: public Builtin<PrintRepr> {
  public:
    PrintRepr(): Builtin("printRepr") {}

    void operator()(VM vm, In value, In toStdErr, In newLine) {
      auto boolToStdErr = getArgument<bool>(vm, toStdErr, MOZART_STR("Boolean"));
      auto boolNewLine = getArgument<bool>(vm, newLine, MOZART_STR("Boolean"));

      auto& stream = boolToStdErr ? std::cerr : std::cout;
      stream << repr(vm, value);
      if (boolNewLine)
        stream << std::endl;
    }
  };

  class GetRepr: public Builtin<GetRepr> {
  public:
    GetRepr(): Builtin("getRepr") {}

    void operator()(VM vm, In value, Out result) {
      std::basic_stringstream<char> buffer;
      buffer << repr(vm, value);
      auto bufferStr = buffer.str();

      auto utf8str = makeLString(bufferStr.c_str(), bufferStr.size());
      auto str = toUTF<nchar>(utf8str);

      result = Atom::build(vm, str.length, str.string);
    }
  };

  class PrintVS: public Builtin<PrintVS> {
  public:
    PrintVS(): Builtin("printVS") {}

    void operator()(VM vm, In value, In toStdErr, In newLine) {
      auto boolToStdErr = getArgument<bool>(vm, toStdErr, MOZART_STR("Boolean"));
      auto boolNewLine = getArgument<bool>(vm, newLine, MOZART_STR("Boolean"));

      std::basic_stringstream<nchar> buffer;
      VirtualString(value).toString(vm, buffer);
      auto bufferStr = buffer.str();

      auto& stream = boolToStdErr ? std::cerr : std::cout;
      stream << toUTF<char>(makeLString(bufferStr.c_str(), bufferStr.size()));
      if (boolNewLine)
        stream << std::endl;
    }
  };

  class GCDo: public Builtin<GCDo> {
  public:
    GCDo(): Builtin("gcDo") {}

    void operator()(VM vm) {
      // TODO
    }
  };

  class Eq: public Builtin<Eq> {
  public:
    Eq(): Builtin("eq") {}

    void operator()(VM vm, In lhs, In rhs, Out result) {
      result = build(vm, lhs.isSameNode(rhs));
    }
  };

  class OnTopLevel: public Builtin<OnTopLevel> {
  public:
    OnTopLevel(): Builtin("onTopLevel") {}

    void operator()(VM vm, Out result) {
      result = build(vm, vm->isOnTopLevel());
    }
  };

  class Exit: public Builtin<Exit> {
  public:
    Exit(): Builtin("exit") {}

    void operator()(VM vm, In exitCode) {
      std::exit(getArgument<nativeint>(vm, exitCode, MOZART_STR("Integer")));
    }
  };
};

}

}

#endif // MOZART_GENERATOR

#endif // __MODSYSTEM_H
<commit_msg>Fixed spelling of System.onToplevel.<commit_after>// Copyright © 2011, Université catholique de Louvain
// 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.
//
// 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 HOLDER 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.

#ifndef __MODSYSTEM_H
#define __MODSYSTEM_H

#include "../mozartcore.hh"

#include <iostream>

#ifndef MOZART_GENERATOR

namespace mozart {

namespace builtins {

///////////////////
// System module //
///////////////////

class ModSystem: public Module {
public:
  ModSystem(): Module("System") {}

  class PrintRepr: public Builtin<PrintRepr> {
  public:
    PrintRepr(): Builtin("printRepr") {}

    void operator()(VM vm, In value, In toStdErr, In newLine) {
      auto boolToStdErr = getArgument<bool>(vm, toStdErr, MOZART_STR("Boolean"));
      auto boolNewLine = getArgument<bool>(vm, newLine, MOZART_STR("Boolean"));

      auto& stream = boolToStdErr ? std::cerr : std::cout;
      stream << repr(vm, value);
      if (boolNewLine)
        stream << std::endl;
    }
  };

  class GetRepr: public Builtin<GetRepr> {
  public:
    GetRepr(): Builtin("getRepr") {}

    void operator()(VM vm, In value, Out result) {
      std::basic_stringstream<char> buffer;
      buffer << repr(vm, value);
      auto bufferStr = buffer.str();

      auto utf8str = makeLString(bufferStr.c_str(), bufferStr.size());
      auto str = toUTF<nchar>(utf8str);

      result = Atom::build(vm, str.length, str.string);
    }
  };

  class PrintVS: public Builtin<PrintVS> {
  public:
    PrintVS(): Builtin("printVS") {}

    void operator()(VM vm, In value, In toStdErr, In newLine) {
      auto boolToStdErr = getArgument<bool>(vm, toStdErr, MOZART_STR("Boolean"));
      auto boolNewLine = getArgument<bool>(vm, newLine, MOZART_STR("Boolean"));

      std::basic_stringstream<nchar> buffer;
      VirtualString(value).toString(vm, buffer);
      auto bufferStr = buffer.str();

      auto& stream = boolToStdErr ? std::cerr : std::cout;
      stream << toUTF<char>(makeLString(bufferStr.c_str(), bufferStr.size()));
      if (boolNewLine)
        stream << std::endl;
    }
  };

  class GCDo: public Builtin<GCDo> {
  public:
    GCDo(): Builtin("gcDo") {}

    void operator()(VM vm) {
      // TODO
    }
  };

  class Eq: public Builtin<Eq> {
  public:
    Eq(): Builtin("eq") {}

    void operator()(VM vm, In lhs, In rhs, Out result) {
      result = build(vm, lhs.isSameNode(rhs));
    }
  };

  class OnTopLevel: public Builtin<OnTopLevel> {
  public:
    OnTopLevel(): Builtin("onToplevel") {}

    void operator()(VM vm, Out result) {
      result = build(vm, vm->isOnTopLevel());
    }
  };

  class Exit: public Builtin<Exit> {
  public:
    Exit(): Builtin("exit") {}

    void operator()(VM vm, In exitCode) {
      std::exit(getArgument<nativeint>(vm, exitCode, MOZART_STR("Integer")));
    }
  };
};

}

}

#endif // MOZART_GENERATOR

#endif // __MODSYSTEM_H
<|endoftext|>


<commit_before>#include "bitcoinamountfield.h"
#include "qvalidatedlineedit.h"
#include "qvaluecombobox.h"
#include "bitcoinunits.h"

#include <QLabel>
#include <QLineEdit>
#include <QRegExpValidator>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QComboBox>
#include <QDebug>

BitcoinAmountField::BitcoinAmountField(QWidget *parent):
        QWidget(parent), amount(0), decimals(0), currentUnit(-1)
{
    amount = new QValidatedLineEdit(this);
    amount->setValidator(new QRegExpValidator(QRegExp("[0-9]*"), this));
    amount->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
    amount->installEventFilter(this);
    amount->setMaximumWidth(100);
    decimals = new QValidatedLineEdit(this);
    decimals->setValidator(new QRegExpValidator(QRegExp("[0-9]+"), this));
    decimals->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
    decimals->setMaximumWidth(75);

    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->setSpacing(0);
    layout->addWidget(amount);
    layout->addWidget(new QLabel(QString(".")));
    layout->addWidget(decimals);
    unit = new QValueComboBox(this);
    unit->setModel(new BitcoinUnits(this));
    layout->addWidget(unit);
    layout->addStretch(1);
    layout->setContentsMargins(0,0,0,0);

    setLayout(layout);

    setFocusPolicy(Qt::TabFocus);
    setFocusProxy(amount);

    // If one if the widgets changes, the combined content changes as well
    connect(amount, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged()));
    connect(decimals, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged()));
    connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));

    // TODO: set default based on configuration
    unitChanged(unit->currentIndex());
}

void BitcoinAmountField::setText(const QString &text)
{
    const QStringList parts = text.split(QString("."));
    if(parts.size() == 2)
    {
        amount->setText(parts[0]);
        decimals->setText(parts[1]);
    }
    else
    {
        amount->setText(QString());
        decimals->setText(QString());
    }
}

void BitcoinAmountField::clear()
{
    amount->clear();
    decimals->clear();
    // TODO: set default based on configuration
    unit->setCurrentIndex(0);
}

bool BitcoinAmountField::validate()
{
    bool valid = true;
    if(decimals->text().isEmpty())
    {
        decimals->setValid(false);
        valid = false;
    }
    if(!BitcoinUnits::parse(currentUnit, text(), 0))
    {
        setValid(false);
        valid = false;
    }

    return valid;
}

void BitcoinAmountField::setValid(bool valid)
{
    amount->setValid(valid);
    decimals->setValid(valid);
}

QString BitcoinAmountField::text() const
{
    if(decimals->text().isEmpty() && amount->text().isEmpty())
    {
        return QString();
    }
    return amount->text() + QString(".") + decimals->text();
}

// Intercept '.' and ',' keys, if pressed focus a specified widget
bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
{
    Q_UNUSED(object);
    if(event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if(keyEvent->key() == Qt::Key_Period || keyEvent->key() == Qt::Key_Comma)
        {
            decimals->setFocus();
            decimals->selectAll();
        }
    }
    return false;
}

QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
{
    QWidget::setTabOrder(prev, amount);
    QWidget::setTabOrder(amount, decimals);
    return decimals;
}

qint64 BitcoinAmountField::value(bool *valid_out) const
{
    qint64 val_out = 0;
    bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
    if(valid_out)
    {
        *valid_out = valid;
    }
    return val_out;
}

void BitcoinAmountField::setValue(qint64 value)
{
    setText(BitcoinUnits::format(currentUnit, value));
}

void BitcoinAmountField::unitChanged(int idx)
{
    // Use description tooltip for current unit for the combobox
    unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());

    // Determine new unit ID
    int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();

    // Parse current value and convert to new unit
    bool valid = false;
    qint64 currentValue = value(&valid);

    currentUnit = newUnit;

    // Set max length after retrieving the value, to prevent truncation
    amount->setMaxLength(BitcoinUnits::amountDigits(currentUnit));
    decimals->setMaxLength(BitcoinUnits::decimals(currentUnit));

    if(valid)
    {
        setValue(currentValue);
    }
    else
    {
        // If current value is invalid, just clear field
        setText("");
    }
    setValid(true);
}

void BitcoinAmountField::setDisplayUnit(int newUnit)
{
    unit->setValue(newUnit);
}
<commit_msg>Make dot in amount field more apparent<commit_after>#include "bitcoinamountfield.h"
#include "qvalidatedlineedit.h"
#include "qvaluecombobox.h"
#include "bitcoinunits.h"

#include <QLabel>
#include <QLineEdit>
#include <QRegExpValidator>
#include <QHBoxLayout>
#include <QKeyEvent>
#include <QComboBox>
#include <QDebug>

BitcoinAmountField::BitcoinAmountField(QWidget *parent):
        QWidget(parent), amount(0), decimals(0), currentUnit(-1)
{
    amount = new QValidatedLineEdit(this);
    amount->setValidator(new QRegExpValidator(QRegExp("[0-9]*"), this));
    amount->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
    amount->installEventFilter(this);
    amount->setMaximumWidth(100);
    decimals = new QValidatedLineEdit(this);
    decimals->setValidator(new QRegExpValidator(QRegExp("[0-9]+"), this));
    decimals->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
    decimals->setMaximumWidth(75);

    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->setSpacing(0);
    layout->addWidget(amount);
    layout->addWidget(new QLabel(QString("<b>.</b>")));
    layout->addWidget(decimals);
    unit = new QValueComboBox(this);
    unit->setModel(new BitcoinUnits(this));
    layout->addWidget(unit);
    layout->addStretch(1);
    layout->setContentsMargins(0,0,0,0);

    setLayout(layout);

    setFocusPolicy(Qt::TabFocus);
    setFocusProxy(amount);

    // If one if the widgets changes, the combined content changes as well
    connect(amount, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged()));
    connect(decimals, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged()));
    connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int)));

    // TODO: set default based on configuration
    unitChanged(unit->currentIndex());
}

void BitcoinAmountField::setText(const QString &text)
{
    const QStringList parts = text.split(QString("."));
    if(parts.size() == 2)
    {
        amount->setText(parts[0]);
        decimals->setText(parts[1]);
    }
    else
    {
        amount->setText(QString());
        decimals->setText(QString());
    }
}

void BitcoinAmountField::clear()
{
    amount->clear();
    decimals->clear();
    // TODO: set default based on configuration
    unit->setCurrentIndex(0);
}

bool BitcoinAmountField::validate()
{
    bool valid = true;
    if(decimals->text().isEmpty())
    {
        decimals->setValid(false);
        valid = false;
    }
    if(!BitcoinUnits::parse(currentUnit, text(), 0))
    {
        setValid(false);
        valid = false;
    }

    return valid;
}

void BitcoinAmountField::setValid(bool valid)
{
    amount->setValid(valid);
    decimals->setValid(valid);
}

QString BitcoinAmountField::text() const
{
    if(decimals->text().isEmpty() && amount->text().isEmpty())
    {
        return QString();
    }
    return amount->text() + QString(".") + decimals->text();
}

// Intercept '.' and ',' keys, if pressed focus a specified widget
bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event)
{
    Q_UNUSED(object);
    if(event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if(keyEvent->key() == Qt::Key_Period || keyEvent->key() == Qt::Key_Comma)
        {
            decimals->setFocus();
            decimals->selectAll();
        }
    }
    return false;
}

QWidget *BitcoinAmountField::setupTabChain(QWidget *prev)
{
    QWidget::setTabOrder(prev, amount);
    QWidget::setTabOrder(amount, decimals);
    return decimals;
}

qint64 BitcoinAmountField::value(bool *valid_out) const
{
    qint64 val_out = 0;
    bool valid = BitcoinUnits::parse(currentUnit, text(), &val_out);
    if(valid_out)
    {
        *valid_out = valid;
    }
    return val_out;
}

void BitcoinAmountField::setValue(qint64 value)
{
    setText(BitcoinUnits::format(currentUnit, value));
}

void BitcoinAmountField::unitChanged(int idx)
{
    // Use description tooltip for current unit for the combobox
    unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString());

    // Determine new unit ID
    int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt();

    // Parse current value and convert to new unit
    bool valid = false;
    qint64 currentValue = value(&valid);

    currentUnit = newUnit;

    // Set max length after retrieving the value, to prevent truncation
    amount->setMaxLength(BitcoinUnits::amountDigits(currentUnit));
    decimals->setMaxLength(BitcoinUnits::decimals(currentUnit));

    if(valid)
    {
        setValue(currentValue);
    }
    else
    {
        // If current value is invalid, just clear field
        setText("");
    }
    setValid(true);
}

void BitcoinAmountField::setDisplayUnit(int newUnit)
{
    unit->setValue(newUnit);
}
<|endoftext|>


<commit_before>#include "AtomTable_wrap.h"
#include <opencog/atomspace/AtomTable.h>
#include <boost/python/class.hpp>

using namespace opencog;
using namespace boost::python;

void init_AtomTable_py()
{
    class_<AtomTable, boost::noncopyable>("AtomTable", no_init)
        .def(init<optional<bool> >())
        //.def(init<const Handle&>())
    ;
}
<commit_msg>Exposed getSize() method of AtomTable class.<commit_after>#include "AtomTable_wrap.h"
#include <opencog/atomspace/AtomTable.h>
#include <boost/python/class.hpp>

using namespace opencog;
using namespace boost::python;

void init_AtomTable_py()
{
    class_<AtomTable, boost::noncopyable>("AtomTable", no_init)
        .def(init<optional<bool> >())
        .def("getSize", &AtomTable::getSize)
    ;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "../config/config.hpp"

#ifdef MFEM_USE_MPI

#include "fem.hpp"

namespace mfem
{

ParNonlinearForm::ParNonlinearForm(ParFiniteElementSpace *pf)
   : NonlinearForm(pf), pGrad(Operator::Hypre_ParCSR)
{
   X.MakeRef(pf, NULL);
   Y.MakeRef(pf, NULL);
   MFEM_VERIFY(!Serial(), "internal MFEM error");
}

double ParNonlinearForm::GetParGridFunctionEnergy(const Vector &x) const
{
   double loc_energy, glob_energy;

   loc_energy = GetGridFunctionEnergy(x);

   if (fnfi.Size())
   {
      MFEM_ABORT("TODO: add energy contribution from shared faces");
   }

   MPI_Allreduce(&loc_energy, &glob_energy, 1, MPI_DOUBLE, MPI_SUM,
                 ParFESpace()->GetComm());

   return glob_energy;
}

void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
{
   NonlinearForm::Mult(x, y); // x --(P)--> aux1 --(A_local)--> aux2

   if (fnfi.Size())
   {
      // Terms over shared interior faces in parallel.
      ParFiniteElementSpace *pfes = ParFESpace();
      ParMesh *pmesh = pfes->GetParMesh();
      FaceElementTransformations *tr;
      const FiniteElement *fe1, *fe2;
      Array<int> vdofs1, vdofs2;
      Vector el_x, el_y;

      aux1.HostReadWrite();
      X.MakeRef(aux1, 0); // aux1 contains P.x
      X.ExchangeFaceNbrData();
      const int n_shared_faces = pmesh->GetNSharedFaces();
      for (int i = 0; i < n_shared_faces; i++)
      {
         tr = pmesh->GetSharedFaceTransformations(i, true);
         int Elem2NbrNo = tr->Elem2No - pmesh->GetNE();

         fe1 = pfes->GetFE(tr->Elem1No);
         fe2 = pfes->GetFaceNbrFE(Elem2NbrNo);

         pfes->GetElementVDofs(tr->Elem1No, vdofs1);
         pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);

         el_x.SetSize(vdofs1.Size() + vdofs2.Size());
         X.GetSubVector(vdofs1, el_x.GetData());
         X.FaceNbrData().GetSubVector(vdofs2, el_x.GetData() + vdofs1.Size());

         for (int k = 0; k < fnfi.Size(); k++)
         {
            fnfi[k]->AssembleFaceVector(*fe1, *fe2, *tr, el_x, el_y);
            aux2.AddElementVector(vdofs1, el_y.GetData());
         }
      }
   }

   P->MultTranspose(aux2, y);

   y.HostReadWrite();
   for (int i = 0; i < ess_tdof_list.Size(); i++)
   {
      y(ess_tdof_list[i]) = 0.0;
   }
}

const SparseMatrix &ParNonlinearForm::GetLocalGradient(const Vector &x) const
{
   NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.

   return *Grad;
}

Operator &ParNonlinearForm::GetGradient(const Vector &x) const
{
   ParFiniteElementSpace *pfes = ParFESpace();

   pGrad.Clear();

   NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.

   OperatorHandle dA(pGrad.Type()), Ph(pGrad.Type());

   if (fnfi.Size() == 0)
   {
      dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
                             pfes->GetDofOffsets(), Grad);
   }
   else
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   // TODO - construct Dof_TrueDof_Matrix directly in the pGrad format
   Ph.ConvertFrom(pfes->Dof_TrueDof_Matrix());
   pGrad.MakePtAP(dA, Ph);

   // Impose b.c. on pGrad
   OperatorHandle pGrad_e;
   pGrad_e.EliminateRowsCols(pGrad, ess_tdof_list);

   return *pGrad.Ptr();
}

void ParNonlinearForm::Update()
{
   Y.MakeRef(ParFESpace(), NULL);
   X.MakeRef(ParFESpace(), NULL);
   pGrad.Clear();
   NonlinearForm::Update();
}

ParBlockNonlinearForm::ParBlockNonlinearForm(Array<ParFiniteElementSpace *> &pf)
   : BlockNonlinearForm()
{
   pBlockGrad = NULL;
   SetParSpaces(pf);
}

void ParBlockNonlinearForm::SetParSpaces(Array<ParFiniteElementSpace *> &pf)
{
   delete pBlockGrad;
   pBlockGrad = NULL;

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         delete phBlockGrad(s1,s2);
      }
   }

   Array<FiniteElementSpace *> serialSpaces(pf.Size());

   for (int s=0; s<pf.Size(); s++)
   {
      serialSpaces[s] = (FiniteElementSpace *) pf[s];
   }

   SetSpaces(serialSpaces);

   phBlockGrad.SetSize(fes.Size(), fes.Size());

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         phBlockGrad(s1,s2) = new OperatorHandle(Operator::Hypre_ParCSR);
      }
   }
}

ParFiniteElementSpace * ParBlockNonlinearForm::ParFESpace(int k)
{
   return (ParFiniteElementSpace *)fes[k];
}

const ParFiniteElementSpace *ParBlockNonlinearForm::ParFESpace(int k) const
{
   return (const ParFiniteElementSpace *)fes[k];
}

// Here, rhs is a true dof vector
void ParBlockNonlinearForm::SetEssentialBC(const
                                           Array<Array<int> *>&bdr_attr_is_ess,
                                           Array<Vector *> &rhs)
{
   Array<Vector *> nullarray(fes.Size());
   nullarray = NULL;

   BlockNonlinearForm::SetEssentialBC(bdr_attr_is_ess, nullarray);

   for (int s=0; s<fes.Size(); ++s)
   {
      if (rhs[s])
      {
         ParFiniteElementSpace *pfes = ParFESpace(s);
         for (int i=0; i < ess_vdofs[s]->Size(); ++i)
         {
            int tdof = pfes->GetLocalTDofNumber((*(ess_vdofs[s]))[i]);
            if (tdof >= 0)
            {
               (*rhs[s])(tdof) = 0.0;
            }
         }
      }
   }
}

double ParBlockNonlinearForm::GetEnergy(const Vector &x) const
{

   xs_true.Update(x.GetData(), block_trueOffsets);
   xs.Update(block_offsets);

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->Mult(
         xs_true.GetBlock(s), xs.GetBlock(s));
   }

   double enloc=BlockNonlinearForm::GetEnergyBlocked(xs);
   double englo=0.0;

   MPI_Allreduce(&enloc, &englo, 1, MPI_DOUBLE, MPI_SUM,
                 ParFESpace(0)->GetComm());

   return englo;
}

void ParBlockNonlinearForm::Mult(const Vector &x, Vector &y) const
{
   xs_true.Update(x.GetData(), block_trueOffsets);
   ys_true.Update(y.GetData(), block_trueOffsets);
   xs.Update(block_offsets);
   ys.Update(block_offsets);

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->Mult(
         xs_true.GetBlock(s), xs.GetBlock(s));
   }

   BlockNonlinearForm::MultBlocked(xs, ys);

   if (fnfi.Size() > 0)
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->MultTranspose(
         ys.GetBlock(s), ys_true.GetBlock(s));
   }
}

/// Return the local gradient matrix for the given true-dof vector x
const BlockOperator & ParBlockNonlinearForm::GetLocalGradient(
   const Vector &x) const
{
   xs_true.Update(x.GetData(), block_trueOffsets);
   xs.Update(block_offsets);

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->Mult(
         xs_true.GetBlock(s), xs.GetBlock(s));
   }

   BlockNonlinearForm::GetGradientBlocked(xs); // (re)assemble Grad with b.c.

   return *BlockGrad;
}

// Set the operator type id for the parallel gradient matrix/operator.
void ParBlockNonlinearForm::SetGradientType(Operator::Type tid)
{
   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         phBlockGrad(s1,s2)->SetType(tid);
      }
   }
}

BlockOperator & ParBlockNonlinearForm::GetGradient(const Vector &x) const
{
   if (pBlockGrad == NULL)
   {
      pBlockGrad = new BlockOperator(block_trueOffsets);
   }

   Array<const ParFiniteElementSpace *> pfes(fes.Size());

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      pfes[s1] = ParFESpace(s1);

      for (int s2=0; s2<fes.Size(); ++s2)
      {
         phBlockGrad(s1,s2)->Clear();
      }
   }

   GetLocalGradient(x); // gradients are stored in 'Grads'

   if (fnfi.Size() > 0)
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         OperatorHandle dA(phBlockGrad(s1,s2)->Type()),
                        Ph(phBlockGrad(s1,s2)->Type()),
                        Rh(phBlockGrad(s1,s2)->Type());

         if (s1 == s2)
         {
            dA.MakeSquareBlockDiag(pfes[s1]->GetComm(), pfes[s1]->GlobalVSize(),
                                   pfes[s1]->GetDofOffsets(), Grads(s1,s1));
            Ph.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
            phBlockGrad(s1,s1)->MakePtAP(dA, Ph);
         }
         else
         {
            dA.MakeRectangularBlockDiag(pfes[s1]->GetComm(),
                                        pfes[s1]->GlobalVSize(),
                                        pfes[s2]->GlobalVSize(),
                                        pfes[s1]->GetDofOffsets(),
                                        pfes[s2]->GetDofOffsets(),
                                        Grads(s1,s2));
            Rh.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
            Ph.ConvertFrom(pfes[s2]->Dof_TrueDof_Matrix());

            phBlockGrad(s1,s2)->MakeRAP(Rh, dA, Ph);
         }

         pBlockGrad->SetBlock(s1, s2, phBlockGrad(s1,s2)->Ptr());
      }
   }

   return *pBlockGrad;
}

ParBlockNonlinearForm::~ParBlockNonlinearForm()
{
   delete pBlockGrad;
   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         delete phBlockGrad(s1,s2);
      }
   }
}

}

#endif
<commit_msg>cosmetics<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "../config/config.hpp"

#ifdef MFEM_USE_MPI

#include "fem.hpp"

namespace mfem
{

ParNonlinearForm::ParNonlinearForm(ParFiniteElementSpace *pf)
   : NonlinearForm(pf), pGrad(Operator::Hypre_ParCSR)
{
   X.MakeRef(pf, NULL);
   Y.MakeRef(pf, NULL);
   MFEM_VERIFY(!Serial(), "internal MFEM error");
}

double ParNonlinearForm::GetParGridFunctionEnergy(const Vector &x) const
{
   double loc_energy, glob_energy;

   loc_energy = GetGridFunctionEnergy(x);

   if (fnfi.Size())
   {
      MFEM_ABORT("TODO: add energy contribution from shared faces");
   }

   MPI_Allreduce(&loc_energy, &glob_energy, 1, MPI_DOUBLE, MPI_SUM,
                 ParFESpace()->GetComm());

   return glob_energy;
}

void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
{
   NonlinearForm::Mult(x, y); // x --(P)--> aux1 --(A_local)--> aux2

   if (fnfi.Size())
   {
      // Terms over shared interior faces in parallel.
      ParFiniteElementSpace *pfes = ParFESpace();
      ParMesh *pmesh = pfes->GetParMesh();
      FaceElementTransformations *tr;
      const FiniteElement *fe1, *fe2;
      Array<int> vdofs1, vdofs2;
      Vector el_x, el_y;

      aux1.HostReadWrite();
      X.MakeRef(aux1, 0); // aux1 contains P.x
      X.ExchangeFaceNbrData();
      const int n_shared_faces = pmesh->GetNSharedFaces();
      for (int i = 0; i < n_shared_faces; i++)
      {
         tr = pmesh->GetSharedFaceTransformations(i, true);
         int Elem2NbrNo = tr->Elem2No - pmesh->GetNE();

         fe1 = pfes->GetFE(tr->Elem1No);
         fe2 = pfes->GetFaceNbrFE(Elem2NbrNo);

         pfes->GetElementVDofs(tr->Elem1No, vdofs1);
         pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);

         el_x.SetSize(vdofs1.Size() + vdofs2.Size());
         X.GetSubVector(vdofs1, el_x.GetData());
         X.FaceNbrData().GetSubVector(vdofs2, el_x.GetData() + vdofs1.Size());

         for (int k = 0; k < fnfi.Size(); k++)
         {
            fnfi[k]->AssembleFaceVector(*fe1, *fe2, *tr, el_x, el_y);
            aux2.AddElementVector(vdofs1, el_y.GetData());
         }
      }
   }

   P->MultTranspose(aux2, y);

   y.HostReadWrite();
   for (int i = 0; i < ess_tdof_list.Size(); i++)
   {
      y(ess_tdof_list[i]) = 0.0;
   }
}

const SparseMatrix &ParNonlinearForm::GetLocalGradient(const Vector &x) const
{
   NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.

   return *Grad;
}

Operator &ParNonlinearForm::GetGradient(const Vector &x) const
{
   ParFiniteElementSpace *pfes = ParFESpace();

   pGrad.Clear();

   NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.

   OperatorHandle dA(pGrad.Type()), Ph(pGrad.Type());

   if (fnfi.Size() == 0)
   {
      dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
                             pfes->GetDofOffsets(), Grad);
   }
   else
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   // TODO - construct Dof_TrueDof_Matrix directly in the pGrad format
   Ph.ConvertFrom(pfes->Dof_TrueDof_Matrix());
   pGrad.MakePtAP(dA, Ph);

   // Impose b.c. on pGrad
   OperatorHandle pGrad_e;
   pGrad_e.EliminateRowsCols(pGrad, ess_tdof_list);

   return *pGrad.Ptr();
}

void ParNonlinearForm::Update()
{
   Y.MakeRef(ParFESpace(), NULL);
   X.MakeRef(ParFESpace(), NULL);
   pGrad.Clear();
   NonlinearForm::Update();
}

ParBlockNonlinearForm::ParBlockNonlinearForm(Array<ParFiniteElementSpace *> &pf)
   : BlockNonlinearForm()
{
   pBlockGrad = NULL;
   SetParSpaces(pf);
}

void ParBlockNonlinearForm::SetParSpaces(Array<ParFiniteElementSpace *> &pf)
{
   delete pBlockGrad;
   pBlockGrad = NULL;

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         delete phBlockGrad(s1,s2);
      }
   }

   Array<FiniteElementSpace *> serialSpaces(pf.Size());

   for (int s=0; s<pf.Size(); s++)
   {
      serialSpaces[s] = (FiniteElementSpace *) pf[s];
   }

   SetSpaces(serialSpaces);

   phBlockGrad.SetSize(fes.Size(), fes.Size());

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         phBlockGrad(s1,s2) = new OperatorHandle(Operator::Hypre_ParCSR);
      }
   }
}

ParFiniteElementSpace * ParBlockNonlinearForm::ParFESpace(int k)
{
   return (ParFiniteElementSpace *)fes[k];
}

const ParFiniteElementSpace *ParBlockNonlinearForm::ParFESpace(int k) const
{
   return (const ParFiniteElementSpace *)fes[k];
}

// Here, rhs is a true dof vector
void ParBlockNonlinearForm::SetEssentialBC(const
                                           Array<Array<int> *>&bdr_attr_is_ess,
                                           Array<Vector *> &rhs)
{
   Array<Vector *> nullarray(fes.Size());
   nullarray = NULL;

   BlockNonlinearForm::SetEssentialBC(bdr_attr_is_ess, nullarray);

   for (int s=0; s<fes.Size(); ++s)
   {
      if (rhs[s])
      {
         ParFiniteElementSpace *pfes = ParFESpace(s);
         for (int i=0; i < ess_vdofs[s]->Size(); ++i)
         {
            int tdof = pfes->GetLocalTDofNumber((*(ess_vdofs[s]))[i]);
            if (tdof >= 0)
            {
               (*rhs[s])(tdof) = 0.0;
            }
         }
      }
   }
}

double ParBlockNonlinearForm::GetEnergy(const Vector &x) const
{
   xs_true.Update(x.GetData(), block_trueOffsets);
   xs.Update(block_offsets);

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->Mult(
         xs_true.GetBlock(s), xs.GetBlock(s));
   }

   double enloc=BlockNonlinearForm::GetEnergyBlocked(xs);
   double englo=0.0;

   MPI_Allreduce(&enloc, &englo, 1, MPI_DOUBLE, MPI_SUM,
                 ParFESpace(0)->GetComm());

   return englo;
}

void ParBlockNonlinearForm::Mult(const Vector &x, Vector &y) const
{
   xs_true.Update(x.GetData(), block_trueOffsets);
   ys_true.Update(y.GetData(), block_trueOffsets);
   xs.Update(block_offsets);
   ys.Update(block_offsets);

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->Mult(
         xs_true.GetBlock(s), xs.GetBlock(s));
   }

   BlockNonlinearForm::MultBlocked(xs, ys);

   if (fnfi.Size() > 0)
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->MultTranspose(
         ys.GetBlock(s), ys_true.GetBlock(s));
   }
}

/// Return the local gradient matrix for the given true-dof vector x
const BlockOperator & ParBlockNonlinearForm::GetLocalGradient(
   const Vector &x) const
{
   xs_true.Update(x.GetData(), block_trueOffsets);
   xs.Update(block_offsets);

   for (int s=0; s<fes.Size(); ++s)
   {
      fes[s]->GetProlongationMatrix()->Mult(
         xs_true.GetBlock(s), xs.GetBlock(s));
   }

   BlockNonlinearForm::GetGradientBlocked(xs); // (re)assemble Grad with b.c.

   return *BlockGrad;
}

// Set the operator type id for the parallel gradient matrix/operator.
void ParBlockNonlinearForm::SetGradientType(Operator::Type tid)
{
   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         phBlockGrad(s1,s2)->SetType(tid);
      }
   }
}

BlockOperator & ParBlockNonlinearForm::GetGradient(const Vector &x) const
{
   if (pBlockGrad == NULL)
   {
      pBlockGrad = new BlockOperator(block_trueOffsets);
   }

   Array<const ParFiniteElementSpace *> pfes(fes.Size());

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      pfes[s1] = ParFESpace(s1);

      for (int s2=0; s2<fes.Size(); ++s2)
      {
         phBlockGrad(s1,s2)->Clear();
      }
   }

   GetLocalGradient(x); // gradients are stored in 'Grads'

   if (fnfi.Size() > 0)
   {
      MFEM_ABORT("TODO: assemble contributions from shared face terms");
   }

   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         OperatorHandle dA(phBlockGrad(s1,s2)->Type()),
                        Ph(phBlockGrad(s1,s2)->Type()),
                        Rh(phBlockGrad(s1,s2)->Type());

         if (s1 == s2)
         {
            dA.MakeSquareBlockDiag(pfes[s1]->GetComm(), pfes[s1]->GlobalVSize(),
                                   pfes[s1]->GetDofOffsets(), Grads(s1,s1));
            Ph.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
            phBlockGrad(s1,s1)->MakePtAP(dA, Ph);
         }
         else
         {
            dA.MakeRectangularBlockDiag(pfes[s1]->GetComm(),
                                        pfes[s1]->GlobalVSize(),
                                        pfes[s2]->GlobalVSize(),
                                        pfes[s1]->GetDofOffsets(),
                                        pfes[s2]->GetDofOffsets(),
                                        Grads(s1,s2));
            Rh.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
            Ph.ConvertFrom(pfes[s2]->Dof_TrueDof_Matrix());

            phBlockGrad(s1,s2)->MakeRAP(Rh, dA, Ph);
         }

         pBlockGrad->SetBlock(s1, s2, phBlockGrad(s1,s2)->Ptr());
      }
   }

   return *pBlockGrad;
}

ParBlockNonlinearForm::~ParBlockNonlinearForm()
{
   delete pBlockGrad;
   for (int s1=0; s1<fes.Size(); ++s1)
   {
      for (int s2=0; s2<fes.Size(); ++s2)
      {
         delete phBlockGrad(s1,s2);
      }
   }
}

}

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: OGLTrans_TransitionImpl.hxx,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_
#define INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_

#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/vector/b3dvector.hxx>

#include <vector>
#include <GL/gl.h>

class Primitive;
class Operation;
class SceneObject;

/** OpenGL 3D Transition class. It implicitly is constructed from XOGLTransition

    This class is capable of making itself into many difference transitions. It holds Primitives and Operations on those primitives.
*/
class OGLTransitionImpl
{
public:
    OGLTransitionImpl() :
        maLeavingSlidePrimitives(),
        maEnteringSlidePrimitives(),
        maSceneObjects()
    {}

    ~OGLTransitionImpl();

    void prepare();
    void display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
    void finish();

    void makeOutsideCubeFaceToLeft();
    void makeInsideCubeFaceToLeft();
    void makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m );
    void makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles );
    void makeHelix( ::sal_uInt16 nRows );
    void makeFallLeaving();
    void makeTurnAround();
    void makeTurnDown();
    void makeIris();
    void makeRochade();

private:
    /** clears all the primitives and operations
    */
    void clear();

    /** All the primitives that use the leaving slide texture
    */
    std::vector<Primitive> maLeavingSlidePrimitives;

    /** All the primitives that use the leaving slide texture
    */
    std::vector<Primitive> maEnteringSlidePrimitives;

    /** All the surrounding scene objects
    */
    std::vector<SceneObject*> maSceneObjects;

    /** All the operations that should be applied to both leaving and entering slide primitives. These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.
    */
    std::vector<Operation*> OverallOperations;
};

class SceneObject
{
public:
    SceneObject();

    virtual void prepare() {};
    virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
    virtual void finish() {};

    void pushPrimitive (const Primitive &p);

protected:
    /** All the surrounding scene primitives
    */
    std::vector<Primitive> maPrimitives;
};

class Iris : public SceneObject
{
public:
    Iris ();

    virtual void prepare();
    virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
    virtual void finish();

private:

    GLuint maTexture;
};

/** This class is a list of Triangles that will share Operations, and could possibly share
*/
class Primitive
{
public:
    Primitive() {}
    // making copy constructor explicit makes the class un-suitable for use with stl containers
    Primitive(const Primitive& rvalue);
    ~Primitive();

    void display(double nTime, double SlideWidthScale, double SlideHeightScale);
    const Primitive& operator=(const Primitive& rvalue);

    /** PushBack a vertex,normal, and tex coord. Each SlideLocation is where on the slide is mapped to this location ( from (0,0) to (1,1)  ). This will make sure the correct aspect ratio is used, and helps to make slides begin and end at the correct position. (0,0) is the top left of the slide, and (1,1) is the bottom right.

    @param SlideLocation0
    Location of first Vertex on slide

    @param SlideLocation1
    Location of second Vertex on slide

    @param SlideLocation2
    Location of third Vertex on slide

    */
    void pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2);

    /** clear all the vertices, normals, tex coordinates, and normals
    */
    void clearTriangles();

    /** guards against directly changing the vertices

        @return
        the list of vertices
    */
    const std::vector<basegfx::B3DVector>& getVertices() const {return Vertices;}

    /** guards against directly changing the vertices
    */
    const std::vector<basegfx::B3DVector>& getNormals() const {return Normals;}

    /** guards against directly changing the vertices

        @return
        the list of Texture Coordinates

    */
    const std::vector<basegfx::B2DVector>& getTexCoords() const {return TexCoords;}

    /** list of Operations to be performed on this primitive.These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.

        @return
        the list of Operations

    */
    std::vector<Operation*> Operations;

private:
    /** list of vertices
    */
    std::vector<basegfx::B3DVector> Vertices;

    /** list of Normals
    */
    std::vector<basegfx::B3DVector> Normals;

    /** list of Texture Coordinates
    */
    std::vector<basegfx::B2DVector> TexCoords;
};

/** This class is to be derived to make any operation (tranform) you may need in order to construct your transitions
*/
class Operation
{
public:
    Operation(){}
    virtual ~Operation(){}

    /** Should this operation be interpolated . If TRUE, the transform will smoothly move from making no difference from t = 0.0 to nT0 to being completely transformed from t = nT1 to 1. If FALSE, the transform will be inneffectual from t = 0 to nT0, and completely transformed from t = nT0 to 1.
    */
    bool bInterpolate;

    /** time to begin the transformation
    */
    double nT0;

    /** time to finish the transformation
    */
    double nT1;
public:
    /** this is the function that is called to give the Operation to OpenGL.

        @param t
        time from t = 0 to t = 1

        @param SlideWidthScale
        width of slide divided by width of window

        @param SlideHeightScale
        height of slide divided by height of window

    */
    virtual void interpolate(double t,double SlideWidthScale,double SlideHeightScale) = 0;

    /** return a copy of this operation
    */
    virtual Operation* clone() = 0;
};

/** this class is a generic CounterClockWise(CCW) rotation with an axis angle
*/
class SRotate: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    virtual SRotate* clone();

    /** Constructor

        @param Axis
        axis to rotate about

        @param Origin
        position that rotation axis runs through

        @param Angle
        angle in radians of CCW rotation

        @param bInter
        see Operation

        @param T0
        transformation starting time

        @param T1
        transformation ending time

    */
    SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
    ~SRotate(){}
private:
    /** axis to rotate CCW about
    */
    basegfx::B3DVector axis;

    /** position that rotation axis runs through
    */
    basegfx::B3DVector origin;

    /** angle in radians of CCW rotation
    */
    double angle;
};

/** scaling transformation
*/
class SScale: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    SScale* clone();

    /** Constructor

        @param Scale
        amount to scale by

        @param Origin
        position that rotation axis runs through

        @param bInter
        see Operation

        @param T0
        transformation starting time

        @param T1
        transformation ending time

    */
    SScale(const basegfx::B3DVector& Scale, const basegfx::B3DVector& Origin,bool bInter, double T0, double T1);
    ~SScale(){}
private:
    basegfx::B3DVector scale;
    basegfx::B3DVector origin;
};

/** translation transformation
*/
class STranslate: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    STranslate* clone();

    /** Constructor

        @param Vector
        vector to translate

        @param bInter
        see Operation

        @param T0
        transformation starting time

        @param T1
        transformation ending time

    */
    STranslate(const basegfx::B3DVector& Vector,bool bInter, double T0, double T1);
    ~STranslate(){}
private:
    /** vector to translate by
    */
    basegfx::B3DVector vector;
};

/** translation transformation
*/
class SEllipseTranslate: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    SEllipseTranslate* clone();

    /** Constructor

        @param Vector
        vector to translate

        @param bInter
        see Operation

        @param T0
        transformation starting time

        @param T1
        transformation ending time

    */
    SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1);
    ~SEllipseTranslate(){}
private:
    /** width and length of the ellipse
     */
    double width, height;

    /** start and end position on the ellipse <0,1>
     */
    double startPosition;
    double endPosition;
};

/** Same as SRotate, except the depth is scaled by the width of the slide divided by the width of the window.
*/
class RotateAndScaleDepthByWidth: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    RotateAndScaleDepthByWidth* clone();

    RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
    ~RotateAndScaleDepthByWidth(){}
private:
    basegfx::B3DVector axis;
    basegfx::B3DVector origin;
    double angle;
};

#endif // INCLUDED_SLIDESHOW_TRANSITION_HXX_

<commit_msg>INTEGRATION: CWS canvas05 (1.3.10); FILE MERGED 2008/04/21 07:53:38 thb 1.3.10.2: RESYNC: (1.3-1.4); FILE MERGED 2008/04/19 13:43:31 mod 1.3.10.1: initial version of OGL windows port<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: OGLTrans_TransitionImpl.hxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_
#define INCLUDED_OGLTRANS_TRANSITIONIMPL_HXX_

#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/vector/b3dvector.hxx>

#include <tools/prewin.h>
#include <tools/postwin.h>

#if defined( WNT )
#include <tools/prewin.h>
#include <tools/postwin.h>
#elif defined( OS2 )
#elif defined( QUARTZ )
#elif defined( UNX )
#endif

#include <vector>
#include <GL/gl.h>

using namespace std;

class Primitive;
class Operation;
class SceneObject;

/** OpenGL 3D Transition class. It implicitly is constructed from XOGLTransition

    This class is capable of making itself into many difference transitions. It holds Primitives and Operations on those primitives.
*/
class OGLTransitionImpl
{
public:
    OGLTransitionImpl() :
        maLeavingSlidePrimitives(),
        maEnteringSlidePrimitives(),
        maSceneObjects()
    {}

    ~OGLTransitionImpl();

    void prepare();
    void display( double nTime, ::sal_Int32 glLeavingSlideTex, ::sal_Int32 glEnteringSlideTex, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
    void finish();

    void makeOutsideCubeFaceToLeft();
    void makeInsideCubeFaceToLeft();
    void makeNByMTileFlip( ::sal_uInt16 n, ::sal_uInt16 m );
    void makeRevolvingCircles( ::sal_uInt16 nCircles , ::sal_uInt16 nPointsOnCircles );
    void makeHelix( ::sal_uInt16 nRows );
    void makeFallLeaving();
    void makeTurnAround();
    void makeTurnDown();
    void makeIris();
    void makeRochade();

private:
    /** clears all the primitives and operations
    */
    void clear();

    /** All the primitives that use the leaving slide texture
    */
    vector<Primitive> maLeavingSlidePrimitives;

    /** All the primitives that use the leaving slide texture
    */
    vector<Primitive> maEnteringSlidePrimitives;

    /** All the surrounding scene objects
    */
    vector<SceneObject*> maSceneObjects;

    /** All the operations that should be applied to both leaving and entering slide primitives. These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.
    */
    vector<Operation*> OverallOperations;
};

class SceneObject
{
public:
    SceneObject();

    virtual void prepare() {};
    virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
    virtual void finish() {};

    void pushPrimitive (const Primitive &p);

protected:
    /** All the surrounding scene primitives
    */
    vector<Primitive> maPrimitives;
};

class Iris : public SceneObject
{
public:
    Iris ();

    virtual void prepare();
    virtual void display(double nTime, double SlideWidth, double SlideHeight, double DispWidth, double DispHeight);
    virtual void finish();

private:

    GLuint maTexture;
};

/** This class is a list of Triangles that will share Operations, and could possibly share
*/
class Primitive
{
public:
    Primitive() {}
    // making copy constructor explicit makes the class un-suitable for use with stl containers
    Primitive(const Primitive& rvalue);
    ~Primitive();

    void display(double nTime, double SlideWidthScale, double SlideHeightScale);
    const Primitive& operator=(const Primitive& rvalue);

    /** PushBack a vertex,normal, and tex coord. Each SlideLocation is where on the slide is mapped to this location ( from (0,0) to (1,1)  ). This will make sure the correct aspect ratio is used, and helps to make slides begin and end at the correct position. (0,0) is the top left of the slide, and (1,1) is the bottom right.

    @param SlideLocation0
    Location of first Vertex on slide

    @param SlideLocation1
    Location of second Vertex on slide

    @param SlideLocation2
    Location of third Vertex on slide

    */
    void pushTriangle(const basegfx::B2DVector& SlideLocation0,const basegfx::B2DVector& SlideLocation1,const basegfx::B2DVector& SlideLocation2);

    /** clear all the vertices, normals, tex coordinates, and normals
    */
    void clearTriangles();

    /** guards against directly changing the vertices

        @return
        the list of vertices
    */
    const vector<basegfx::B3DVector>& getVertices() const {return Vertices;}

    /** guards against directly changing the vertices
    */
    const vector<basegfx::B3DVector>& getNormals() const {return Normals;}

    /** guards against directly changing the vertices

        @return
        the list of Texture Coordinates

    */
    const vector<basegfx::B2DVector>& getTexCoords() const {return TexCoords;}

    /** list of Operations to be performed on this primitive.These operations will be called in the order they were pushed back in. In OpenGL this effectively uses the operations in the opposite order they were pushed back.

        @return
        the list of Operations

    */
    vector<Operation*> Operations;

private:
    /** list of vertices
    */
    vector<basegfx::B3DVector> Vertices;

    /** list of Normals
    */
    vector<basegfx::B3DVector> Normals;

    /** list of Texture Coordinates
    */
    vector<basegfx::B2DVector> TexCoords;
};

/** This class is to be derived to make any operation (tranform) you may need in order to construct your transitions
*/
class Operation
{
public:
    Operation(){}
    virtual ~Operation(){}

    /** Should this operation be interpolated . If TRUE, the transform will smoothly move from making no difference from t = 0.0 to nT0 to being completely transformed from t = nT1 to 1. If FALSE, the transform will be inneffectual from t = 0 to nT0, and completely transformed from t = nT0 to 1.
    */
    bool bInterpolate;

    /** time to begin the transformation
    */
    double nT0;

    /** time to finish the transformation
    */
    double nT1;
public:
    /** this is the function that is called to give the Operation to OpenGL.

        @param t
        time from t = 0 to t = 1

        @param SlideWidthScale
        width of slide divided by width of window

        @param SlideHeightScale
        height of slide divided by height of window

    */
    virtual void interpolate(double t,double SlideWidthScale,double SlideHeightScale) = 0;

    /** return a copy of this operation
    */
    virtual Operation* clone() = 0;
};

/** this class is a generic CounterClockWise(CCW) rotation with an axis angle
*/
class SRotate: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    virtual SRotate* clone();

    /** Constructor

        @param Axis
        axis to rotate about

        @param Origin
        position that rotation axis runs through

        @param Angle
        angle in radians of CCW rotation

        @param bInter
        see Operation

        @param T0
        transformation starting time

        @param T1
        transformation ending time

    */
    SRotate(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
    ~SRotate(){}
private:
    /** axis to rotate CCW about
    */
    basegfx::B3DVector axis;

    /** position that rotation axis runs through
    */
    basegfx::B3DVector origin;

    /** angle in radians of CCW rotation
    */
    double angle;
};

/** scaling transformation
*/
class SScale: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    SScale* clone();

    /** Constructor

        @param Scale
        amount to scale by

        @param Origin
        position that rotation axis runs through

        @param bInter
        see Operation

        @param T0
        transformation starting time

        @param T1
        transformation ending time

    */
    SScale(const basegfx::B3DVector& Scale, const basegfx::B3DVector& Origin,bool bInter, double T0, double T1);
    ~SScale(){}
private:
    basegfx::B3DVector scale;
    basegfx::B3DVector origin;
};

/** translation transformation
*/
class STranslate: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    STranslate* clone();

    /** Constructor

        @param Vector
        vector to translate

        @param bInter
        see Operation

        @param T0
        transformation starting time

        @param T1
        transformation ending time

    */
    STranslate(const basegfx::B3DVector& Vector,bool bInter, double T0, double T1);
    ~STranslate(){}
private:
    /** vector to translate by
    */
    basegfx::B3DVector vector;
};

/** translation transformation
*/
class SEllipseTranslate: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    SEllipseTranslate* clone();

    /** Constructor

        @param Vector
        vector to translate

        @param bInter
        see Operation

        @param T0
        transformation starting time

        @param T1
        transformation ending time

    */
    SEllipseTranslate(double dWidth, double dHeight, double dStartPosition, double dEndPosition, bool bInter, double T0, double T1);
    ~SEllipseTranslate(){}
private:
    /** width and length of the ellipse
     */
    double width, height;

    /** start and end position on the ellipse <0,1>
     */
    double startPosition;
    double endPosition;
};

/** Same as SRotate, except the depth is scaled by the width of the slide divided by the width of the window.
*/
class RotateAndScaleDepthByWidth: public Operation
{
public:
    void interpolate(double t,double SlideWidthScale,double SlideHeightScale);
    RotateAndScaleDepthByWidth* clone();

    RotateAndScaleDepthByWidth(const basegfx::B3DVector& Axis,const basegfx::B3DVector& Origin,double Angle,bool bInter, double T0, double T1);
    ~RotateAndScaleDepthByWidth(){}
private:
    basegfx::B3DVector axis;
    basegfx::B3DVector origin;
    double angle;
};

#endif // INCLUDED_SLIDESHOW_TRANSITION_HXX_

<|endoftext|>


<commit_before>/*
 * Utilities for reading a HTTP body, either request or response.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_HTTP_BODY_HXX
#define BENG_PROXY_HTTP_BODY_HXX

#include "istream.h"
#include "util/Cast.hxx"

#include <inline/compiler.h>

#include <stddef.h>

struct pool;
struct FilteredSocket;

struct HttpBodyReader {
    /**
     * The remaining size is unknown.
     */
    static constexpr off_t REST_UNKNOWN = -1;

    /**
     * EOF chunk has been seen.
     */
    static constexpr off_t REST_EOF_CHUNK = -2;

    /**
     * Chunked response.  Will flip to #REST_EOF_CHUNK as soon
     * as the EOF chunk is seen.
     */
    static constexpr off_t REST_CHUNKED = -3;

    struct istream output;

    /**
     * The remaining number of bytes.
     *
     * @see #REST_UNKNOWN, #REST_EOF_CHUNK,
     * #REST_CHUNKED
     */
    off_t rest;

#ifndef NDEBUG
    bool chunked, socket_eof;
#endif

    struct istream &Init(const struct istream_class &stream,
                         struct pool &stream_pool,
                         struct pool &pool, off_t content_length,
                         bool chunked);

    struct istream &GetStream() {
        return output;
    }

    static HttpBodyReader &FromStream(struct istream &stream) {
        return ContainerCast2(stream, &HttpBodyReader::output);
    }

    void Deinit();
    void DeinitEOF();
    void DeinitAbort(GError *error);

    bool IsChunked() const {
        return rest == REST_CHUNKED;
    }

    /**
     * Do we know the remaining length of the body?
     */
    bool KnownLength() const {
        return rest >= 0;
    }

    bool IsEOF() const {
        return rest == 0 || rest == REST_EOF_CHUNK;
    }

    /**
     * Do we require more data to finish the body?
     */
    bool RequireMore() const {
        return rest > 0 || rest == REST_CHUNKED;
    }

    gcc_pure
    off_t GetAvailable(const FilteredSocket &s, bool partial) const;

    size_t FeedBody(const void *data, size_t length);

    gcc_pure
    bool CheckDirect(enum istream_direct fd_type) const;

    ssize_t TryDirect(int fd, enum istream_direct fd_type);

    /**
     * Determines whether the socket can be released now.  This is true if
     * the body is empty, or if the data in the buffer contains enough for
     * the full response.
     */
    gcc_pure
    bool IsSocketDone(const FilteredSocket &s) const;

    /**
     * The underlying socket has been closed by the remote.
     *
     * @return true if there is data left in the buffer, false if the body
     * has been finished (with or without error)
     */
    bool SocketEOF(size_t remaining);

private:
    gcc_pure
    size_t GetMaxRead(size_t length) const;

    void Consumed(size_t nbytes);

    void DechunkerEOF();
    static void DechunkerEOF(void *ctx);
};

#endif
<commit_msg>http_body: convert to class, make attributes private<commit_after>/*
 * Utilities for reading a HTTP body, either request or response.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef BENG_PROXY_HTTP_BODY_HXX
#define BENG_PROXY_HTTP_BODY_HXX

#include "istream.h"
#include "util/Cast.hxx"

#include <inline/compiler.h>

#include <stddef.h>

struct pool;
struct FilteredSocket;

class HttpBodyReader {
    /**
     * The remaining size is unknown.
     */
    static constexpr off_t REST_UNKNOWN = -1;

    /**
     * EOF chunk has been seen.
     */
    static constexpr off_t REST_EOF_CHUNK = -2;

    /**
     * Chunked response.  Will flip to #REST_EOF_CHUNK as soon
     * as the EOF chunk is seen.
     */
    static constexpr off_t REST_CHUNKED = -3;

    struct istream output;

    /**
     * The remaining number of bytes.
     *
     * @see #REST_UNKNOWN, #REST_EOF_CHUNK,
     * #REST_CHUNKED
     */
    off_t rest;

#ifndef NDEBUG
    bool chunked, socket_eof;
#endif

public:
    struct istream &Init(const struct istream_class &stream,
                         struct pool &stream_pool,
                         struct pool &pool, off_t content_length,
                         bool chunked);

    struct istream &GetStream() {
        return output;
    }

    static HttpBodyReader &FromStream(struct istream &stream) {
        return ContainerCast2(stream, &HttpBodyReader::output);
    }

    void Deinit();
    void DeinitEOF();
    void DeinitAbort(GError *error);

    bool IsChunked() const {
        return rest == REST_CHUNKED;
    }

    /**
     * Do we know the remaining length of the body?
     */
    bool KnownLength() const {
        return rest >= 0;
    }

    bool IsEOF() const {
        return rest == 0 || rest == REST_EOF_CHUNK;
    }

    /**
     * Do we require more data to finish the body?
     */
    bool RequireMore() const {
        return rest > 0 || rest == REST_CHUNKED;
    }

    gcc_pure
    off_t GetAvailable(const FilteredSocket &s, bool partial) const;

    size_t FeedBody(const void *data, size_t length);

    gcc_pure
    bool CheckDirect(enum istream_direct fd_type) const;

    ssize_t TryDirect(int fd, enum istream_direct fd_type);

    /**
     * Determines whether the socket can be released now.  This is true if
     * the body is empty, or if the data in the buffer contains enough for
     * the full response.
     */
    gcc_pure
    bool IsSocketDone(const FilteredSocket &s) const;

    /**
     * The underlying socket has been closed by the remote.
     *
     * @return true if there is data left in the buffer, false if the body
     * has been finished (with or without error)
     */
    bool SocketEOF(size_t remaining);

private:
    gcc_pure
    size_t GetMaxRead(size_t length) const;

    void Consumed(size_t nbytes);

    void DechunkerEOF();
    static void DechunkerEOF(void *ctx);
};

#endif
<|endoftext|>


<commit_before>extern "C" {
#include "cInCLexer.h"
#include "cInCParser.h"
}
#include<list>
#include<string>
using namespace std;
char testip[] = "float x;\nstatic int z;\nchar text[64] = \"hello\"; int bob(char x, char *harry) { stuff  { inside } }";

class Decl
{
public:
  char *identifier;
  bool typeStatic, typeExtern, typeTypedef, typeAuto, typeRegister;
  int  primType;    // -1 for things that are not
  Decl() :
    primType(-1)
  {
  }
  string typeStr()
  {
    return "hello";
  }
};

class Func
{
public:
  char *identifier;
};

class TranslationU
{
public:
  list<Decl*> globals;
  list<Func*> functions;
  TranslationU(pANTLR3_BASE_TREE root);
  void processTopLevel(pANTLR3_BASE_TREE node);
  void dump();
};

TranslationU::TranslationU(pANTLR3_BASE_TREE root)
{
  if( root->getType(root)==0 )
  {
    int count = root->getChildCount(root);
    for(int i=0; i<count; i++)
      processTopLevel((pANTLR3_BASE_TREE)root->getChild(root,i));
  }
  else
    processTopLevel(root);
}

void TranslationU::processTopLevel(pANTLR3_BASE_TREE node)
{
int type  = node->getType(node);
int count = node->getChildCount(node);
  switch(type)
  {
    case DECL:
      {
        Decl *d = new Decl;
        pANTLR3_BASE_TREE id = (pANTLR3_BASE_TREE)node->getChild(node,0);
        d->identifier = (char*)id->getText(id)->chars;
        for(int i=1; i<count; i++)
        {
          pANTLR3_BASE_TREE tok = (pANTLR3_BASE_TREE)node->getChild(node,i);
          switch(tok->getType(tok))
          {
            case FLOAT:
            case CHAR:
            case INT:
            case LONG:
              d->primType = tok->getType(tok);
              break;
            case AUTO:
              d->typeAuto = true;
              break;
            case TYPEDEF:
              d->typeTypedef = true;
              break;
            case EXTERN:
              d->typeExtern = true;
              break;
            case STATIC:
              d->typeStatic = true;
              break;
            default:
              printf("-->%s %d\n", (char*)tok->getText(tok)->chars, tok->getType(tok));
              break;
          }
        }
        globals.push_back(d);
      }
    case FUNC:
      break;
    default:
      printf("Unknown Type %u Children %u ", type, count);
      if(node->getText(node)!=NULL)
        printf("%s\n", node->getText(node)->chars);
      else
        printf("empty\n");
      break;
  }
}

// C++11 is scary and both "differently" supported and "differently" able.
// Also upgrading g++ on the knackered old version of Ubuntu that I use can wait until another day.
#define foreach(T,V,C) for(T::iterator V = C.begin(); V!=C.end(); ++V)
// This is definitely a bit messy... but it works :)
#define tmplForeach(Tmpl,ElemT,V,C) { Tmpl<ElemT>::iterator V##It; ElemT V; for(V##It = C.begin(),V=*V##It; V##It!=C.end(); ++V##It,V=*V##It)
#define tmplEnd }

void TranslationU::dump()
{
  tmplForeach(list,Decl*,decl,globals)
    printf("Declation: %s <- %s\n", decl->identifier, decl->typeStr().c_str());
  tmplEnd
  tmplForeach(list,Func*,f,functions)
    printf("Function: %s <- %s\n", f->identifier, "type");
  tmplEnd
}

int main(int argc, char **argv)
{
pANTLR3_INPUT_STREAM ip;
pANTLR3_COMMON_TOKEN_STREAM tokens;
pcInCLexer lex;
pcInCParser parser;
cInCParser_translationUnit_return retVal;

  ip = antlr3NewAsciiStringInPlaceStream((uint8_t*)testip, strlen(testip), NULL);
  lex = cInCLexerNew(ip);
  tokens = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lex));
  parser = cInCParserNew(tokens);
  retVal = parser->translationUnit(parser);

TranslationU model = TranslationU(retVal.tree);
  model.dump();

}
<commit_msg>Parsing contents of decl node.<commit_after>extern "C" {
#include "cInCLexer.h"
#include "cInCParser.h"
}
#include<list>
#include<string>
#include<sstream>
using namespace std;
char testip[] = "float x;\nstatic int z;\nchar text[64] = \"hello\"; int bob(char x, char *harry) { stuff  { inside } }";

// Implements the python str.join function on lists of strings. Awkward to inline without
// a helper function because the first iteration doesn't start with a separator so it needs
// to be lifted from the loop.
string joinStrings(list<string> &strs, char separator)
{
stringstream res;
list<string>::iterator it = strs.begin();
  if(it!=strs.end())
  {
    res << *it;
    ++it;
  }
  while(it!=strs.end())
  {
    res << separator << *it;
    ++it;
  }
  return res.str();
}

class Decl
{
public:
  char *identifier;
  bool typeStatic, typeExtern, typeTypedef, typeAuto, typeRegister;
  int  primType;    // -1 for things that are not
  int stars;
  int array;
  Decl() :
    primType(-1), stars(0), array(0)
  {
  }
  string typeStr()
  {
    list<string> prefix;
    if(typeStatic)
      prefix.push_back("static");
    if(typeExtern)
      prefix.push_back("extern");
    if(typeTypedef)
      prefix.push_back("typedef");
    if(typeAuto)
      prefix.push_back("auto");
    if(typeRegister)
      prefix.push_back("register");
    switch(primType)
    {
      case CHAR:
        prefix.push_back("char");
        break;
      case FLOAT:
        prefix.push_back("float");
        break;
      case INT:
        prefix.push_back("int");
        break;
      case LONG:
        prefix.push_back("long");
        break;
    }
    stringstream res;
    res << joinStrings(prefix,' ');
    if(array>0)
      res << '[' << array << ']';
    return res.str();
  }
};

class Func
{
public:
  char *identifier;
};

class TranslationU
{
public:
  list<Decl*> globals;
  list<Func*> functions;
  TranslationU(pANTLR3_BASE_TREE root);
  void processTopLevel(pANTLR3_BASE_TREE node);
  void dump();
};

TranslationU::TranslationU(pANTLR3_BASE_TREE root)
{
  if( root->getType(root)==0 )
  {
    int count = root->getChildCount(root);
    for(int i=0; i<count; i++)
      processTopLevel((pANTLR3_BASE_TREE)root->getChild(root,i));
  }
  else
    processTopLevel(root);
}

void TranslationU::processTopLevel(pANTLR3_BASE_TREE node)
{
int type  = node->getType(node);
int count = node->getChildCount(node);
  switch(type)
  {
    case DECL:
      {
        Decl *d = new Decl;
        pANTLR3_BASE_TREE id = (pANTLR3_BASE_TREE)node->getChild(node,0);
        d->identifier = (char*)id->getText(id)->chars;
        for(int i=1; i<count; i++)
        {
          pANTLR3_BASE_TREE tok = (pANTLR3_BASE_TREE)node->getChild(node,i);
          switch(tok->getType(tok))
          {
            case FLOAT:
            case CHAR:
            case INT:
            case LONG:
              d->primType = tok->getType(tok);
              break;
            case AUTO:
              d->typeAuto = true;
              break;
            case TYPEDEF:
              d->typeTypedef = true;
              break;
            case EXTERN:
              d->typeExtern = true;
              break;
            case STATIC:
              d->typeStatic = true;
              break;
            case OPENSQ:
              if(i+3 >= count)
                printf("ERROR: truncated array expression\n");
              else
              {
                pANTLR3_BASE_TREE cexp = (pANTLR3_BASE_TREE)node->getChild(node,i+1);
                if(cexp->getType(cexp)!=NUM)
                  printf("ERROR: array bound is unevaluated\n");
                else
                  d->array = atoi((char*)cexp->getText(cexp)->chars);
                i += 2;   // Skip NUM CLOSESQ
              }
              break;
            default:
              printf("-->%s %d\n", (char*)tok->getText(tok)->chars, tok->getType(tok));
              break;
          }
        }
        globals.push_back(d);
      }
    case FUNC:
      break;
    default:
      printf("Unknown Type %u Children %u ", type, count);
      if(node->getText(node)!=NULL)
        printf("%s\n", node->getText(node)->chars);
      else
        printf("empty\n");
      break;
  }
}

// C++11 is scary and both "differently" supported and "differently" able.
// Also upgrading g++ on the knackered old version of Ubuntu that I use can wait until another day.
#define foreach(T,V,C) for(T::iterator V = C.begin(); V!=C.end(); ++V)
// This is definitely a bit messy... but it works :)
#define tmplForeach(Tmpl,ElemT,V,C) { Tmpl<ElemT>::iterator V##It; ElemT V; for(V##It = C.begin(),V=*V##It; V##It!=C.end(); ++V##It,V=*V##It)
#define tmplEnd }

void TranslationU::dump()
{
  tmplForeach(list,Decl*,decl,globals)
    printf("Declation: %s <- %s\n", decl->identifier, decl->typeStr().c_str());
  tmplEnd
  tmplForeach(list,Func*,f,functions)
    printf("Function: %s <- %s\n", f->identifier, "type");
  tmplEnd
}

int main(int argc, char **argv)
{
pANTLR3_INPUT_STREAM ip;
pANTLR3_COMMON_TOKEN_STREAM tokens;
pcInCLexer lex;
pcInCParser parser;
cInCParser_translationUnit_return retVal;

  ip = antlr3NewAsciiStringInPlaceStream((uint8_t*)testip, strlen(testip), NULL);
  lex = cInCLexerNew(ip);
  tokens = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lex));
  parser = cInCParserNew(tokens);
  retVal = parser->translationUnit(parser);

TranslationU model = TranslationU(retVal.tree);
  model.dump();

}
<|endoftext|>