<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/audio_renderer_algorithm_base.h"

#include "base/logging.h"
#include "media/base/buffers.h"

namespace media {

// The size in bytes we try to maintain for the |queue_|. Previous usage
// maintained a deque of 16 Buffers, each of size 4Kb. This worked well, so we
// maintain this number of bytes (16 * 4096).
const uint32 kDefaultMinQueueSizeInBytes = 65536;

AudioRendererAlgorithmBase::AudioRendererAlgorithmBase()
    : channels_(0),
      sample_rate_(0),
      sample_bytes_(0),
      playback_rate_(0.0f),
      queue_(0, kDefaultMinQueueSizeInBytes) {
}

AudioRendererAlgorithmBase::~AudioRendererAlgorithmBase() {}

void AudioRendererAlgorithmBase::Initialize(int channels,
                                            int sample_rate,
                                            int sample_bits,
                                            float initial_playback_rate,
                                            RequestReadCallback* callback) {
  DCHECK_GT(channels, 0);
  DCHECK_LE(channels, 6) << "We only support <=6 channel audio.";
  DCHECK_GT(sample_rate, 0);
  DCHECK_LE(sample_rate, 256000)
      << "We only support sample rates at or below 256000Hz.";
  DCHECK_GT(sample_bits, 0);
  DCHECK_LE(sample_bits, 32) << "We only support 8, 16, 32 bit audio.";
  DCHECK_EQ(sample_bits % 8, 0) << "We only support 8, 16, 32 bit audio.";
  DCHECK(callback);

  channels_ = channels;
  sample_rate_ = sample_rate;
  sample_bytes_ = sample_bits / 8;
  request_read_callback_.reset(callback);

  set_playback_rate(initial_playback_rate);
}

void AudioRendererAlgorithmBase::FlushBuffers() {
  // Clear the queue of decoded packets (releasing the buffers).
  queue_.Clear();
  request_read_callback_->Run();
}

base::TimeDelta AudioRendererAlgorithmBase::GetTime() {
  return queue_.current_time();
}

void AudioRendererAlgorithmBase::EnqueueBuffer(Buffer* buffer_in) {
  // If we're at end of stream, |buffer_in| contains no data.
  if (!buffer_in->IsEndOfStream())
    queue_.Append(buffer_in);

  // If we still don't have enough data, request more.
  if (!IsQueueFull())
    request_read_callback_->Run();
}

float AudioRendererAlgorithmBase::playback_rate() {
  return playback_rate_;
}

void AudioRendererAlgorithmBase::set_playback_rate(float new_rate) {
  DCHECK_GE(new_rate, 0.0);
  playback_rate_ = new_rate;
}

bool AudioRendererAlgorithmBase::IsQueueEmpty() {
  return queue_.forward_bytes() == 0;
}

bool AudioRendererAlgorithmBase::IsQueueFull() {
  return (queue_.forward_bytes() >= kDefaultMinQueueSizeInBytes);
}

uint32 AudioRendererAlgorithmBase::QueueSize() {
  return queue_.forward_bytes();
}

void AudioRendererAlgorithmBase::AdvanceInputPosition(uint32 bytes) {
  queue_.Seek(bytes);

  if (!IsQueueFull())
    request_read_callback_->Run();
}

uint32 AudioRendererAlgorithmBase::CopyFromInput(uint8* dest, uint32 bytes) {
  return queue_.Peek(dest, bytes);
}

int AudioRendererAlgorithmBase::channels() {
  return channels_;
}

int AudioRendererAlgorithmBase::sample_rate() {
  return sample_rate_;
}

int AudioRendererAlgorithmBase::sample_bytes() {
  return sample_bytes_;
}

}  // namespace media
<commit_msg>audio ola resampler accept 8 channel source BUG=59832 TEST=player_wtl _xvid_pcm_7.1_640x480_183sec_m1599.wav<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "media/filters/audio_renderer_algorithm_base.h"

#include "base/logging.h"
#include "media/base/buffers.h"

namespace media {

// The size in bytes we try to maintain for the |queue_|. Previous usage
// maintained a deque of 16 Buffers, each of size 4Kb. This worked well, so we
// maintain this number of bytes (16 * 4096).
const uint32 kDefaultMinQueueSizeInBytes = 65536;

AudioRendererAlgorithmBase::AudioRendererAlgorithmBase()
    : channels_(0),
      sample_rate_(0),
      sample_bytes_(0),
      playback_rate_(0.0f),
      queue_(0, kDefaultMinQueueSizeInBytes) {
}

AudioRendererAlgorithmBase::~AudioRendererAlgorithmBase() {}

void AudioRendererAlgorithmBase::Initialize(int channels,
                                            int sample_rate,
                                            int sample_bits,
                                            float initial_playback_rate,
                                            RequestReadCallback* callback) {
  DCHECK_GT(channels, 0);
  DCHECK_LE(channels, 8) << "We only support <= 8 channel audio.";
  DCHECK_GT(sample_rate, 0);
  DCHECK_LE(sample_rate, 256000)
      << "We only support sample rates at or below 256000Hz.";
  DCHECK_GT(sample_bits, 0);
  DCHECK_LE(sample_bits, 32) << "We only support 8, 16, 32 bit audio.";
  DCHECK_EQ(sample_bits % 8, 0) << "We only support 8, 16, 32 bit audio.";
  DCHECK(callback);

  channels_ = channels;
  sample_rate_ = sample_rate;
  sample_bytes_ = sample_bits / 8;
  request_read_callback_.reset(callback);

  set_playback_rate(initial_playback_rate);
}

void AudioRendererAlgorithmBase::FlushBuffers() {
  // Clear the queue of decoded packets (releasing the buffers).
  queue_.Clear();
  request_read_callback_->Run();
}

base::TimeDelta AudioRendererAlgorithmBase::GetTime() {
  return queue_.current_time();
}

void AudioRendererAlgorithmBase::EnqueueBuffer(Buffer* buffer_in) {
  // If we're at end of stream, |buffer_in| contains no data.
  if (!buffer_in->IsEndOfStream())
    queue_.Append(buffer_in);

  // If we still don't have enough data, request more.
  if (!IsQueueFull())
    request_read_callback_->Run();
}

float AudioRendererAlgorithmBase::playback_rate() {
  return playback_rate_;
}

void AudioRendererAlgorithmBase::set_playback_rate(float new_rate) {
  DCHECK_GE(new_rate, 0.0);
  playback_rate_ = new_rate;
}

bool AudioRendererAlgorithmBase::IsQueueEmpty() {
  return queue_.forward_bytes() == 0;
}

bool AudioRendererAlgorithmBase::IsQueueFull() {
  return (queue_.forward_bytes() >= kDefaultMinQueueSizeInBytes);
}

uint32 AudioRendererAlgorithmBase::QueueSize() {
  return queue_.forward_bytes();
}

void AudioRendererAlgorithmBase::AdvanceInputPosition(uint32 bytes) {
  queue_.Seek(bytes);

  if (!IsQueueFull())
    request_read_callback_->Run();
}

uint32 AudioRendererAlgorithmBase::CopyFromInput(uint8* dest, uint32 bytes) {
  return queue_.Peek(dest, bytes);
}

int AudioRendererAlgorithmBase::channels() {
  return channels_;
}

int AudioRendererAlgorithmBase::sample_rate() {
  return sample_rate_;
}

int AudioRendererAlgorithmBase::sample_bytes() {
  return sample_bytes_;
}

}  // namespace media
<|endoftext|>


<commit_before>/**
 * @file windows_volume_catcher.cpp
 * @brief A Windows implementation of volume level control of all audio channels opened by a process.
 *
 * @cond
 * $LicenseInfo:firstyear=2010&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 * @endcond
 */

#include "volume_catcher.h"
#include <windows.h>
#include "llsingleton.h"
class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl>
{
friend LLSingleton<VolumeCatcherImpl>;
public:

	void setVolume(F32 volume);
	void setPan(F32 pan);

private:
	// This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
	VolumeCatcherImpl();
	~VolumeCatcherImpl();

	typedef void (WINAPI *set_volume_func_t)(F32);
	typedef void (WINAPI *set_mute_func_t)(bool);

	set_volume_func_t mSetVolumeFunc;
	set_mute_func_t mSetMuteFunc;

	// tests if running on Vista, 7, 8 + once in CTOR
	bool isWindowsVistaOrHigher();

	F32 	mVolume;
	F32 	mPan;
	bool mSystemIsVistaOrHigher;
};

bool VolumeCatcherImpl::isWindowsVistaOrHigher()
{
	OSVERSIONINFO osvi;
	ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osvi);
	return osvi.dwMajorVersion >= 6;
}

VolumeCatcherImpl::VolumeCatcherImpl()
:	mVolume(1.0f),			// default volume is max
	mPan(0.f)				// default pan is centered
{
	mSystemIsVistaOrHigher = isWindowsVistaOrHigher();

	if ( mSystemIsVistaOrHigher )
	{
		HMODULE handle = ::LoadLibrary(L"winmm.dll");
		if(handle)
		{
			mSetVolumeFunc = (set_volume_func_t)::GetProcAddress(handle, "setPluginVolume");
			mSetMuteFunc = (set_mute_func_t)::GetProcAddress(handle, "setPluginMute");
		}
	}
}

VolumeCatcherImpl::~VolumeCatcherImpl()
{
}

void VolumeCatcherImpl::setVolume(F32 volume)
{
	mVolume = volume;

	if ( ! mSystemIsVistaOrHigher )
	{
		// set both left/right to same volume
		// TODO: use pan value to set independently
		DWORD left_channel  = (DWORD)(mVolume * 65535.0f);
		DWORD right_channel =  (DWORD)(mVolume * 65535.0f);
		DWORD hw_volume = left_channel << 16 | right_channel;
		::waveOutSetVolume(NULL, hw_volume);
	}
	else
	{
		if (mSetMuteFunc)
		{
			mSetMuteFunc(volume == 0.f);
		}
		if (mSetVolumeFunc)
		{
			mSetVolumeFunc(mVolume);
		}
	}
}

void VolumeCatcherImpl::setPan(F32 pan)
{	// remember pan for calculating individual channel levels later
	mPan = pan;
}

/////////////////////////////////////////////////////

VolumeCatcher::VolumeCatcher()
{
	pimpl = VolumeCatcherImpl::getInstance();
}

VolumeCatcher::~VolumeCatcher()
{
	// Let the instance persist until exit.
}

void VolumeCatcher::setVolume(F32 volume)
{
	pimpl->setVolume(volume);
}

void VolumeCatcher::setPan(F32 pan)
{
	pimpl->setPan(pan);
}

void VolumeCatcher::pump()
{
	// No periodic tasks are necessary for this implementation.
}

<commit_msg>MAINT-2281: correct test for XP (corrected fix I applied incorrectly)<commit_after>/**
 * @file windows_volume_catcher.cpp
 * @brief A Windows implementation of volume level control of all audio channels opened by a process.
 *
 * @cond
 * $LicenseInfo:firstyear=2010&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 * @endcond
 */

#include "volume_catcher.h"
#include <windows.h>
#include "llsingleton.h"
class VolumeCatcherImpl : public LLSingleton<VolumeCatcherImpl>
{
friend LLSingleton<VolumeCatcherImpl>;
public:

	void setVolume(F32 volume);
	void setPan(F32 pan);

private:
	// This is a singleton class -- both callers and the component implementation should use getInstance() to find the instance.
	VolumeCatcherImpl();
	~VolumeCatcherImpl();

	typedef void (WINAPI *set_volume_func_t)(F32);
	typedef void (WINAPI *set_mute_func_t)(bool);

	set_volume_func_t mSetVolumeFunc;
	set_mute_func_t mSetMuteFunc;

	// tests if running on Vista, 7, 8 + once in CTOR
	bool isWindowsVistaOrHigher();

	F32 	mVolume;
	F32 	mPan;
	bool mSystemIsVistaOrHigher;
};

bool VolumeCatcherImpl::isWindowsVistaOrHigher()
{
	OSVERSIONINFO osvi;
	ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osvi);
	return osvi.dwMajorVersion >= 6;
}

VolumeCatcherImpl::VolumeCatcherImpl()
:	mVolume(1.0f),			// default volume is max
	mPan(0.f)				// default pan is centered
{
	mSystemIsVistaOrHigher = isWindowsVistaOrHigher();

	if ( ! mSystemIsVistaOrHigher )
	{
		HMODULE handle = ::LoadLibrary(L"winmm.dll");
		if(handle)
		{
			mSetVolumeFunc = (set_volume_func_t)::GetProcAddress(handle, "setPluginVolume");
			mSetMuteFunc = (set_mute_func_t)::GetProcAddress(handle, "setPluginMute");
		}
	}
}

VolumeCatcherImpl::~VolumeCatcherImpl()
{
}

void VolumeCatcherImpl::setVolume(F32 volume)
{
	mVolume = volume;

	if ( mSystemIsVistaOrHigher )
	{
		// set both left/right to same volume
		// TODO: use pan value to set independently
		DWORD left_channel  = (DWORD)(mVolume * 65535.0f);
		DWORD right_channel =  (DWORD)(mVolume * 65535.0f);
		DWORD hw_volume = left_channel << 16 | right_channel;
		::waveOutSetVolume(NULL, hw_volume);
	}
	else
	{
		if (mSetMuteFunc)
		{
			mSetMuteFunc(volume == 0.f);
		}
		if (mSetVolumeFunc)
		{
			mSetVolumeFunc(mVolume);
		}
	}
}

void VolumeCatcherImpl::setPan(F32 pan)
{	// remember pan for calculating individual channel levels later
	mPan = pan;
}

/////////////////////////////////////////////////////

VolumeCatcher::VolumeCatcher()
{
	pimpl = VolumeCatcherImpl::getInstance();
}

VolumeCatcher::~VolumeCatcher()
{
	// Let the instance persist until exit.
}

void VolumeCatcher::setVolume(F32 volume)
{
	pimpl->setVolume(volume);
}

void VolumeCatcher::setPan(F32 pan)
{
	pimpl->setPan(pan);
}

void VolumeCatcher::pump()
{
	// No periodic tasks are necessary for this implementation.
}

<|endoftext|>


<commit_before>#ifndef NETWORKING_H
#define NETWORKING_H

#include <iostream>
#include <set>

#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#else
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <unistd.h>
#endif

#include "../core/hlt.hpp"

extern bool quiet_output;

class Networking {
public:
	void startAndConnectBot(std::string command);
	void handleInitNetworking(unsigned char playerTag, const hlt::Map & m, int * playerMillis, std::string * playerName);
	void handleFrameNetworking(unsigned char playerTag, const hlt::Map & m, int * playermillis, std::set<hlt::Move> * moves);
	void killPlayer(unsigned char playerTag);
	bool isProcessDead(unsigned char playerTag);
	int numberOfPlayers();

	std::vector< std::vector<std::string> > player_logs;

private:
	#ifdef _WIN32
	struct WinConnection {
		HANDLE write, read;
	};
	std::vector<WinConnection> connections;
	std::vector<HANDLE> processes;
	#else
	struct UniConnection {
		int read, write;
	};
	std::vector< UniConnection > connections;
	std::vector<int> processes;
	#endif

	std::string serializeMap(const hlt::Map & map);
	std::set<hlt::Move> deserializeMoveSet(std::string & inputString, const hlt::Map & m);

	void sendString(unsigned char playerTag, std::string &sendString);
	std::string getString(unsigned char playerTag, unsigned int timoutMillis);
};

#endif
<commit_msg>Fixed preproc indentation<commit_after>#ifndef NETWORKING_H
#define NETWORKING_H

#include <iostream>
#include <set>

#ifdef _WIN32
	#include <windows.h>
	#include <tchar.h>
	#include <stdio.h>
	#include <strsafe.h>
#else
	#include <signal.h>
	#include <time.h>
	#include <sys/types.h>
	#include <sys/stat.h>
	#include <fcntl.h>
	#include <sys/select.h>
	#include <unistd.h>
#endif

#include "../core/hlt.hpp"

extern bool quiet_output;

class Networking {
public:
	void startAndConnectBot(std::string command);
	void handleInitNetworking(unsigned char playerTag, const hlt::Map & m, int * playerMillis, std::string * playerName);
	void handleFrameNetworking(unsigned char playerTag, const hlt::Map & m, int * playermillis, std::set<hlt::Move> * moves);
	void killPlayer(unsigned char playerTag);
	bool isProcessDead(unsigned char playerTag);
	int numberOfPlayers();

	std::vector<std::string> player_logs;

private:
#ifdef _WIN32
	struct WinConnection {
		HANDLE write, read;
	};
	std::vector<WinConnection> connections;
	std::vector<HANDLE> processes;
#else
	struct UniConnection {
		int read, write;
	};
	std::vector< UniConnection > connections;
	std::vector<int> processes;
#endif

	std::string serializeMap(const hlt::Map & map);
	std::set<hlt::Move> deserializeMoveSet(std::string & inputString, const hlt::Map & m);

	void sendString(unsigned char playerTag, std::string &sendString);
	std::string getString(unsigned char playerTag, unsigned int timoutMillis);
};

#endif
<|endoftext|>


<commit_before>/*
 * Option.cpp
 *
 *  Created on: 04/05/2011
 *        User: diego
 *      Author: Diego Lago <diego.lago.gonzalez@gmail.com>
 */

#include "../include/cli++/Option.hpp"
#include "../include/cli++/OptionDefinition.hpp"
#include "../include/cli++/Exceptions.hpp"
#include "../include/cli++/Utils.hpp"

namespace clipp {

static const size_t		MaxParameterCount	= 65536;

Option::Option(const string name, const string value)
	: fId(0),
	  fName(name),
	  fOccurrences(1),
	  fValues(MaxParameterCount),
	  fOptdef(NULL)
{
	if(fName.empty()) {
		throw length_error("Option: Option name cannot be empty.");
	}
	if(!value.empty()) {
		fValues.push_back(value);
	}
}

Option::~Option() {
}

int
Option::id() const {
	return fId;
}

const string
Option::name() const {
	return fName;
}

const OptionDefinition*
Option::optionDefinition() const {
	return fOptdef;
}

void
Option::incOccurrenceCount() {
	fOccurrences++;
}

int
Option::occurrences() const {
	return fOccurrences;
}

void
Option::add(const string value) {
	if(!value.empty()) {
		fValues.push_back(value);
	}
}

void
Option::set(const string value, int index) {
	if(!value.empty()) {
		if(index >= 0 && index < (int)fValues.size()) {
			fValues[index] = value;
		} else {
			throw clipp::error::OutOfBounds("Cannot set value " + value + " at index " + StringFrom<int>(index) + " from option '" + fName + "'.", fName);
		}
	}
}

const string
Option::getAt(unsigned short index) const {
	if(index < (int)fValues.size()) {
		return fValues[index];
	} else {
		throw clipp::error::OutOfBounds("Cannot get value at index " + StringFrom<unsigned short>(index) + " from option '" + fName + "'.", fName);
	}
}

const string
Option::get() const {
	return getAt(0);
}

int
Option::countValues() const {
	return fValues.size();
}

void
Option::checkArguments() {
	if(fOptdef == NULL) {
		throw clipp::error::OptionDefinition("FATAL: OptionDefinition pointer from Option (_optdef) is NULL. Contact developer.");
	}
	for(Strings::const_iterator it = fValues.begin(); it != fValues.end(); ++it) {
		fOptdef->checkArgumentType(*it);
		fOptdef->checkArgumentValue(*it);
	}
}

}	// namespace clipp
<commit_msg>Implemented isNegated in the Option.<commit_after>/*
 * Option.cpp
 *
 *  Created on: 04/05/2011
 *        User: diego
 *      Author: Diego Lago <diego.lago.gonzalez@gmail.com>
 */

#include "../include/cli++/Option.hpp"
#include "../include/cli++/OptionDefinition.hpp"
#include "../include/cli++/Exceptions.hpp"
#include "../include/cli++/Utils.hpp"

namespace clipp {

static const size_t		MaxParameterCount	= 65536;

Option::Option(const string name, const string value)
	: fId(0),
	  fName(name),
	  fOccurrences(1),
	  fValues(MaxParameterCount),
	  fOptdef(NULL)
{
	if(fName.empty()) {
		throw length_error("Option: Option name cannot be empty.");
	}
	if(!value.empty()) {
		fValues.push_back(value);
	}
}

Option::~Option() {
}

int
Option::id() const {
	return fId;
}

const string
Option::name() const {
	return fName;
}

bool
Option::isNegated() const {
	return fIsNegated;
}

const OptionDefinition*
Option::optionDefinition() const {
	return fOptdef;
}

void
Option::incOccurrenceCount() {
	fOccurrences++;
}

int
Option::occurrences() const {
	return fOccurrences;
}

void
Option::add(const string value) {
	if(!value.empty()) {
		fValues.push_back(value);
	}
}

void
Option::set(const string value, int index) {
	if(!value.empty()) {
		if(index >= 0 && index < (int)fValues.size()) {
			fValues[index] = value;
		} else {
			throw clipp::error::OutOfBounds("Cannot set value " + value + " at index " + StringFrom<int>(index) + " from option '" + fName + "'.", fName);
		}
	}
}

const string
Option::getAt(unsigned short index) const {
	if(index < (int)fValues.size()) {
		return fValues[index];
	} else {
		throw clipp::error::OutOfBounds("Cannot get value at index " + StringFrom<unsigned short>(index) + " from option '" + fName + "'.", fName);
	}
}

const string
Option::get() const {
	return getAt(0);
}

int
Option::countValues() const {
	return fValues.size();
}

void
Option::checkArguments() {
	if(fOptdef == NULL) {
		throw clipp::error::OptionDefinition("FATAL: OptionDefinition pointer from Option (_optdef) is NULL. Contact developer.");
	}
	for(Strings::const_iterator it = fValues.begin(); it != fValues.end(); ++it) {
		fOptdef->checkArgumentType(*it);
		fOptdef->checkArgumentValue(*it);
	}
}

}	// namespace clipp
<|endoftext|>


<commit_before>/*
  Copyright Kitware, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "Output.h"
#include "Utils.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"

#include <fstream>
#include <iostream>
#include <queue>

//----------------------------------------------------------------------------
class ASTVisitorBase
{
protected:
  clang::CompilerInstance& CI;
  clang::ASTContext const& CTX;
  llvm::raw_ostream& OS;

  ASTVisitorBase(clang::CompilerInstance& ci,
                 clang::ASTContext const& ctx,
                 llvm::raw_ostream& os): CI(ci), CTX(ctx), OS(os) {}

  // Record status of one AST node to be dumped.
  struct DumpNode {
    DumpNode(): Index(0), Complete(false) {}

    // Index in nodes ordered by first encounter.
    unsigned int Index;

    // Whether the node is to be traversed completely.
    bool Complete;
  };

  // Report all decl nodes as unimplemented until overridden.
#define ABSTRACT_DECL(DECL)
#define DECL(CLASS, BASE) \
  void Output##CLASS##Decl(clang::CLASS##Decl const* d, DumpNode const* dn) { \
    this->OutputUnimplementedDecl(d, dn); \
  }
#include "clang/AST/DeclNodes.inc"

  void OutputUnimplementedDecl(clang::Decl const* d, DumpNode const* dn) {
    this->OS << "  <Unimplemented id=\"_" << dn->Index
             << "\" kind=\"" << encodeXML(d->getDeclKindName()) << "\"/>\n";
  }

  // Report all type nodes as unimplemented until overridden.
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) \
  void Output##CLASS##Type(clang::CLASS##Type const* t, DumpNode const* dn) { \
    this->OutputUnimplementedType(t, dn); \
    }
#include "clang/AST/TypeNodes.def"

  void OutputUnimplementedType(clang::Type const* t, DumpNode const* dn) {
    this->OS << "  <Unimplemented id=\"_" << dn->Index
             << "\" type_class=\"" << encodeXML(t->getTypeClassName())
             << "\"/>\n";
  }
};

//----------------------------------------------------------------------------
class ASTVisitor: public ASTVisitorBase
{
  // Store an entry in the node traversal queue.
  struct QueueEntry {
    // Available node kinds.
    enum Kinds {
      KindDecl,
      KindType
    };

    QueueEntry(): Kind(KindDecl), Decl(0), DN(0) {}
    QueueEntry(clang::Decl const* d, DumpNode const* dn):
      Kind(KindDecl), Decl(d), DN(dn) {}
    QueueEntry(clang::QualType t, DumpNode const* dn):
      Kind(KindType), Decl(0), Type(t), DN(dn) {}

    // Kind of node at this entry.
    Kinds Kind;

    // The declaration when Kind == KindDecl.
    clang::Decl const* Decl;

    // The type when Kind == KindType.
    clang::QualType Type;

    // The dump status for this node.
    DumpNode const* DN;
  };

  // Order clang::QualType values.
  struct QualTypeCompare {
    bool operator()(clang::QualType l, clang::QualType r) const {
      // Order by pointer value without discarding low-order
      // bits used to encode qualifiers.
      void* lpp = &l;
      void* rpp = &r;
      return *static_cast<void**>(lpp) < *static_cast<void**>(rpp);
    }
  };

  /** Get the dump status node for a Clang declaration.  */
  DumpNode* GetDumpNode(clang::Decl const* d) {
    return &this->DeclNodes[d];
  }

  /** Get the dump status node for a Clang type.  */
  DumpNode* GetDumpNode(clang::QualType t) {
    return &this->TypeNodes[t];
  }

  /** Allocate a dump node for a Clang declaration.  */
  unsigned int AddDumpNode(clang::Decl const* d, bool complete);

  /** Allocate a dump node for a Clang type.  */
  unsigned int AddDumpNode(clang::QualType t, bool complete);

  /** Helper common to AddDumpNode implementation for every kind.  */
  template <typename K> unsigned int AddDumpNodeImpl(K k, bool complete);

  /** Queue leftover nodes that do not need complete output.  */
  void QueueIncompleteDumpNodes();

  /** Traverse AST nodes until the queue is empty.  */
  void ProcessQueue();

  /** Dispatch output of a declaration.  */
  void OutputDecl(clang::Decl const* d, DumpNode const* dn);

  /** Dispatch output of a qualified or unqualified type.  */
  void OutputType(clang::QualType t, DumpNode const* dn);

  /** Output a qualified type and queue its unqualified type.  */
  void OutputCvQualifiedType(clang::QualType t, DumpNode const* dn);

  /** Queue declarations matching given qualified name in given context.  */
  void LookupStart(clang::DeclContext const* dc, std::string const& name);

private:
  // List of starting declaration names.
  std::vector<std::string> const& StartNames;

  // Total number of nodes to be dumped.
  unsigned int NodeCount;

  // Whether we are in the complete or incomplete output step.
  bool RequireComplete;

  // Map from clang AST declaration node to our dump status node.
  typedef std::map<clang::Decl const*, DumpNode> DeclNodesMap;
  DeclNodesMap DeclNodes;

  // Map from clang AST type node to our dump status node.
  typedef std::map<clang::QualType, DumpNode, QualTypeCompare> TypeNodesMap;
  TypeNodesMap TypeNodes;

  // Node traversal queue.
  std::queue<QueueEntry> Queue;

public:
  ASTVisitor(clang::CompilerInstance& ci,
             clang::ASTContext const& ctx,
             llvm::raw_ostream& os,
             std::vector<std::string> const& startNames):
    ASTVisitorBase(ci, ctx, os),
    StartNames(startNames),
    NodeCount(0),
    RequireComplete(true) {}

  /** Visit declarations in the given translation unit.
      This is the main entry point.  */
  void HandleTranslationUnit(clang::TranslationUnitDecl const* tu);
};

//----------------------------------------------------------------------------
unsigned int ASTVisitor::AddDumpNode(clang::Decl const* d, bool complete) {
  // Add the node for the canonical declaration instance.
  return this->AddDumpNodeImpl(d->getCanonicalDecl(), complete);
}

//----------------------------------------------------------------------------
unsigned int ASTVisitor::AddDumpNode(clang::QualType t, bool complete) {
  return this->AddDumpNodeImpl(t, complete);
}

//----------------------------------------------------------------------------
template <typename K>
unsigned int ASTVisitor::AddDumpNodeImpl(K k, bool complete)
{
  // Update an existing node or add one.
  DumpNode* dn = this->GetDumpNode(k);
  if (dn->Index) {
    // Node was already encountered.  See if it is now complete.
    if(complete && !dn->Complete) {
      // Node is now complete, but wasn't before.  Queue it.
      dn->Complete = true;
      this->Queue.push(QueueEntry(k, dn));
    }
  } else {
    // This is a new node.  Assign it an index.
    dn->Index = ++this->NodeCount;
    dn->Complete = complete;
    if(complete || !this->RequireComplete) {
      // Node is complete.  Queue it.
      this->Queue.push(QueueEntry(k, dn));
    }
  }
  // Return node's index.
  return dn->Index;
}

//----------------------------------------------------------------------------
void ASTVisitor::QueueIncompleteDumpNodes()
{
  // Queue declaration nodes that do not need complete output.
  for(DeclNodesMap::const_iterator i = this->DeclNodes.begin(),
        e = this->DeclNodes.end(); i != e; ++i) {
    if(!i->second.Complete) {
      this->Queue.push(QueueEntry(i->first, &i->second));
    }
  }

  // Queue type nodes that do not need complete output.
  for(TypeNodesMap::const_iterator i = this->TypeNodes.begin(),
        e = this->TypeNodes.end(); i != e; ++i) {
    if(!i->second.Complete) {
      this->Queue.push(QueueEntry(i->first, &i->second));
    }
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::ProcessQueue()
{
  // Dispatch each entry in the queue based on its node kind.
  while(!this->Queue.empty()) {
    QueueEntry qe = this->Queue.front();
    this->Queue.pop();
    switch(qe.Kind) {
    case QueueEntry::KindDecl:
      this->OutputDecl(qe.Decl, qe.DN);
      break;
    case QueueEntry::KindType:
      this->OutputType(qe.Type, qe.DN);
      break;
    }
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::OutputDecl(clang::Decl const* d, DumpNode const* dn)
{
  // Dispatch output of the declaration.
  switch (d->getKind()) {
#define ABSTRACT_DECL(DECL)
#define DECL(CLASS, BASE) \
  case clang::Decl::CLASS: \
    this->Output##CLASS##Decl( \
      static_cast<clang::CLASS##Decl const*>(d), dn); \
    break;
#include "clang/AST/DeclNodes.inc"
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::OutputType(clang::QualType t, DumpNode const* dn)
{
  if(t.hasLocalQualifiers()) {
    // Output the qualified type.  This will queue
    // the unqualified type if necessary.
    this->OutputCvQualifiedType(t, dn);
  } else {
    // Dispatch output of the unqualified type.
    switch (t->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) \
      case clang::Type::CLASS: \
        this->Output##CLASS##Type( \
          static_cast<clang::CLASS##Type const*>(t.getTypePtr()), dn); \
        break;
#include "clang/AST/TypeNodes.def"
    }
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::OutputCvQualifiedType(clang::QualType t, DumpNode const* dn)
{
  // TODO: Output a CvQualifiedType element that references the
  // unqualified type element and lists qualifier attributes.
  static_cast<void>(t);
  static_cast<void>(dn);
}

//----------------------------------------------------------------------------
void ASTVisitor::LookupStart(clang::DeclContext const* dc,
                             std::string const& name)
{
  std::string::size_type pos = name.find("::");
  std::string cur = name.substr(0, pos);

  clang::IdentifierTable& ids = CI.getPreprocessor().getIdentifierTable();
  clang::DeclContext::lookup_const_result r =
    dc->lookup(clang::DeclarationName(&ids.get(cur)));
  if(pos == name.npos) {
    for(clang::DeclContext::lookup_const_iterator i = r.begin(), e = r.end();
        i != e; ++i) {
      this->AddDumpNode(*i, true);
    }
  } else {
    std::string rest = name.substr(pos+2);
    for(clang::DeclContext::lookup_const_iterator i = r.begin(), e = r.end();
        i != e; ++i) {
      if (clang::DeclContext* idc = clang::dyn_cast<clang::DeclContext>(*i)) {
        this->LookupStart(idc, rest);
      }
    }
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::HandleTranslationUnit(clang::TranslationUnitDecl const* tu)
{
  // Add the starting nodes for the dump.
  if(!this->StartNames.empty()) {
    // Use the specified starting locations.
    for(std::vector<std::string>::const_iterator i = this->StartNames.begin(),
          e = this->StartNames.end(); i != e; ++i) {
      this->LookupStart(tu, *i);
    }
  } else {
    // No start specified.  Use whole translation unit.
    this->AddDumpNode(tu, true);
  }

  // Start dump with gccxml-compatible format.
  this->OS <<
    "<?xml version=\"1.0\"?>\n"
    "<GCC_XML version=\"0.9.0\" cvs_revision=\"1.136\">\n"
    ;

  // Dump the complete nodes.
  this->ProcessQueue();

  // Queue all the incomplete nodes.
  this->RequireComplete = false;
  this->QueueIncompleteDumpNodes();

  // Dump the incomplete nodes.
  this->ProcessQueue();

  // Finish dump.
  this->OS <<
    "</GCC_XML>\n"
    ;
}

//----------------------------------------------------------------------------
void outputXML(clang::CompilerInstance& ci,
               clang::ASTContext const& ctx,
               llvm::raw_ostream& os,
               std::vector<std::string> const& startNames)
{
  ASTVisitor v(ci, ctx, os, startNames);
  v.HandleTranslationUnit(ctx.getTranslationUnitDecl());
}
<commit_msg>Add output for 'File' XML elements<commit_after>/*
  Copyright Kitware, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "Output.h"
#include "Utils.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"

#include <fstream>
#include <iostream>
#include <queue>

//----------------------------------------------------------------------------
class ASTVisitorBase
{
protected:
  clang::CompilerInstance& CI;
  clang::ASTContext const& CTX;
  llvm::raw_ostream& OS;

  ASTVisitorBase(clang::CompilerInstance& ci,
                 clang::ASTContext const& ctx,
                 llvm::raw_ostream& os): CI(ci), CTX(ctx), OS(os) {}

  // Record status of one AST node to be dumped.
  struct DumpNode {
    DumpNode(): Index(0), Complete(false) {}

    // Index in nodes ordered by first encounter.
    unsigned int Index;

    // Whether the node is to be traversed completely.
    bool Complete;
  };

  // Report all decl nodes as unimplemented until overridden.
#define ABSTRACT_DECL(DECL)
#define DECL(CLASS, BASE) \
  void Output##CLASS##Decl(clang::CLASS##Decl const* d, DumpNode const* dn) { \
    this->OutputUnimplementedDecl(d, dn); \
  }
#include "clang/AST/DeclNodes.inc"

  void OutputUnimplementedDecl(clang::Decl const* d, DumpNode const* dn) {
    this->OS << "  <Unimplemented id=\"_" << dn->Index
             << "\" kind=\"" << encodeXML(d->getDeclKindName()) << "\"/>\n";
  }

  // Report all type nodes as unimplemented until overridden.
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) \
  void Output##CLASS##Type(clang::CLASS##Type const* t, DumpNode const* dn) { \
    this->OutputUnimplementedType(t, dn); \
    }
#include "clang/AST/TypeNodes.def"

  void OutputUnimplementedType(clang::Type const* t, DumpNode const* dn) {
    this->OS << "  <Unimplemented id=\"_" << dn->Index
             << "\" type_class=\"" << encodeXML(t->getTypeClassName())
             << "\"/>\n";
  }
};

//----------------------------------------------------------------------------
class ASTVisitor: public ASTVisitorBase
{
  // Store an entry in the node traversal queue.
  struct QueueEntry {
    // Available node kinds.
    enum Kinds {
      KindDecl,
      KindType
    };

    QueueEntry(): Kind(KindDecl), Decl(0), DN(0) {}
    QueueEntry(clang::Decl const* d, DumpNode const* dn):
      Kind(KindDecl), Decl(d), DN(dn) {}
    QueueEntry(clang::QualType t, DumpNode const* dn):
      Kind(KindType), Decl(0), Type(t), DN(dn) {}

    // Kind of node at this entry.
    Kinds Kind;

    // The declaration when Kind == KindDecl.
    clang::Decl const* Decl;

    // The type when Kind == KindType.
    clang::QualType Type;

    // The dump status for this node.
    DumpNode const* DN;
  };

  // Order clang::QualType values.
  struct QualTypeCompare {
    bool operator()(clang::QualType l, clang::QualType r) const {
      // Order by pointer value without discarding low-order
      // bits used to encode qualifiers.
      void* lpp = &l;
      void* rpp = &r;
      return *static_cast<void**>(lpp) < *static_cast<void**>(rpp);
    }
  };

  /** Get the dump status node for a Clang declaration.  */
  DumpNode* GetDumpNode(clang::Decl const* d) {
    return &this->DeclNodes[d];
  }

  /** Get the dump status node for a Clang type.  */
  DumpNode* GetDumpNode(clang::QualType t) {
    return &this->TypeNodes[t];
  }

  /** Allocate a dump node for a Clang declaration.  */
  unsigned int AddDumpNode(clang::Decl const* d, bool complete);

  /** Allocate a dump node for a Clang type.  */
  unsigned int AddDumpNode(clang::QualType t, bool complete);

  /** Helper common to AddDumpNode implementation for every kind.  */
  template <typename K> unsigned int AddDumpNodeImpl(K k, bool complete);

  /** Allocate a dump node for a source file entry.  */
  unsigned int AddDumpFile(clang::FileEntry const* f);

  /** Queue leftover nodes that do not need complete output.  */
  void QueueIncompleteDumpNodes();

  /** Traverse AST nodes until the queue is empty.  */
  void ProcessQueue();
  void ProcessFileQueue();

  /** Dispatch output of a declaration.  */
  void OutputDecl(clang::Decl const* d, DumpNode const* dn);

  /** Dispatch output of a qualified or unqualified type.  */
  void OutputType(clang::QualType t, DumpNode const* dn);

  /** Output a qualified type and queue its unqualified type.  */
  void OutputCvQualifiedType(clang::QualType t, DumpNode const* dn);

  /** Queue declarations matching given qualified name in given context.  */
  void LookupStart(clang::DeclContext const* dc, std::string const& name);

private:
  // List of starting declaration names.
  std::vector<std::string> const& StartNames;

  // Total number of nodes to be dumped.
  unsigned int NodeCount;

  // Total number of source files to be referenced.
  unsigned int FileCount;

  // Whether we are in the complete or incomplete output step.
  bool RequireComplete;

  // Map from clang AST declaration node to our dump status node.
  typedef std::map<clang::Decl const*, DumpNode> DeclNodesMap;
  DeclNodesMap DeclNodes;

  // Map from clang AST type node to our dump status node.
  typedef std::map<clang::QualType, DumpNode, QualTypeCompare> TypeNodesMap;
  TypeNodesMap TypeNodes;

  // Map from clang file entry to our source file index.
  typedef std::map<clang::FileEntry const*, unsigned int> FileNodesMap;
  FileNodesMap FileNodes;

  // Node traversal queue.
  std::queue<QueueEntry> Queue;

  // File traversal queue.
  std::queue<clang::FileEntry const*> FileQueue;

public:
  ASTVisitor(clang::CompilerInstance& ci,
             clang::ASTContext const& ctx,
             llvm::raw_ostream& os,
             std::vector<std::string> const& startNames):
    ASTVisitorBase(ci, ctx, os),
    StartNames(startNames),
    NodeCount(0), FileCount(0),
    RequireComplete(true) {}

  /** Visit declarations in the given translation unit.
      This is the main entry point.  */
  void HandleTranslationUnit(clang::TranslationUnitDecl const* tu);
};

//----------------------------------------------------------------------------
unsigned int ASTVisitor::AddDumpNode(clang::Decl const* d, bool complete) {
  // Add the node for the canonical declaration instance.
  return this->AddDumpNodeImpl(d->getCanonicalDecl(), complete);
}

//----------------------------------------------------------------------------
unsigned int ASTVisitor::AddDumpNode(clang::QualType t, bool complete) {
  return this->AddDumpNodeImpl(t, complete);
}

//----------------------------------------------------------------------------
template <typename K>
unsigned int ASTVisitor::AddDumpNodeImpl(K k, bool complete)
{
  // Update an existing node or add one.
  DumpNode* dn = this->GetDumpNode(k);
  if (dn->Index) {
    // Node was already encountered.  See if it is now complete.
    if(complete && !dn->Complete) {
      // Node is now complete, but wasn't before.  Queue it.
      dn->Complete = true;
      this->Queue.push(QueueEntry(k, dn));
    }
  } else {
    // This is a new node.  Assign it an index.
    dn->Index = ++this->NodeCount;
    dn->Complete = complete;
    if(complete || !this->RequireComplete) {
      // Node is complete.  Queue it.
      this->Queue.push(QueueEntry(k, dn));
    }
  }
  // Return node's index.
  return dn->Index;
}

//----------------------------------------------------------------------------
unsigned int ASTVisitor::AddDumpFile(clang::FileEntry const* f)
{
  unsigned int& index = this->FileNodes[f];
  if(index == 0) {
    index = ++this->FileCount;
    this->FileQueue.push(f);
  }
  return index;
}

//----------------------------------------------------------------------------
void ASTVisitor::QueueIncompleteDumpNodes()
{
  // Queue declaration nodes that do not need complete output.
  for(DeclNodesMap::const_iterator i = this->DeclNodes.begin(),
        e = this->DeclNodes.end(); i != e; ++i) {
    if(!i->second.Complete) {
      this->Queue.push(QueueEntry(i->first, &i->second));
    }
  }

  // Queue type nodes that do not need complete output.
  for(TypeNodesMap::const_iterator i = this->TypeNodes.begin(),
        e = this->TypeNodes.end(); i != e; ++i) {
    if(!i->second.Complete) {
      this->Queue.push(QueueEntry(i->first, &i->second));
    }
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::ProcessQueue()
{
  // Dispatch each entry in the queue based on its node kind.
  while(!this->Queue.empty()) {
    QueueEntry qe = this->Queue.front();
    this->Queue.pop();
    switch(qe.Kind) {
    case QueueEntry::KindDecl:
      this->OutputDecl(qe.Decl, qe.DN);
      break;
    case QueueEntry::KindType:
      this->OutputType(qe.Type, qe.DN);
      break;
    }
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::ProcessFileQueue()
{
  while(!this->FileQueue.empty()) {
    clang::FileEntry const* f = this->FileQueue.front();
    this->FileQueue.pop();
    this->OS <<
      "  <File"
      " id=\"f" << this->FileNodes[f] << "\""
      " name=\"" << encodeXML(f->getName()) << "\""
      "/>\n"
      ;
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::OutputDecl(clang::Decl const* d, DumpNode const* dn)
{
  // Dispatch output of the declaration.
  switch (d->getKind()) {
#define ABSTRACT_DECL(DECL)
#define DECL(CLASS, BASE) \
  case clang::Decl::CLASS: \
    this->Output##CLASS##Decl( \
      static_cast<clang::CLASS##Decl const*>(d), dn); \
    break;
#include "clang/AST/DeclNodes.inc"
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::OutputType(clang::QualType t, DumpNode const* dn)
{
  if(t.hasLocalQualifiers()) {
    // Output the qualified type.  This will queue
    // the unqualified type if necessary.
    this->OutputCvQualifiedType(t, dn);
  } else {
    // Dispatch output of the unqualified type.
    switch (t->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) \
      case clang::Type::CLASS: \
        this->Output##CLASS##Type( \
          static_cast<clang::CLASS##Type const*>(t.getTypePtr()), dn); \
        break;
#include "clang/AST/TypeNodes.def"
    }
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::OutputCvQualifiedType(clang::QualType t, DumpNode const* dn)
{
  // TODO: Output a CvQualifiedType element that references the
  // unqualified type element and lists qualifier attributes.
  static_cast<void>(t);
  static_cast<void>(dn);
}

//----------------------------------------------------------------------------
void ASTVisitor::LookupStart(clang::DeclContext const* dc,
                             std::string const& name)
{
  std::string::size_type pos = name.find("::");
  std::string cur = name.substr(0, pos);

  clang::IdentifierTable& ids = CI.getPreprocessor().getIdentifierTable();
  clang::DeclContext::lookup_const_result r =
    dc->lookup(clang::DeclarationName(&ids.get(cur)));
  if(pos == name.npos) {
    for(clang::DeclContext::lookup_const_iterator i = r.begin(), e = r.end();
        i != e; ++i) {
      this->AddDumpNode(*i, true);
    }
  } else {
    std::string rest = name.substr(pos+2);
    for(clang::DeclContext::lookup_const_iterator i = r.begin(), e = r.end();
        i != e; ++i) {
      if (clang::DeclContext* idc = clang::dyn_cast<clang::DeclContext>(*i)) {
        this->LookupStart(idc, rest);
      }
    }
  }
}

//----------------------------------------------------------------------------
void ASTVisitor::HandleTranslationUnit(clang::TranslationUnitDecl const* tu)
{
  // Add the starting nodes for the dump.
  if(!this->StartNames.empty()) {
    // Use the specified starting locations.
    for(std::vector<std::string>::const_iterator i = this->StartNames.begin(),
          e = this->StartNames.end(); i != e; ++i) {
      this->LookupStart(tu, *i);
    }
  } else {
    // No start specified.  Use whole translation unit.
    this->AddDumpNode(tu, true);
  }

  // Start dump with gccxml-compatible format.
  this->OS <<
    "<?xml version=\"1.0\"?>\n"
    "<GCC_XML version=\"0.9.0\" cvs_revision=\"1.136\">\n"
    ;

  // Dump the complete nodes.
  this->ProcessQueue();

  // Queue all the incomplete nodes.
  this->RequireComplete = false;
  this->QueueIncompleteDumpNodes();

  // Dump the incomplete nodes.
  this->ProcessQueue();

  // Dump the filename queue.
  this->ProcessFileQueue();

  // Finish dump.
  this->OS <<
    "</GCC_XML>\n"
    ;
}

//----------------------------------------------------------------------------
void outputXML(clang::CompilerInstance& ci,
               clang::ASTContext const& ctx,
               llvm::raw_ostream& os,
               std::vector<std::string> const& startNames)
{
  ASTVisitor v(ci, ctx, os, startNames);
  v.HandleTranslationUnit(ctx.getTranslationUnitDecl());
}
<|endoftext|>


<commit_before>#pragma once

#include <boost/shared_ptr.hpp>
#include <darc/inbound_data.hpp>
#include <darc/serializer/boost.hpp>

#include <darc/message_packet.hpp>
#include <darc/subscribe_packet.hpp>
#include <darc/peer.hpp>

namespace darc
{

class RemoteDispatcher
{
protected:
  // Datastructure stuff, refactor out
  typedef std::pair</*peer*/ID, /*tag*/ID> remote_tag_type;
  typedef std::set<remote_tag_type> remote_tag_list_type;
  typedef boost::shared_ptr<remote_tag_list_type> remote_tag_list_type_ptr;
  typedef std::map</*tag*/ID, remote_tag_list_type_ptr> remote_list_type;

  remote_list_type list_;
  peer& peer_;

protected:
  void handle_subscribe_packet(const darc::ID& src_peer_id,
			       darc::buffer::shared_buffer data)
  {
  }

  void handle_message_packet(const darc::ID& src_peer_id,
			     darc::buffer::shared_buffer data)
  {
  }

public:
  RemoteDispatcher(peer& p) :
    peer_(p)
  {
  }

  void recv(const darc::ID& src_peer_id,
	    darc::service_type service_id,
	    darc::buffer::shared_buffer data)
  {
    darc::inbound_data<darc::serializer::boost_serializer, uint32_t> payload_type_i(data);
    switch(payload_type_i.get())
    {
    case subscribe_packet::payload_id:
    {
      handle_subscribe_packet(src_peer_id, data);
    }
    break;
    case message_packet::payload_id:
    {
      handle_message_packet(src_peer_id, data);
    }
    break;
    default:
      assert(0);
    }
  }

  void new_tag_event(ID tag_id,
		     ID alias_id,
		     ID peer_id)
  {
    remote_list_type::iterator item = list_.find(tag_id);
    if(item != list_.end())
    {
      remote_tag_list_type& l = *(item->second);
      l.insert(remote_tag_type(peer_id, alias_id));
    }
    else
    {
      remote_tag_list_type_ptr lp = boost::make_shared<remote_tag_list_type>();
      lp->insert(remote_tag_type(peer_id, alias_id));
      list_.insert(remote_list_type::value_type(tag_id, lp));
    }
  }

  template<typename T>
  void dispatch_remotely(const ID& tag_id, const boost::shared_ptr<const T> &msg)
  {
    remote_list_type::iterator item = list_.find(tag_id);
    if(item != list_.end())
    {
      for(remote_tag_list_type::iterator it = item->second->begin();
	  it != item->second->end();
	  it++)
      {
	// todo: here we send a copy to all
	send_msg(tag_id, it->first, msg);
      }
    }
  }

  template<typename T>
  void send_msg(const ID& tag_id, const ID& peer_id, const boost::shared_ptr<const T> &msg)
  {

  }

};

}
<commit_msg>serialize and send message<commit_after>#pragma once

#include <boost/shared_ptr.hpp>
#include <darc/inbound_data.hpp>
#include <darc/serializer/boost.hpp>

#include <darc/payload_header_packet.hpp>
#include <darc/message_packet.hpp>
#include <darc/subscribe_packet.hpp>
#include <darc/peer.hpp>

namespace darc
{

class RemoteDispatcher
{
protected:
  // Datastructure stuff, refactor out
  typedef std::pair</*peer*/ID, /*tag*/ID> remote_tag_type;
  typedef std::set<remote_tag_type> remote_tag_list_type;
  typedef boost::shared_ptr<remote_tag_list_type> remote_tag_list_type_ptr;
  typedef std::map</*tag*/ID, remote_tag_list_type_ptr> remote_list_type;

  remote_list_type list_;
  peer& peer_;

protected:
  void handle_subscribe_packet(const darc::ID& src_peer_id,
			       darc::buffer::shared_buffer data)
  {
  }

  void handle_message_packet(const darc::ID& src_peer_id,
			     darc::buffer::shared_buffer data)
  {
  }

public:
  RemoteDispatcher(peer& p) :
    peer_(p)
  {
  }

  void recv(const darc::ID& src_peer_id,
	    darc::service_type service_id,
	    darc::buffer::shared_buffer data)
  {
    darc::inbound_data<darc::serializer::boost_serializer, uint32_t> payload_type_i(data);
    switch(payload_type_i.get())
    {
    case subscribe_packet::payload_id:
    {
      handle_subscribe_packet(src_peer_id, data);
    }
    break;
    case message_packet::payload_id:
    {
      handle_message_packet(src_peer_id, data);
    }
    break;
    default:
      assert(0);
    }
  }

  void new_tag_event(ID tag_id,
		     ID alias_id,
		     ID peer_id)
  {
    remote_list_type::iterator item = list_.find(tag_id);
    if(item != list_.end())
    {
      remote_tag_list_type& l = *(item->second);
      l.insert(remote_tag_type(peer_id, alias_id));
    }
    else
    {
      remote_tag_list_type_ptr lp = boost::make_shared<remote_tag_list_type>();
      lp->insert(remote_tag_type(peer_id, alias_id));
      list_.insert(remote_list_type::value_type(tag_id, lp));
    }
  }

  template<typename T>
  void dispatch_remotely(const ID& tag_id, const boost::shared_ptr<const T> &msg)
  {
    remote_list_type::iterator item = list_.find(tag_id);
    if(item != list_.end())
    {
      for(remote_tag_list_type::iterator it = item->second->begin();
	  it != item->second->end();
	  it++)
      {
	// todo: here we send a copy to all
	send_msg(tag_id, it->first, msg);
      }
    }
  }

  template<typename T>
  void send_msg(const ID& tag_id, const ID& peer_id, const boost::shared_ptr<const T> &msg)
  {

    // todo move to peer_service
    buffer::shared_buffer buffer = boost::make_shared<buffer::const_size_buffer>(1024*10); // todo

    payload_header_packet hdr;
    hdr.payload_type = message_packet::payload_id;
    outbound_data<serializer::boost_serializer, payload_header_packet> o_hdr(hdr);

    message_packet msg_hdr(tag_id);
    outbound_data<serializer::boost_serializer, message_packet> o_msg_hdr(msg_hdr);

    outbound_ptr<serializer::boost_serializer, T> o_msg(msg);

    outbound_pair o_pair1(o_hdr, o_msg_hdr);
    outbound_pair o_pair2(o_pair1, o_msg);

    o_pair2.pack(buffer);

    peer_.send_to(peer_id, 52, buffer);
  }

};

}
<|endoftext|>


<commit_before>/**
 * \file
 * \brief StaticThread class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-03-26
 */

#ifndef INCLUDE_DISTORTOS_STATICTHREAD_HPP_
#define INCLUDE_DISTORTOS_STATICTHREAD_HPP_

#include "distortos/Thread.hpp"
#include "distortos/SignalsReceiver.hpp"

namespace distortos
{

/**
 * \brief StaticThread class is a templated interface for thread that has automatic storage for stack.
 *
 * \param StackSize is the size of stack, bytes
 * \param CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \param Function is the function that will be executed in separate thread
 * \param Args are the arguments for Function
 */

template<size_t StackSize, bool CanReceiveSignals, typename Function, typename... Args>
class StaticThread : public Thread<Function, Args...>
{
public:

	/// base of StaticThread
	using Base = Thread<Function, Args...>;

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args) :
			Base{&stack_, sizeof(stack_), priority, schedulingPolicy, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, Function&& function, Args&&... args) :
			StaticThread{priority, SchedulingPolicy::RoundRobin, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	StaticThread(const StaticThread&) = delete;
	StaticThread(StaticThread&&) = default;
	const StaticThread& operator=(const StaticThread&) = delete;
	StaticThread& operator=(StaticThread&&) = delete;

private:

	/// stack buffer
	typename std::aligned_storage<StackSize>::type stack_;
};

/**
 * \brief StaticThread class is a templated interface for thread that has automatic storage for stack and internal
 * SignalsReceiver object.
 *
 * Specialization for threads with enabled reception of signals (CanReceiveSignals == true)
 *
 * \param StackSize is the size of stack, bytes
 * \param Function is the function that will be executed in separate thread
 * \param Args are the arguments for Function
 */

template<size_t StackSize, typename Function, typename... Args>
class StaticThread<StackSize, true, Function, Args...> : public Thread<Function, Args...>
{
public:

	/// base of StaticThread
	using Base = Thread<Function, Args...>;

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args) :
			Base{&stack_, sizeof(stack_), priority, schedulingPolicy, &signalsReceiver_,
					std::forward<Function>(function), std::forward<Args>(args)...},
			signalsReceiver_{}
	{

	}

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, Function&& function, Args&&... args) :
			StaticThread{priority, SchedulingPolicy::RoundRobin, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	StaticThread(const StaticThread&) = delete;
	StaticThread(StaticThread&&) = default;
	const StaticThread& operator=(const StaticThread&) = delete;
	StaticThread& operator=(StaticThread&&) = delete;

private:

	/// stack buffer
	typename std::aligned_storage<StackSize>::type stack_;

	/// internal SignalsReceiver object
	SignalsReceiver signalsReceiver_;
};

/**
 * \brief Helper factory function to make StaticThread object with partially deduced template arguments
 *
 * \param StackSize is the size of stack, bytes
 * \param CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \param Function is the function that will be executed
 * \param Args are the arguments for Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] schedulingPolicy is the scheduling policy of the thread
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, Function, Args...> makeStaticThread(const uint8_t priority,
		const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args)
{
	return {priority, schedulingPolicy, std::forward<Function>(function), std::forward<Args>(args)...};
}

/**
 * \brief Helper factory function to make StaticThread object with partially deduced template arguments
 *
 * \param StackSize is the size of stack, bytes
 * \param CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \param Function is the function that will be executed
 * \param Args are the arguments for Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, Function, Args...> makeStaticThread(const uint8_t priority,
		Function&& function, Args&&... args)
{
	return {priority, std::forward<Function>(function), std::forward<Args>(args)...};
}

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_STATICTHREAD_HPP_
<commit_msg>StaticThread: replace internal SignalsReceiver with StaticSignalsReceiver<commit_after>/**
 * \file
 * \brief StaticThread class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-03-26
 */

#ifndef INCLUDE_DISTORTOS_STATICTHREAD_HPP_
#define INCLUDE_DISTORTOS_STATICTHREAD_HPP_

#include "distortos/Thread.hpp"
#include "distortos/StaticSignalsReceiver.hpp"

namespace distortos
{

/**
 * \brief StaticThread class is a templated interface for thread that has automatic storage for stack.
 *
 * \param StackSize is the size of stack, bytes
 * \param CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \param Function is the function that will be executed in separate thread
 * \param Args are the arguments for Function
 */

template<size_t StackSize, bool CanReceiveSignals, typename Function, typename... Args>
class StaticThread : public Thread<Function, Args...>
{
public:

	/// base of StaticThread
	using Base = Thread<Function, Args...>;

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args) :
			Base{&stack_, sizeof(stack_), priority, schedulingPolicy, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, Function&& function, Args&&... args) :
			StaticThread{priority, SchedulingPolicy::RoundRobin, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	StaticThread(const StaticThread&) = delete;
	StaticThread(StaticThread&&) = default;
	const StaticThread& operator=(const StaticThread&) = delete;
	StaticThread& operator=(StaticThread&&) = delete;

private:

	/// stack buffer
	typename std::aligned_storage<StackSize>::type stack_;
};

/**
 * \brief StaticThread class is a templated interface for thread that has automatic storage for stack and internal
 * StaticSignalsReceiver object.
 *
 * Specialization for threads with enabled reception of signals (CanReceiveSignals == true)
 *
 * \param StackSize is the size of stack, bytes
 * \param Function is the function that will be executed in separate thread
 * \param Args are the arguments for Function
 */

template<size_t StackSize, typename Function, typename... Args>
class StaticThread<StackSize, true, Function, Args...> : public Thread<Function, Args...>
{
public:

	/// base of StaticThread
	using Base = Thread<Function, Args...>;

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] schedulingPolicy is the scheduling policy of the thread
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args) :
			Base{&stack_, sizeof(stack_), priority, schedulingPolicy, &staticSignalsReceiver_,
					std::forward<Function>(function), std::forward<Args>(args)...},
			staticSignalsReceiver_{}
	{

	}

	/**
	 * \brief StaticThread's constructor
	 *
	 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
	 * \param [in] function is a function that will be executed in separate thread
	 * \param [in] args are arguments for function
	 */

	StaticThread(const uint8_t priority, Function&& function, Args&&... args) :
			StaticThread{priority, SchedulingPolicy::RoundRobin, std::forward<Function>(function),
					std::forward<Args>(args)...}
	{

	}

	StaticThread(const StaticThread&) = delete;
	StaticThread(StaticThread&&) = default;
	const StaticThread& operator=(const StaticThread&) = delete;
	StaticThread& operator=(StaticThread&&) = delete;

private:

	/// stack buffer
	typename std::aligned_storage<StackSize>::type stack_;

	/// internal StaticSignalsReceiver object
	StaticSignalsReceiver staticSignalsReceiver_;
};

/**
 * \brief Helper factory function to make StaticThread object with partially deduced template arguments
 *
 * \param StackSize is the size of stack, bytes
 * \param CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \param Function is the function that will be executed
 * \param Args are the arguments for Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] schedulingPolicy is the scheduling policy of the thread
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, Function, Args...> makeStaticThread(const uint8_t priority,
		const SchedulingPolicy schedulingPolicy, Function&& function, Args&&... args)
{
	return {priority, schedulingPolicy, std::forward<Function>(function), std::forward<Args>(args)...};
}

/**
 * \brief Helper factory function to make StaticThread object with partially deduced template arguments
 *
 * \param StackSize is the size of stack, bytes
 * \param CanReceiveSignals selects whether reception of signals is enabled (true) or disabled (false) for this thread
 * \param Function is the function that will be executed
 * \param Args are the arguments for Function
 *
 * \param [in] priority is the thread's priority, 0 - lowest, UINT8_MAX - highest
 * \param [in] function is a function that will be executed in separate thread
 * \param [in] args are arguments for function
 *
 * \return StaticThread object with partially deduced template arguments
 */

template<size_t StackSize, bool CanReceiveSignals = {}, typename Function, typename... Args>
StaticThread<StackSize, CanReceiveSignals, Function, Args...> makeStaticThread(const uint8_t priority,
		Function&& function, Args&&... args)
{
	return {priority, std::forward<Function>(function), std::forward<Args>(args)...};
}

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_STATICTHREAD_HPP_
<|endoftext|>


<commit_before>/**
 * \file
 * \brief Architecture specific symbols
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-08-06
 */

#ifndef INCLUDE_DISTORTOS_ARCHITECTURE_HPP_
#define INCLUDE_DISTORTOS_ARCHITECTURE_HPP_

#include "distortos/architecture/parameters.hpp"

#include <cstddef>

namespace distortos
{

/// architecture namespace has symbols that need to be provided by selected architecture
namespace architecture
{

/**
 * \brief Enables interrupt masking.
 *
 * Disables normal-priority interrupts.
 *
 * \note High-priority interrupts are not controlled by distortos, so they may be left enabled. Support for that feature
 * is architecture-dependent.
 *
 * \return previous value of interrupts' mask, must be used for matched restoreInterruptMasking() call
 */

InterruptMask enableInterruptMasking();

/**
 * \brief Architecture-specific stack initialization.
 *
 * This function fills provided buffer with hardware and software stack frame and calculates value of stack pointer
 * register. After this function completes, stack is ready for context switching.
 *
 * \attention buffer and size must be properly adjusted for architecture requirements
 *
 * \param [in] buffer is a pointer to stack's buffer
 * \param [in] size is the size of stack's buffer, bytes
 * \param [in] function is a reference to thread's function
 * \param [in] arguments is an argument for function
 * \param [in] trap is a reference to trap function called when thread function returns
 *
 * \return value that can be used as thread's stack pointer, ready for context switching
 */

void * initializeStack(void *buffer, size_t size, void * (&function)(void *), void *arguments, void (&trap)(void *));

/**
 * \brief Restores interrupt masking.
 *
 * Restores previous interrupt masking state (before matching enableInterruptMasking() was called), enabling some (maybe
 * all) interrupts.
 *
 * \param [in] interrupt_mask is the value of interrupts' mask, must come from previous call to enableInterruptMasking()
 */

void restoreInterruptMasking(InterruptMask interrupt_mask);

/**
 * \brief Architecture-specific request for context switch.
 *
 * Causes the architecture to do context save, call scheduler::schedulerInstance.switchContext() and do context restore.
 * The call to scheduler::schedulerInstance.switchContext() must be done from the context in which such call is valid
 * (usually system interrupt).
 */

void requestContextSwitch();

/**
 * \brief Architecture-specific start of scheduling.
 *
 * Initializes all required hardware/software to perform context switching and starts the scheduling.
 */

__attribute__ ((noreturn))
void startScheduling();

}	// namespace architecture

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_ARCHITECTURE_HPP_
<commit_msg>include/distortos/architecture.hpp: add declaration of disableInterruptMasking()<commit_after>/**
 * \file
 * \brief Architecture specific symbols
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-08-06
 */

#ifndef INCLUDE_DISTORTOS_ARCHITECTURE_HPP_
#define INCLUDE_DISTORTOS_ARCHITECTURE_HPP_

#include "distortos/architecture/parameters.hpp"

#include <cstddef>

namespace distortos
{

/// architecture namespace has symbols that need to be provided by selected architecture
namespace architecture
{

/**
 * \brief Disables interrupt masking.
 *
 * Enables normal-priority interrupts.
 *
 * \return previous value of interrupts' mask, must be used for matched restoreInterruptMasking() call
 */

InterruptMask disableInterruptMasking();

/**
 * \brief Enables interrupt masking.
 *
 * Disables normal-priority interrupts.
 *
 * \note High-priority interrupts are not controlled by distortos, so they may be left enabled. Support for that feature
 * is architecture-dependent.
 *
 * \return previous value of interrupts' mask, must be used for matched restoreInterruptMasking() call
 */

InterruptMask enableInterruptMasking();

/**
 * \brief Architecture-specific stack initialization.
 *
 * This function fills provided buffer with hardware and software stack frame and calculates value of stack pointer
 * register. After this function completes, stack is ready for context switching.
 *
 * \attention buffer and size must be properly adjusted for architecture requirements
 *
 * \param [in] buffer is a pointer to stack's buffer
 * \param [in] size is the size of stack's buffer, bytes
 * \param [in] function is a reference to thread's function
 * \param [in] arguments is an argument for function
 * \param [in] trap is a reference to trap function called when thread function returns
 *
 * \return value that can be used as thread's stack pointer, ready for context switching
 */

void * initializeStack(void *buffer, size_t size, void * (&function)(void *), void *arguments, void (&trap)(void *));

/**
 * \brief Restores interrupt masking.
 *
 * Restores previous interrupt masking state (before matching enableInterruptMasking() or disableInterruptMasking() was
 * called), enabling some (maybe all, maybe none) interrupts.
 *
 * \param [in] interrupt_mask is the value of interrupts' mask, must come from previous call to enableInterruptMasking()
 * or disableInterruptMasking()
 */

void restoreInterruptMasking(InterruptMask interrupt_mask);

/**
 * \brief Architecture-specific request for context switch.
 *
 * Causes the architecture to do context save, call scheduler::schedulerInstance.switchContext() and do context restore.
 * The call to scheduler::schedulerInstance.switchContext() must be done from the context in which such call is valid
 * (usually system interrupt).
 */

void requestContextSwitch();

/**
 * \brief Architecture-specific start of scheduling.
 *
 * Initializes all required hardware/software to perform context switching and starts the scheduling.
 */

__attribute__ ((noreturn))
void startScheduling();

}	// namespace architecture

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_ARCHITECTURE_HPP_
<|endoftext|>


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

#ifndef MAPNIK_POLYGON_CLIPPER_HPP
#define MAPNIK_POLYGON_CLIPPER_HPP

// stl
#include <iostream>
#include <deque>

// mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/geometry.hpp>

// boost

#include <boost/tuple/tuple.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/register/point.hpp>

BOOST_GEOMETRY_REGISTER_POINT_2D(mapnik::coord2d, double, cs::cartesian, x, y)

// register mapnik::box2d<double>
namespace boost { namespace geometry { namespace traits
{

template<> struct tag<mapnik::box2d<double> > { typedef box_tag type; };

template<> struct point_type<mapnik::box2d<double> > { typedef mapnik::coord2d type; };

template <>
struct indexed_access<mapnik::box2d<double>, min_corner, 0>
{
    typedef coordinate_type<mapnik::coord2d>::type ct;
    static inline ct get(mapnik::box2d<double> const& b) { return b.minx();}
    static inline void set(mapnik::box2d<double> &b, ct const& value) { b.set_minx(value); }
};

template <>
struct indexed_access<mapnik::box2d<double>, min_corner, 1>
{
    typedef coordinate_type<mapnik::coord2d>::type ct;
    static inline ct get(mapnik::box2d<double> const& b) { return b.miny();}
    static inline void set(mapnik::box2d<double> &b, ct const& value) { b.set_miny(value); }
};

template <>
struct indexed_access<mapnik::box2d<double>, max_corner, 0>
{
    typedef coordinate_type<mapnik::coord2d>::type ct;
    static inline ct get(mapnik::box2d<double> const& b) { return b.maxx();}
    static inline void set(mapnik::box2d<double> &b, ct const& value) { b.set_maxx(value); }
};

template <>
struct indexed_access<mapnik::box2d<double>, max_corner, 1>
{
    typedef coordinate_type<mapnik::coord2d>::type ct;
    static inline ct get(mapnik::box2d<double> const& b) { return b.maxy();}
    static inline void set(mapnik::box2d<double> &b , ct const& value) { b.set_maxy(value); }
};

}}}

namespace mapnik {

using namespace boost::geometry;

template <typename Geometry>
struct polygon_clipper
{
    typedef mapnik::coord2d point_2d;
    typedef model::polygon<mapnik::coord2d> polygon_2d;
    typedef std::deque<polygon_2d> polygon_list;

    enum
    {
        clip = 1,
        no_clip = 2,
        ignore = 3

    } state_;

    polygon_clipper(Geometry & geom)
        : state_(clip),
          clip_box_(),
          geom_(geom)
    {

    }

    polygon_clipper(box2d<double> const& clip_box, Geometry & geom)
        :state_(clip),
         clip_box_(clip_box),
         geom_(geom)
    {
        init();
    }

    void set_clip_box(box2d<double> const& clip_box)
    {
        state_ = clip;
        clip_box_ = clip_box;
        init();
    }

    unsigned type() const
    {
        return geom_.type();
    }

    void rewind(unsigned path_id)
    {
        if (state_ == clip) output_.rewind(path_id);
        else geom_.rewind(path_id);
    }

    unsigned vertex (double * x, double * y)
    {
        switch (state_)
        {
        case clip:
            return output_.vertex(x,y);
        case no_clip:
            return geom_.vertex(x,y);
        case ignore:
            return SEG_END;
        }
    }

private:

    void init()
    {
        geom_.rewind(0);
        box2d<double> bbox = geom_.envelope();
        if (clip_box_.contains(bbox))
        {
            // shortcut to original geometry (no-clipping)
            state_ = no_clip;
            return;
        }
        else if (!clip_box_.intersects(bbox))
        {
            // polygon is outside of clipping box
            state_ = ignore;
            return;
        }

        polygon_2d subject_poly;
        double x,y;
        double prev_x, prev_y;
        geom_.rewind(0);
        unsigned ring_count = 0;
        while (true)
        {
            unsigned cmd = geom_.vertex(&x,&y);
            if (cmd == SEG_END) break;
            if (cmd == SEG_MOVETO)
            {
                prev_x = x;
                prev_y = y;
                if (ring_count == 0)
                {
                    append(subject_poly, make<point_2d>(x,y));
                }
                else
                {
                    subject_poly.inners().push_back(polygon_2d::inner_container_type::value_type());
                    append(subject_poly.inners().back(),make<point_2d>(x,y));
                }
                ++ring_count;
            }
            else if (cmd == SEG_LINETO)
            {
                if (std::abs(x - prev_x) < 1e-12 && std::abs(y - prev_y) < 1e-12)
                {
#ifdef MAPNIK_LOG
                    MAPNIK_LOG_WARN(polygon_clipper)
                        << std::setprecision(12) << "coincident vertices:(" << prev_x << ","
                        <<  prev_y << ") , (" << x << "," << y <<  ")";
#endif
                    continue;
                }
                prev_x = x;
                prev_y = y;
                if (ring_count == 1)
                {
                    append(subject_poly, make<point_2d>(x,y));
                }
                else
                {
                    append(subject_poly.inners().back(),make<point_2d>(x,y));
                }
            }
        }

        polygon_list clipped_polygons;
#ifdef MAPNIK_LOG
        double area = boost::geometry::area(subject_poly);
        if (area < 0)
        {
            MAPNIK_LOG_ERROR(polygon_clipper) << "negative area detected for polygon indicating incorrect winding order";
        }
#endif
        try
        {
            boost::geometry::intersection(clip_box_, subject_poly, clipped_polygons);
        }
        catch (boost::geometry::exception const& ex)
        {
            std::cerr << ex.what() << std::endl;
        }

        for (polygon_2d const& poly : clipped_polygons)
        {
            bool move_to = true;
            for (point_2d const& c : boost::geometry::exterior_ring(poly))
            {
                if (move_to)
                {
                    move_to = false;
                    output_.move_to(c.x,c.y);
                }
                else
                {
                    output_.line_to(c.x,c.y);
                }
            }
            output_.close_path();
            // interior rings
            for (polygon_2d::inner_container_type::value_type const& ring : boost::geometry::interior_rings(poly))
            {
                move_to = true;
                for (point_2d const& c : ring)
                {
                    if (move_to)
                    {
                        move_to = false;
                        output_.move_to(c.x,c.y);
                    }
                    else
                    {
                        output_.line_to(c.x,c.y);
                    }
                }
                output_.close_path();
            }
        }
    }

    box2d<double> clip_box_;
    Geometry & geom_;
    mapnik::geometry_type output_;

};

}

#endif //MAPNIK_POLYGON_CLIPPER_HPP
<commit_msg>polygon clipper: ensure we return from function<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2013 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef MAPNIK_POLYGON_CLIPPER_HPP
#define MAPNIK_POLYGON_CLIPPER_HPP

// stl
#include <iostream>
#include <deque>

// mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/geometry.hpp>

// boost

#include <boost/tuple/tuple.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/register/point.hpp>

BOOST_GEOMETRY_REGISTER_POINT_2D(mapnik::coord2d, double, cs::cartesian, x, y)

// register mapnik::box2d<double>
namespace boost { namespace geometry { namespace traits
{

template<> struct tag<mapnik::box2d<double> > { typedef box_tag type; };

template<> struct point_type<mapnik::box2d<double> > { typedef mapnik::coord2d type; };

template <>
struct indexed_access<mapnik::box2d<double>, min_corner, 0>
{
    typedef coordinate_type<mapnik::coord2d>::type ct;
    static inline ct get(mapnik::box2d<double> const& b) { return b.minx();}
    static inline void set(mapnik::box2d<double> &b, ct const& value) { b.set_minx(value); }
};

template <>
struct indexed_access<mapnik::box2d<double>, min_corner, 1>
{
    typedef coordinate_type<mapnik::coord2d>::type ct;
    static inline ct get(mapnik::box2d<double> const& b) { return b.miny();}
    static inline void set(mapnik::box2d<double> &b, ct const& value) { b.set_miny(value); }
};

template <>
struct indexed_access<mapnik::box2d<double>, max_corner, 0>
{
    typedef coordinate_type<mapnik::coord2d>::type ct;
    static inline ct get(mapnik::box2d<double> const& b) { return b.maxx();}
    static inline void set(mapnik::box2d<double> &b, ct const& value) { b.set_maxx(value); }
};

template <>
struct indexed_access<mapnik::box2d<double>, max_corner, 1>
{
    typedef coordinate_type<mapnik::coord2d>::type ct;
    static inline ct get(mapnik::box2d<double> const& b) { return b.maxy();}
    static inline void set(mapnik::box2d<double> &b , ct const& value) { b.set_maxy(value); }
};

}}}

namespace mapnik {

using namespace boost::geometry;

template <typename Geometry>
struct polygon_clipper
{
    typedef mapnik::coord2d point_2d;
    typedef model::polygon<mapnik::coord2d> polygon_2d;
    typedef std::deque<polygon_2d> polygon_list;

    enum
    {
        clip = 1,
        no_clip = 2,
        ignore = 3

    } state_;

    polygon_clipper(Geometry & geom)
        : state_(clip),
          clip_box_(),
          geom_(geom)
    {

    }

    polygon_clipper(box2d<double> const& clip_box, Geometry & geom)
        :state_(clip),
         clip_box_(clip_box),
         geom_(geom)
    {
        init();
    }

    void set_clip_box(box2d<double> const& clip_box)
    {
        state_ = clip;
        clip_box_ = clip_box;
        init();
    }

    unsigned type() const
    {
        return geom_.type();
    }

    void rewind(unsigned path_id)
    {
        if (state_ == clip) output_.rewind(path_id);
        else geom_.rewind(path_id);
    }

    unsigned vertex (double * x, double * y)
    {
        switch (state_)
        {
        case clip:
            return output_.vertex(x,y);
        case no_clip:
            return geom_.vertex(x,y);
        case ignore:
            return SEG_END;
        }
        return SEG_END;
    }

private:

    void init()
    {
        geom_.rewind(0);
        box2d<double> bbox = geom_.envelope();
        if (clip_box_.contains(bbox))
        {
            // shortcut to original geometry (no-clipping)
            state_ = no_clip;
            return;
        }
        else if (!clip_box_.intersects(bbox))
        {
            // polygon is outside of clipping box
            state_ = ignore;
            return;
        }

        polygon_2d subject_poly;
        double x,y;
        double prev_x, prev_y;
        geom_.rewind(0);
        unsigned ring_count = 0;
        while (true)
        {
            unsigned cmd = geom_.vertex(&x,&y);
            if (cmd == SEG_END) break;
            if (cmd == SEG_MOVETO)
            {
                prev_x = x;
                prev_y = y;
                if (ring_count == 0)
                {
                    append(subject_poly, make<point_2d>(x,y));
                }
                else
                {
                    subject_poly.inners().push_back(polygon_2d::inner_container_type::value_type());
                    append(subject_poly.inners().back(),make<point_2d>(x,y));
                }
                ++ring_count;
            }
            else if (cmd == SEG_LINETO)
            {
                if (std::abs(x - prev_x) < 1e-12 && std::abs(y - prev_y) < 1e-12)
                {
#ifdef MAPNIK_LOG
                    MAPNIK_LOG_WARN(polygon_clipper)
                        << std::setprecision(12) << "coincident vertices:(" << prev_x << ","
                        <<  prev_y << ") , (" << x << "," << y <<  ")";
#endif
                    continue;
                }
                prev_x = x;
                prev_y = y;
                if (ring_count == 1)
                {
                    append(subject_poly, make<point_2d>(x,y));
                }
                else
                {
                    append(subject_poly.inners().back(),make<point_2d>(x,y));
                }
            }
        }

        polygon_list clipped_polygons;
#ifdef MAPNIK_LOG
        double area = boost::geometry::area(subject_poly);
        if (area < 0)
        {
            MAPNIK_LOG_ERROR(polygon_clipper) << "negative area detected for polygon indicating incorrect winding order";
        }
#endif
        try
        {
            boost::geometry::intersection(clip_box_, subject_poly, clipped_polygons);
        }
        catch (boost::geometry::exception const& ex)
        {
            std::cerr << ex.what() << std::endl;
        }

        for (polygon_2d const& poly : clipped_polygons)
        {
            bool move_to = true;
            for (point_2d const& c : boost::geometry::exterior_ring(poly))
            {
                if (move_to)
                {
                    move_to = false;
                    output_.move_to(c.x,c.y);
                }
                else
                {
                    output_.line_to(c.x,c.y);
                }
            }
            output_.close_path();
            // interior rings
            for (polygon_2d::inner_container_type::value_type const& ring : boost::geometry::interior_rings(poly))
            {
                move_to = true;
                for (point_2d const& c : ring)
                {
                    if (move_to)
                    {
                        move_to = false;
                        output_.move_to(c.x,c.y);
                    }
                    else
                    {
                        output_.line_to(c.x,c.y);
                    }
                }
                output_.close_path();
            }
        }
    }

    box2d<double> clip_box_;
    Geometry & geom_;
    mapnik::geometry_type output_;

};

}

#endif //MAPNIK_POLYGON_CLIPPER_HPP
<|endoftext|>