<commit_before>// Copyright (c) 2011 - 2017, GS Group, https://github.com/GSGroup
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
// provided that the above copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include <stingraykit/timer/Timer.h>

#include <list>
#include <map>

#include <stingraykit/diagnostics/ExecutorsProfiler.h>
#include <stingraykit/function/CancellableFunction.h>
#include <stingraykit/function/bind.h>
#include <stingraykit/function/function_name_getter.h>
#include <stingraykit/log/Logger.h>
#include <stingraykit/time/ElapsedTime.h>
#include <stingraykit/TaskLifeToken.h>

namespace stingray
{

	namespace Detail
	{
		struct ITimerConnectionImpl
		{
			virtual ~ITimerConnectionImpl() { }

			virtual void Disconnect() = 0;
		};
		STINGRAYKIT_DECLARE_PTR(ITimerConnectionImpl);
	}

	class TimerConnectionToken : public virtual IToken
	{
		friend class Timer;

	private:
		Detail::ITimerConnectionImplPtr		_impl;

	public:
		TimerConnectionToken(const Detail::ITimerConnectionImplPtr& impl) : _impl(impl)
		{ }

		~TimerConnectionToken()
		{
			if (_impl)
			{
				_impl->Disconnect();
				_impl.reset();
			}
		}
	};

	class Timer::CallbackQueue
	{
		typedef std::list<CallbackInfoPtr>					ContainerInternal;
		typedef std::map<TimeDuration, ContainerInternal>	Container;

	private:
		Mutex			_mutex;
		Container		_container;

	public:
		typedef ContainerInternal::iterator iterator;

		inline Mutex &Sync()
		{ return _mutex; }

		inline bool IsEmpty() const
		{
			MutexLock l(_mutex);
			return _container.empty();
		}

		CallbackInfoPtr Top() const;
		void Push(CallbackInfoPtr ci);
		void Erase(const iterator & it);
		CallbackInfoPtr Pop();
	};

	class Timer::CallbackInfo : public virtual Detail::ITimerConnectionImpl
	{
		STINGRAYKIT_NONCOPYABLE(CallbackInfo);
		typedef function<void()>		FuncT;

	private:
		FuncT						_func;
		TimeDuration				_timeToTrigger;
		optional<TimeDuration>		_period;
		TaskLifeToken				_token;
		CallbackQueueWeakPtr		_queue;
		CallbackQueue::iterator		_iterator;
		bool						_iteratorIsValid;

	private:
		friend class CallbackQueue;

		void SetIterator(const CallbackQueue::iterator& it)		{ _iterator = it; _iteratorIsValid = true; }
		void ResetIterator()									{ _iteratorIsValid = false; }

	public:
		CallbackInfo(const FuncT& func, const TimeDuration& timeToTrigger, const optional<TimeDuration>& period, const CallbackQueuePtr& queue)
			: _func(func), _timeToTrigger(timeToTrigger), _period(period), _queue(queue), _iteratorIsValid(false)
		{ }

		const FuncT& GetFunc() const							{ return _func; }
		FutureExecutionTester GetExecutionTester() const 		{ return _token.GetExecutionTester(); }

		bool IsPeriodic() const									{ return _period.is_initialized(); }
		void Restart(const TimeDuration& currentTime)
		{
			STINGRAYKIT_CHECK(_period, "CallbackInfo::Restart internal error: _period is set!");
			_timeToTrigger = currentTime + *_period;
		}
		TimeDuration GetTimeToTrigger() const					{ return _timeToTrigger; }

		virtual void Disconnect()
		{
			CallbackQueuePtr qm = _queue.lock();
			if (qm)
			{
				MutexLock l(qm->Sync());
				if (_iteratorIsValid)
				{
					qm->Erase(_iterator);
					ResetIterator();
				}
			}
			_token.Release();
		}
	};

	Timer::CallbackInfoPtr Timer::CallbackQueue::Top() const
	{
		MutexLock l(_mutex);
		if (!_container.empty())
		{
			const ContainerInternal& listForTop = _container.begin()->second;
			STINGRAYKIT_CHECK(!listForTop.empty(), "try to get callback from empty list");
			return listForTop.front();
		}
		else
			return null;
	}

	void Timer::CallbackQueue::Push(CallbackInfoPtr ci)
	{
		MutexLock l(_mutex);
		ContainerInternal& listToInsert = _container[ci->GetTimeToTrigger()];
		ci->SetIterator(listToInsert.insert(listToInsert.end(), ci));
	}

	void Timer::CallbackQueue::Erase(const iterator & it)
	{
		MutexLock l(_mutex);
		TimeDuration keyToErase = (*it)->GetTimeToTrigger();
		ContainerInternal& listToErase = _container[keyToErase];
		listToErase.erase(it);
		if (listToErase.empty())
			_container.erase(keyToErase);
	}

	Timer::CallbackInfoPtr Timer::CallbackQueue::Pop()
	{
		MutexLock l(_mutex);
		STINGRAYKIT_CHECK(!_container.empty(), "popping callback from empty map");
		ContainerInternal& listToPop = _container.begin()->second;
		STINGRAYKIT_CHECK(!listToPop.empty(), "popping callback from empty list");

		CallbackInfoPtr ci = listToPop.front();
		listToPop.pop_front();
		if (listToPop.empty())
			_container.erase(ci->GetTimeToTrigger());
		ci->ResetIterator();
		return ci;
	}

	STINGRAYKIT_DEFINE_NAMED_LOGGER(Timer);

	Timer::Timer(const std::string& timerName, const ExceptionHandler& exceptionHandler, bool profileCalls)
		:	_timerName(timerName),
			_exceptionHandler(exceptionHandler),
			_profileCalls(profileCalls),
			_alive(true),
			_queue(make_shared<CallbackQueue>()),
			_worker(make_shared<Thread>(timerName, bind(&Timer::ThreadFunc, this, not_using(_1))))
	{ }

	Timer::~Timer()
	{
		{
			MutexLock l(_queue->Sync());
			_alive = false;
			_cond.Broadcast();
		}
		_worker.reset();

		while(!_queue->IsEmpty())
		{
			CallbackInfoPtr top = _queue->Pop();
			LocalExecutionGuard guard(top->GetExecutionTester());
			if (guard)
			{
				s_logger.Warning() << "killing timer " << _timerName << " which still has some functions to execute";
				break;
			}
		}
	}

	Token Timer::SetTimeout(const TimeDuration& timeout, const function<void()>& func)
	{
		MutexLock l(_queue->Sync());

		CallbackInfoPtr ci = make_shared<CallbackInfo>(func, _monotonic.Elapsed() + timeout, null, _queue);
		_queue->Push(ci);
		_cond.Broadcast();

		return MakeToken<TimerConnectionToken>(ci);
	}

	Token Timer::SetTimer(const TimeDuration& interval, const function<void()>& func)
	{ return SetTimer(interval, interval, func); }

	Token Timer::SetTimer(const TimeDuration& timeout, const TimeDuration& interval, const function<void()>& func)
	{
		MutexLock l(_queue->Sync());

		CallbackInfoPtr ci = make_shared<CallbackInfo>(func, _monotonic.Elapsed() + timeout, interval, _queue);
		_queue->Push(ci);
		_cond.Broadcast();

		return MakeToken<TimerConnectionToken>(ci);
	}

	void Timer::AddTask(const function<void()>& task, const FutureExecutionTester& tester)
	{
		MutexLock l(_queue->Sync());

		CallbackInfoPtr ci = make_shared<CallbackInfo>(MakeCancellableFunction(task, tester), _monotonic.Elapsed(), null, _queue);
		_queue->Push(ci);
		_cond.Broadcast();
	}

	std::string Timer::GetProfilerMessage(const function<void()>& func)
	{ return StringBuilder() % get_function_name(func) % " in Timer '" % _timerName % "'"; }

	void Timer::ThreadFunc()
	{
		MutexLock l(_queue->Sync());

		while (_alive)
		{
			if (_queue->IsEmpty())
			{
				_cond.Wait(_queue->Sync());
				continue;
			}

			CallbackInfoPtr top = _queue->Top();
			if (top->GetTimeToTrigger() <= _monotonic.Elapsed())
			{
				_queue->Pop();

				{
					MutexUnlock ul(l);
					LocalExecutionGuard guard(top->GetExecutionTester());
					if (!guard)
					{
						top.reset();
						continue;
					}

					if (top->IsPeriodic())
						top->Restart(_monotonic.Elapsed());

					try
					{
						if (_profileCalls)
						{
							AsyncProfiler::Session profiler_session(ExecutorsProfiler::Instance().GetProfiler(), bind(&Timer::GetProfilerMessage, this, ref(top->GetFunc())), 10000, AsyncProfiler::Session::NameGetterTag());
							(top->GetFunc())();
						}
						else
							(top->GetFunc())();
					}
					catch(const std::exception &ex)
					{ _exceptionHandler(ex); }

					if (!top->IsPeriodic())
						top.reset();
				}

				if (top)
					_queue->Push(top);
			}
			else //top timer not triggered
			{
				const TimeDuration waitTime = top->GetTimeToTrigger() - _monotonic.Elapsed();
				top.reset();
				if (waitTime > TimeDuration())
					_cond.TimedWait(_queue->Sync(), waitTime);
			}
		}

		const TimeDuration currentTime = _monotonic.Elapsed();
		while (!_queue->IsEmpty())
		{
			CallbackInfoPtr top = _queue->Pop();

			if (top->GetTimeToTrigger() <= currentTime)
				break;

			MutexUnlock ul(l);
			LocalExecutionGuard guard(top->GetExecutionTester());
			if (!guard)
			{
				top.reset();
				continue;
			}

			try
			{
				if (_profileCalls)
				{
					AsyncProfiler::Session profiler_session(ExecutorsProfiler::Instance().GetProfiler(), bind(&Timer::GetProfilerMessage, this, ref(top->GetFunc())), 10000, AsyncProfiler::Session::NameGetterTag());
					(top->GetFunc())();
				}
				else
					(top->GetFunc())();
			}
			catch(const std::exception &ex)
			{ _exceptionHandler(ex); }

			top.reset();
		}
	}

	void Timer::DefaultExceptionHandler(const std::exception& ex)
	{ s_logger.Error() << "Timer func exception: " << ex; }

}
<commit_msg>Timer: fix destructor safety<commit_after>// Copyright (c) 2011 - 2017, GS Group, https://github.com/GSGroup
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
// provided that the above copyright notice and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

#include <stingraykit/timer/Timer.h>

#include <list>
#include <map>

#include <stingraykit/diagnostics/ExecutorsProfiler.h>
#include <stingraykit/function/CancellableFunction.h>
#include <stingraykit/function/bind.h>
#include <stingraykit/function/function_name_getter.h>
#include <stingraykit/log/Logger.h>
#include <stingraykit/time/ElapsedTime.h>
#include <stingraykit/TaskLifeToken.h>

namespace stingray
{

	namespace Detail
	{
		struct ITimerConnectionImpl
		{
			virtual ~ITimerConnectionImpl() { }

			virtual void Disconnect() = 0;
		};
		STINGRAYKIT_DECLARE_PTR(ITimerConnectionImpl);
	}

	class TimerConnectionToken : public virtual IToken
	{
		friend class Timer;

	private:
		Detail::ITimerConnectionImplPtr		_impl;

	public:
		TimerConnectionToken(const Detail::ITimerConnectionImplPtr& impl) : _impl(impl)
		{ }

		~TimerConnectionToken()
		{
			if (_impl)
			{
				_impl->Disconnect();
				_impl.reset();
			}
		}
	};

	class Timer::CallbackQueue
	{
		typedef std::list<CallbackInfoPtr>					ContainerInternal;
		typedef std::map<TimeDuration, ContainerInternal>	Container;

	private:
		Mutex			_mutex;
		Container		_container;

	public:
		typedef ContainerInternal::iterator iterator;

		inline Mutex &Sync()
		{ return _mutex; }

		inline bool IsEmpty() const
		{
			MutexLock l(_mutex);
			return _container.empty();
		}

		CallbackInfoPtr Top() const;
		void Push(CallbackInfoPtr ci);
		void Erase(const iterator & it);
		CallbackInfoPtr Pop();
	};

	class Timer::CallbackInfo : public virtual Detail::ITimerConnectionImpl
	{
		STINGRAYKIT_NONCOPYABLE(CallbackInfo);
		typedef function<void()>		FuncT;

	private:
		FuncT						_func;
		TimeDuration				_timeToTrigger;
		optional<TimeDuration>		_period;
		TaskLifeToken				_token;
		CallbackQueueWeakPtr		_queue;
		CallbackQueue::iterator		_iterator;
		bool						_iteratorIsValid;

	private:
		friend class CallbackQueue;

		void SetIterator(const CallbackQueue::iterator& it)		{ _iterator = it; _iteratorIsValid = true; }
		void ResetIterator()									{ _iteratorIsValid = false; }

	public:
		CallbackInfo(const FuncT& func, const TimeDuration& timeToTrigger, const optional<TimeDuration>& period, const CallbackQueuePtr& queue)
			: _func(func), _timeToTrigger(timeToTrigger), _period(period), _queue(queue), _iteratorIsValid(false)
		{ }

		const FuncT& GetFunc() const							{ return _func; }
		FutureExecutionTester GetExecutionTester() const 		{ return _token.GetExecutionTester(); }

		bool IsPeriodic() const									{ return _period.is_initialized(); }
		void Restart(const TimeDuration& currentTime)
		{
			STINGRAYKIT_CHECK(_period, "CallbackInfo::Restart internal error: _period is set!");
			_timeToTrigger = currentTime + *_period;
		}
		TimeDuration GetTimeToTrigger() const					{ return _timeToTrigger; }

		virtual void Disconnect()
		{
			CallbackQueuePtr qm = _queue.lock();
			if (qm)
			{
				MutexLock l(qm->Sync());
				if (_iteratorIsValid)
				{
					qm->Erase(_iterator);
					ResetIterator();
				}
			}
			_token.Release();
		}
	};

	Timer::CallbackInfoPtr Timer::CallbackQueue::Top() const
	{
		MutexLock l(_mutex);
		if (!_container.empty())
		{
			const ContainerInternal& listForTop = _container.begin()->second;
			STINGRAYKIT_CHECK(!listForTop.empty(), "try to get callback from empty list");
			return listForTop.front();
		}
		else
			return null;
	}

	void Timer::CallbackQueue::Push(CallbackInfoPtr ci)
	{
		MutexLock l(_mutex);
		ContainerInternal& listToInsert = _container[ci->GetTimeToTrigger()];
		ci->SetIterator(listToInsert.insert(listToInsert.end(), ci));
	}

	void Timer::CallbackQueue::Erase(const iterator & it)
	{
		MutexLock l(_mutex);
		TimeDuration keyToErase = (*it)->GetTimeToTrigger();
		ContainerInternal& listToErase = _container[keyToErase];
		listToErase.erase(it);
		if (listToErase.empty())
			_container.erase(keyToErase);
	}

	Timer::CallbackInfoPtr Timer::CallbackQueue::Pop()
	{
		MutexLock l(_mutex);
		STINGRAYKIT_CHECK(!_container.empty(), "popping callback from empty map");
		ContainerInternal& listToPop = _container.begin()->second;
		STINGRAYKIT_CHECK(!listToPop.empty(), "popping callback from empty list");

		CallbackInfoPtr ci = listToPop.front();
		listToPop.pop_front();
		if (listToPop.empty())
			_container.erase(ci->GetTimeToTrigger());
		ci->ResetIterator();
		return ci;
	}

	STINGRAYKIT_DEFINE_NAMED_LOGGER(Timer);

	Timer::Timer(const std::string& timerName, const ExceptionHandler& exceptionHandler, bool profileCalls)
		:	_timerName(timerName),
			_exceptionHandler(exceptionHandler),
			_profileCalls(profileCalls),
			_alive(true),
			_queue(make_shared<CallbackQueue>()),
			_worker(make_shared<Thread>(timerName, bind(&Timer::ThreadFunc, this, not_using(_1))))
	{ }

	Timer::~Timer()
	{
		{
			MutexLock l(_queue->Sync());
			_alive = false;
			_cond.Broadcast();
		}
		_worker.reset();

		MutexLock l(_queue->Sync());
		while(!_queue->IsEmpty())
		{
			CallbackInfoPtr top = _queue->Pop();

			MutexUnlock ul(l);
			LocalExecutionGuard guard(top->GetExecutionTester());

			top.reset();
			if (guard)
			{
				s_logger.Warning() << "killing timer " << _timerName << " which still has some functions to execute";
				break;
			}
		}
	}

	Token Timer::SetTimeout(const TimeDuration& timeout, const function<void()>& func)
	{
		MutexLock l(_queue->Sync());

		CallbackInfoPtr ci = make_shared<CallbackInfo>(func, _monotonic.Elapsed() + timeout, null, _queue);
		_queue->Push(ci);
		_cond.Broadcast();

		return MakeToken<TimerConnectionToken>(ci);
	}

	Token Timer::SetTimer(const TimeDuration& interval, const function<void()>& func)
	{ return SetTimer(interval, interval, func); }

	Token Timer::SetTimer(const TimeDuration& timeout, const TimeDuration& interval, const function<void()>& func)
	{
		MutexLock l(_queue->Sync());

		CallbackInfoPtr ci = make_shared<CallbackInfo>(func, _monotonic.Elapsed() + timeout, interval, _queue);
		_queue->Push(ci);
		_cond.Broadcast();

		return MakeToken<TimerConnectionToken>(ci);
	}

	void Timer::AddTask(const function<void()>& task, const FutureExecutionTester& tester)
	{
		MutexLock l(_queue->Sync());

		CallbackInfoPtr ci = make_shared<CallbackInfo>(MakeCancellableFunction(task, tester), _monotonic.Elapsed(), null, _queue);
		_queue->Push(ci);
		_cond.Broadcast();
	}

	std::string Timer::GetProfilerMessage(const function<void()>& func)
	{ return StringBuilder() % get_function_name(func) % " in Timer '" % _timerName % "'"; }

	void Timer::ThreadFunc()
	{
		MutexLock l(_queue->Sync());

		while (_alive)
		{
			if (_queue->IsEmpty())
			{
				_cond.Wait(_queue->Sync());
				continue;
			}

			CallbackInfoPtr top = _queue->Top();
			if (top->GetTimeToTrigger() <= _monotonic.Elapsed())
			{
				_queue->Pop();

				{
					MutexUnlock ul(l);
					LocalExecutionGuard guard(top->GetExecutionTester());
					if (!guard)
					{
						top.reset();
						continue;
					}

					if (top->IsPeriodic())
						top->Restart(_monotonic.Elapsed());

					try
					{
						if (_profileCalls)
						{
							AsyncProfiler::Session profiler_session(ExecutorsProfiler::Instance().GetProfiler(), bind(&Timer::GetProfilerMessage, this, ref(top->GetFunc())), 10000, AsyncProfiler::Session::NameGetterTag());
							(top->GetFunc())();
						}
						else
							(top->GetFunc())();
					}
					catch(const std::exception &ex)
					{ _exceptionHandler(ex); }

					if (!top->IsPeriodic())
						top.reset();
				}

				if (top)
					_queue->Push(top);
			}
			else //top timer not triggered
			{
				const TimeDuration waitTime = top->GetTimeToTrigger() - _monotonic.Elapsed();
				top.reset();
				if (waitTime > TimeDuration())
					_cond.TimedWait(_queue->Sync(), waitTime);
			}
		}

		const TimeDuration currentTime = _monotonic.Elapsed();
		while (!_queue->IsEmpty())
		{
			CallbackInfoPtr top = _queue->Pop();

			if (top->GetTimeToTrigger() <= currentTime)
				break;

			MutexUnlock ul(l);
			LocalExecutionGuard guard(top->GetExecutionTester());
			if (!guard)
			{
				top.reset();
				continue;
			}

			try
			{
				if (_profileCalls)
				{
					AsyncProfiler::Session profiler_session(ExecutorsProfiler::Instance().GetProfiler(), bind(&Timer::GetProfilerMessage, this, ref(top->GetFunc())), 10000, AsyncProfiler::Session::NameGetterTag());
					(top->GetFunc())();
				}
				else
					(top->GetFunc())();
			}
			catch(const std::exception &ex)
			{ _exceptionHandler(ex); }

			top.reset();
		}
	}

	void Timer::DefaultExceptionHandler(const std::exception& ex)
	{ s_logger.Error() << "Timer func exception: " << ex; }

}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkChartLegend.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkChartLegend.h"

#include "vtkContext2D.h"
#include "vtkPen.h"
#include "vtkBrush.h"
#include "vtkChart.h"
#include "vtkPlot.h"
#include "vtkTextProperty.h"
#include "vtkStdString.h"
#include "vtkVector.h"
#include "vtkWeakPointer.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"
#include "vtkContextScene.h"
#include "vtkContextMouseEvent.h"

#include "vtkObjectFactory.h"

#include <vector>

//-----------------------------------------------------------------------------
class vtkChartLegend::Private
{
public:
  Private()
  {
  }
  ~Private()
  {
  }

  vtkVector2f Point;
  vtkWeakPointer<vtkChart> Chart;
  std::vector<vtkPlot*> ActivePlots;
};

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkChartLegend);

//-----------------------------------------------------------------------------
vtkChartLegend::vtkChartLegend()
{
  this->Storage = new vtkChartLegend::Private;
  this->Point = this->Storage->Point.GetData();
  // Defaults to 12pt text, with top, right alignment to the specified point.
  this->LabelProperties->SetFontSize(12);
  this->LabelProperties->SetColor(0.0, 0.0, 0.0);
  this->LabelProperties->SetJustificationToLeft();
  this->LabelProperties->SetVerticalJustificationToBottom();

  this->Pen->SetColor(0, 0, 0);
  this->Brush->SetColor(255, 255, 255, 255);
  this->HorizontalAlignment = vtkChartLegend::RIGHT;
  this->VerticalAlignment = vtkChartLegend::TOP;

  this->Padding = 5;
  this->SymbolWidth = 25;
  this->Inline = true;
  this->Button = -1;
  this->DragEnabled = true;
}

//-----------------------------------------------------------------------------
vtkChartLegend::~vtkChartLegend()
{
  delete this->Storage;
  this->Storage = NULL;
  this->Point = NULL;
}

//-----------------------------------------------------------------------------
void vtkChartLegend::Update()
{
  this->Storage->ActivePlots.clear();
  for (int i = 0; i < this->Storage->Chart->GetNumberOfPlots(); ++i)
    {
    if (this->Storage->Chart->GetPlot(i)->GetVisible()
        && this->Storage->Chart->GetPlot(i)->GetLabel().length() > 0)
      {
      this->Storage->ActivePlots.push_back(this->Storage->Chart->GetPlot(i));
      }
    // If we have a plot with multiple labels, we generally only want to show
    // the labels/legend symbols for the first one. So truncate at the first
    // one we encounter.
    if (this->Storage->Chart->GetPlot(i)->GetLabels() &&
        this->Storage->Chart->GetPlot(i)->GetLabels()->GetNumberOfTuples() > 1)
      {
      break;
      }
    }
  this->PlotTime.Modified();
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::Paint(vtkContext2D *painter)
{
  // This is where everything should be drawn, or dispatched to other methods.
  vtkDebugMacro(<< "Paint event called in vtkChartLegend.");

  if (!this->Visible || this->Storage->ActivePlots.size() == 0)
    {
    return true;
    }

  this->GetBoundingRect(painter);

  // Now draw a box for the legend.
  painter->ApplyPen(this->Pen.GetPointer());
  painter->ApplyBrush(this->Brush.GetPointer());
  painter->DrawRect(this->Rect.X(), this->Rect.Y(),
                    this->Rect.Width(), this->Rect.Height());

  painter->ApplyTextProp(this->LabelProperties.GetPointer());

  vtkVector2f stringBounds[2];
  painter->ComputeStringBounds("Tgyf", stringBounds->GetData());
  float height = stringBounds[1].GetY();
  painter->ComputeStringBounds("The", stringBounds->GetData());
  float baseHeight = stringBounds[1].GetY();

  vtkVector2f pos(this->Rect.X() + this->Padding + this->SymbolWidth,
                  this->Rect.Y() + this->Rect.Height() - this->Padding - floor(height));
  vtkRectf rect(this->Rect.X() + this->Padding, pos.Y(),
               this->SymbolWidth-3, ceil(height));

  // Draw all of the legend labels and marks
  for(size_t i = 0; i < this->Storage->ActivePlots.size(); ++i)
    {
    vtkStringArray *labels = this->Storage->ActivePlots[i]->GetLabels();
    for (vtkIdType l = 0; labels && (l < labels->GetNumberOfValues()); ++l)
      {
      // This is fairly hackish, but gets the text looking reasonable...
      // Calculate a height for a "normal" string, then if this height is greater
      // that offset is used to move it down. Effectively hacking in a text
      // base line until better support is in the text rendering code...
      // There are still several one pixel glitches, but it looks better than
      // using the default vertical alignment. FIXME!
      vtkStdString testString = labels->GetValue(l);
      testString += "T";
      painter->ComputeStringBounds(testString, stringBounds->GetData());
      painter->DrawString(pos.X(), rect.Y() + (baseHeight-stringBounds[1].Y()),
                          labels->GetValue(l));

      // Paint the legend mark and increment out y value.
      this->Storage->ActivePlots[i]->PaintLegend(painter, rect, l);
      rect.SetY(rect.Y() - height - this->Padding);
      }
    }

  return true;
}

//-----------------------------------------------------------------------------
vtkRectf vtkChartLegend::GetBoundingRect(vtkContext2D *painter)
{
  if (this->RectTime > this->GetMTime() && this->RectTime > this->PlotTime)
    {
    return this->Rect;
    }

  painter->ApplyTextProp(this->LabelProperties.GetPointer());

  vtkVector2f stringBounds[2];
  painter->ComputeStringBounds("Tgyf", stringBounds->GetData());
  float height = stringBounds[1].GetY();
  float maxWidth = 0.0f;

  // Calculate the widest legend label - needs the context to calculate font
  // metrics, but these could be cached.
  for(size_t i = 0; i < this->Storage->ActivePlots.size(); ++i)
    {
    vtkStringArray *labels = this->Storage->ActivePlots[i]->GetLabels();
    for (vtkIdType l = 0; labels && (l < labels->GetNumberOfTuples()); ++l)
      {
      painter->ComputeStringBounds(labels->GetValue(l),
                                   stringBounds->GetData());
      if (stringBounds[1].X() > maxWidth)
        {
        maxWidth = stringBounds[1].X();
        }
      }
    }

  // Figure out the size of the legend box and store locally.
  int numLabels = 0;
  for(size_t i = 0; i < this->Storage->ActivePlots.size(); ++i)
    {
    numLabels += this->Storage->ActivePlots[i]->GetNumberOfLabels();
    }

  // Default point placement is bottom left.
  this->Rect = vtkRectf(floor(this->Storage->Point.X()),
                        floor(this->Storage->Point.Y()),
                        ceil(maxWidth + 2 * this->Padding + this->SymbolWidth),
                        ceil((numLabels * (height + this->Padding)) + this->Padding));

  this->RectTime.Modified();
  return this->Rect;
}

//-----------------------------------------------------------------------------
void vtkChartLegend::SetPoint(const vtkVector2f &point)
{
  this->Storage->Point = point;
  this->Modified();
}

//-----------------------------------------------------------------------------
const vtkVector2f& vtkChartLegend::GetPointVector()
{
  return this->Storage->Point;
}

//-----------------------------------------------------------------------------
void vtkChartLegend::SetLabelSize(int size)
{
  this->LabelProperties->SetFontSize(size);
}

//-----------------------------------------------------------------------------
int vtkChartLegend::GetLabelSize()
{
  return this->LabelProperties->GetFontSize();
}

//-----------------------------------------------------------------------------
vtkPen * vtkChartLegend::GetPen()
{
  return this->Pen.GetPointer();
}

//-----------------------------------------------------------------------------
vtkBrush * vtkChartLegend::GetBrush()
{
  return this->Brush.GetPointer();
}

//-----------------------------------------------------------------------------
vtkTextProperty * vtkChartLegend::GetLabelProperties()
{
  return this->LabelProperties.GetPointer();
}

//-----------------------------------------------------------------------------
void vtkChartLegend::SetChart(vtkChart* chart)
{
  if (this->Storage->Chart == chart)
    {
    return;
    }
  else
    {
    this->Storage->Chart = chart;
    this->Modified();
    }
}

//-----------------------------------------------------------------------------
vtkChart* vtkChartLegend::GetChart()
{
  return this->Storage->Chart;
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::Hit(const vtkContextMouseEvent &mouse)
{
  if (this->DragEnabled && mouse.ScreenPos.X() > this->Rect.X() &&
      mouse.ScreenPos.X() < this->Rect.X() + this->Rect.Width() &&
      mouse.ScreenPos.Y() > this->Rect.Y() &&
      mouse.ScreenPos.Y() < this->Rect.Y() + this->Rect.Height())
    {
    return true;
    }
  else
    {
    return false;
    }
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::MouseMoveEvent(const vtkContextMouseEvent &mouse)
{
  if (this->Button == vtkContextMouseEvent::LEFT_BUTTON)
    {
    vtkVector2f delta = mouse.ScenePos - mouse.LastScenePos;
    this->HorizontalAlignment = vtkChartLegend::CUSTOM;
    this->Storage->Point = this->Storage->Point + delta;
    this->GetScene()->SetDirty(true);
    }
  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::MouseButtonPressEvent(const vtkContextMouseEvent &mouse)
{
  if (mouse.Button == vtkContextMouseEvent::LEFT_BUTTON)
    {
    this->Button = vtkContextMouseEvent::LEFT_BUTTON;
    return true;
    }
  return false;
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::MouseButtonReleaseEvent(const vtkContextMouseEvent &mouse)
{
  this->Button = -1;
  return true;
}

//-----------------------------------------------------------------------------
void vtkChartLegend::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<commit_msg>COMP: Fixed compiler warning about unused variable.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkChartLegend.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkChartLegend.h"

#include "vtkContext2D.h"
#include "vtkPen.h"
#include "vtkBrush.h"
#include "vtkChart.h"
#include "vtkPlot.h"
#include "vtkTextProperty.h"
#include "vtkStdString.h"
#include "vtkVector.h"
#include "vtkWeakPointer.h"
#include "vtkSmartPointer.h"
#include "vtkStringArray.h"
#include "vtkContextScene.h"
#include "vtkContextMouseEvent.h"

#include "vtkObjectFactory.h"

#include <vector>

//-----------------------------------------------------------------------------
class vtkChartLegend::Private
{
public:
  Private()
  {
  }
  ~Private()
  {
  }

  vtkVector2f Point;
  vtkWeakPointer<vtkChart> Chart;
  std::vector<vtkPlot*> ActivePlots;
};

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkChartLegend);

//-----------------------------------------------------------------------------
vtkChartLegend::vtkChartLegend()
{
  this->Storage = new vtkChartLegend::Private;
  this->Point = this->Storage->Point.GetData();
  // Defaults to 12pt text, with top, right alignment to the specified point.
  this->LabelProperties->SetFontSize(12);
  this->LabelProperties->SetColor(0.0, 0.0, 0.0);
  this->LabelProperties->SetJustificationToLeft();
  this->LabelProperties->SetVerticalJustificationToBottom();

  this->Pen->SetColor(0, 0, 0);
  this->Brush->SetColor(255, 255, 255, 255);
  this->HorizontalAlignment = vtkChartLegend::RIGHT;
  this->VerticalAlignment = vtkChartLegend::TOP;

  this->Padding = 5;
  this->SymbolWidth = 25;
  this->Inline = true;
  this->Button = -1;
  this->DragEnabled = true;
}

//-----------------------------------------------------------------------------
vtkChartLegend::~vtkChartLegend()
{
  delete this->Storage;
  this->Storage = NULL;
  this->Point = NULL;
}

//-----------------------------------------------------------------------------
void vtkChartLegend::Update()
{
  this->Storage->ActivePlots.clear();
  for (int i = 0; i < this->Storage->Chart->GetNumberOfPlots(); ++i)
    {
    if (this->Storage->Chart->GetPlot(i)->GetVisible()
        && this->Storage->Chart->GetPlot(i)->GetLabel().length() > 0)
      {
      this->Storage->ActivePlots.push_back(this->Storage->Chart->GetPlot(i));
      }
    // If we have a plot with multiple labels, we generally only want to show
    // the labels/legend symbols for the first one. So truncate at the first
    // one we encounter.
    if (this->Storage->Chart->GetPlot(i)->GetLabels() &&
        this->Storage->Chart->GetPlot(i)->GetLabels()->GetNumberOfTuples() > 1)
      {
      break;
      }
    }
  this->PlotTime.Modified();
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::Paint(vtkContext2D *painter)
{
  // This is where everything should be drawn, or dispatched to other methods.
  vtkDebugMacro(<< "Paint event called in vtkChartLegend.");

  if (!this->Visible || this->Storage->ActivePlots.size() == 0)
    {
    return true;
    }

  this->GetBoundingRect(painter);

  // Now draw a box for the legend.
  painter->ApplyPen(this->Pen.GetPointer());
  painter->ApplyBrush(this->Brush.GetPointer());
  painter->DrawRect(this->Rect.X(), this->Rect.Y(),
                    this->Rect.Width(), this->Rect.Height());

  painter->ApplyTextProp(this->LabelProperties.GetPointer());

  vtkVector2f stringBounds[2];
  painter->ComputeStringBounds("Tgyf", stringBounds->GetData());
  float height = stringBounds[1].GetY();
  painter->ComputeStringBounds("The", stringBounds->GetData());
  float baseHeight = stringBounds[1].GetY();

  vtkVector2f pos(this->Rect.X() + this->Padding + this->SymbolWidth,
                  this->Rect.Y() + this->Rect.Height() - this->Padding - floor(height));
  vtkRectf rect(this->Rect.X() + this->Padding, pos.Y(),
               this->SymbolWidth-3, ceil(height));

  // Draw all of the legend labels and marks
  for(size_t i = 0; i < this->Storage->ActivePlots.size(); ++i)
    {
    vtkStringArray *labels = this->Storage->ActivePlots[i]->GetLabels();
    for (vtkIdType l = 0; labels && (l < labels->GetNumberOfValues()); ++l)
      {
      // This is fairly hackish, but gets the text looking reasonable...
      // Calculate a height for a "normal" string, then if this height is greater
      // that offset is used to move it down. Effectively hacking in a text
      // base line until better support is in the text rendering code...
      // There are still several one pixel glitches, but it looks better than
      // using the default vertical alignment. FIXME!
      vtkStdString testString = labels->GetValue(l);
      testString += "T";
      painter->ComputeStringBounds(testString, stringBounds->GetData());
      painter->DrawString(pos.X(), rect.Y() + (baseHeight-stringBounds[1].Y()),
                          labels->GetValue(l));

      // Paint the legend mark and increment out y value.
      this->Storage->ActivePlots[i]->PaintLegend(painter, rect, l);
      rect.SetY(rect.Y() - height - this->Padding);
      }
    }

  return true;
}

//-----------------------------------------------------------------------------
vtkRectf vtkChartLegend::GetBoundingRect(vtkContext2D *painter)
{
  if (this->RectTime > this->GetMTime() && this->RectTime > this->PlotTime)
    {
    return this->Rect;
    }

  painter->ApplyTextProp(this->LabelProperties.GetPointer());

  vtkVector2f stringBounds[2];
  painter->ComputeStringBounds("Tgyf", stringBounds->GetData());
  float height = stringBounds[1].GetY();
  float maxWidth = 0.0f;

  // Calculate the widest legend label - needs the context to calculate font
  // metrics, but these could be cached.
  for(size_t i = 0; i < this->Storage->ActivePlots.size(); ++i)
    {
    vtkStringArray *labels = this->Storage->ActivePlots[i]->GetLabels();
    for (vtkIdType l = 0; labels && (l < labels->GetNumberOfTuples()); ++l)
      {
      painter->ComputeStringBounds(labels->GetValue(l),
                                   stringBounds->GetData());
      if (stringBounds[1].X() > maxWidth)
        {
        maxWidth = stringBounds[1].X();
        }
      }
    }

  // Figure out the size of the legend box and store locally.
  int numLabels = 0;
  for(size_t i = 0; i < this->Storage->ActivePlots.size(); ++i)
    {
    numLabels += this->Storage->ActivePlots[i]->GetNumberOfLabels();
    }

  // Default point placement is bottom left.
  this->Rect = vtkRectf(floor(this->Storage->Point.X()),
                        floor(this->Storage->Point.Y()),
                        ceil(maxWidth + 2 * this->Padding + this->SymbolWidth),
                        ceil((numLabels * (height + this->Padding)) + this->Padding));

  this->RectTime.Modified();
  return this->Rect;
}

//-----------------------------------------------------------------------------
void vtkChartLegend::SetPoint(const vtkVector2f &point)
{
  this->Storage->Point = point;
  this->Modified();
}

//-----------------------------------------------------------------------------
const vtkVector2f& vtkChartLegend::GetPointVector()
{
  return this->Storage->Point;
}

//-----------------------------------------------------------------------------
void vtkChartLegend::SetLabelSize(int size)
{
  this->LabelProperties->SetFontSize(size);
}

//-----------------------------------------------------------------------------
int vtkChartLegend::GetLabelSize()
{
  return this->LabelProperties->GetFontSize();
}

//-----------------------------------------------------------------------------
vtkPen * vtkChartLegend::GetPen()
{
  return this->Pen.GetPointer();
}

//-----------------------------------------------------------------------------
vtkBrush * vtkChartLegend::GetBrush()
{
  return this->Brush.GetPointer();
}

//-----------------------------------------------------------------------------
vtkTextProperty * vtkChartLegend::GetLabelProperties()
{
  return this->LabelProperties.GetPointer();
}

//-----------------------------------------------------------------------------
void vtkChartLegend::SetChart(vtkChart* chart)
{
  if (this->Storage->Chart == chart)
    {
    return;
    }
  else
    {
    this->Storage->Chart = chart;
    this->Modified();
    }
}

//-----------------------------------------------------------------------------
vtkChart* vtkChartLegend::GetChart()
{
  return this->Storage->Chart;
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::Hit(const vtkContextMouseEvent &mouse)
{
  if (this->DragEnabled && mouse.ScreenPos.X() > this->Rect.X() &&
      mouse.ScreenPos.X() < this->Rect.X() + this->Rect.Width() &&
      mouse.ScreenPos.Y() > this->Rect.Y() &&
      mouse.ScreenPos.Y() < this->Rect.Y() + this->Rect.Height())
    {
    return true;
    }
  else
    {
    return false;
    }
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::MouseMoveEvent(const vtkContextMouseEvent &mouse)
{
  if (this->Button == vtkContextMouseEvent::LEFT_BUTTON)
    {
    vtkVector2f delta = mouse.ScenePos - mouse.LastScenePos;
    this->HorizontalAlignment = vtkChartLegend::CUSTOM;
    this->Storage->Point = this->Storage->Point + delta;
    this->GetScene()->SetDirty(true);
    }
  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::MouseButtonPressEvent(const vtkContextMouseEvent &mouse)
{
  if (mouse.Button == vtkContextMouseEvent::LEFT_BUTTON)
    {
    this->Button = vtkContextMouseEvent::LEFT_BUTTON;
    return true;
    }
  return false;
}

//-----------------------------------------------------------------------------
bool vtkChartLegend::MouseButtonReleaseEvent(const vtkContextMouseEvent &)
{
  this->Button = -1;
  return true;
}

//-----------------------------------------------------------------------------
void vtkChartLegend::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  int a, b, c;
  string s;
  cin >> a >> b >> c >> s;
  while (true) {
    // nothing
  }
}
<commit_msg>tried A3.cpp to 'A'<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int main () {
  int a, b, c;
  string s;
  cin >> a >> b >> c >> s;
  while (true) {
    cerr << "aaa" << endl;
    // nothing
  }
}
<|endoftext|>


<commit_before>/***************************************************************************
                          optionconverter.cpp  -  class OptionConverter
                             -------------------
    begin                : mer avr 30 2003
    copyright            : (C) 2003 by Michael CATANZARITI
    email                : mcatan@free.fr
 ***************************************************************************/

/***************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.      *
 *                                                                         *
 * This software is published under the terms of the Apache Software       *
 * License version 1.1, a copy of which has been included with this        *
 * distribution in the LICENSE.txt file.                                   *
 ***************************************************************************/

#include <log4cxx/helpers/optionconverter.h>
#include <algorithm>
#include <ctype.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/exception.h>
#include <stdlib.h>
#include <log4cxx/helpers/properties.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/level.h>
#include <log4cxx/helpers/object.h>
#include <log4cxx/helpers/class.h>
#include <log4cxx/helpers/loader.h>
#include <log4cxx/helpers/system.h>

using namespace log4cxx;
using namespace log4cxx::helpers;

tstring OptionConverter::DELIM_START = _T("${");
TCHAR OptionConverter::DELIM_STOP  = _T('}');
int OptionConverter::DELIM_START_LEN = 2;
int OptionConverter::DELIM_STOP_LEN  = 1;

namespace {
    // Function object to turn a lower case character into an upper case one
    class ToUpper {
    public:
        void operator()(TCHAR& c){c = toupper(c);}
    };
}

bool OptionConverter::toBoolean(const tstring& value, bool dEfault)
{
	if (value.empty())
	{
		return dEfault;
	}

	tstring trimmedVal = StringHelper::toLowerCase(StringHelper::trim(value));

	if (trimmedVal == _T("true"))
	{
		return true;
	}
	if (trimmedVal == _T("false"))
	{
		return false;
	}

	return dEfault;
}

int OptionConverter::toInt(const tstring& value, int dEfault)
{
	if (value.empty())
	{
		return dEfault;
	}

	return (int)ttol(StringHelper::trim(value).c_str());
}

long OptionConverter::toFileSize(const tstring& value, long dEfault)
{
	if(value.empty())
	{
		return dEfault;
	}

	tstring s = StringHelper::toLowerCase(StringHelper::trim(value));

	long multiplier = 1;
	int index;

	if((index = s.find(_T("kb"))) != -1)
	{
		multiplier = 1024;
		s = s.substr(0, index);
	}
	else if((index = s.find(_T("mb"))) != -1)
	{
		multiplier = 1024*1024;
		s = s.substr(0, index);
	}
	else if((index = s.find(_T("gb"))) != -1)
	{
		multiplier = 1024*1024*1024;
		s = s.substr(0, index);
	}
	if(!s.empty())
	{
		return ttol(s.c_str()) * multiplier;
	}

	return dEfault;
}

tstring OptionConverter::findAndSubst(const tstring& key, Properties& props)
{
	tstring value = props.getProperty(key);

	if(value.empty())
		return value;

	try
	{
		return substVars(value, props);
	}
	catch(IllegalArgumentException& e)
	{
		LogLog::error(_T("Bad option value [")+value+_T("]."), e);
		return value;
	}
}

tstring OptionConverter::substVars(const tstring& val, Properties& props)
{
	tostringstream sbuf;

	int i = 0;
	int j, k;

	while(true)
	{
		j = val.find(DELIM_START, i);
		if(j == -1)
		{
			// no more variables
			if(i==0)
			{ // this is a simple string
				return val;
			}
			else
			{ // add the tail string which contails no variables and return the result.
				sbuf << val.substr(i, val.length() - i);
				return sbuf.str();
			}
		}
		else
		{
			sbuf << val.substr(i, j - i);
			k = val.find(DELIM_STOP, j);
			if(k == -1)
			{
				tostringstream oss;
				oss << _T("\"") << val
					<< _T("\" has no closing brace. Opening brace at position ")
					<< j << _T(".");
				throw new IllegalArgumentException(oss.str());
			}
			else
			{
				j += DELIM_START_LEN;
				tstring key = val.substr(j, k - j);
				// first try in System properties
				tstring replacement = getSystemProperty(key, _T(""));
				// then try props parameter
				if(replacement.empty())
				{
					replacement = props.getProperty(key);
				}

				if(!replacement.empty())
				{
					// Do variable substitution on the replacement string
					// such that we can solve "Hello ${x2}" as "Hello p1"
					// the where the properties are
					// x1=p1
					// x2=${x1}
					tstring recursiveReplacement = substVars(replacement, props);
					sbuf << (recursiveReplacement);
				}
				i = k + DELIM_STOP_LEN;
			}
		}
	}
}

tstring OptionConverter::getSystemProperty(const tstring& key, const tstring& def)
{
	if (!key.empty())
	{
		tstring value = System::getProperty(def);

		if (!value.empty())
		{
			return value;
		}
		else
		{
			return def;
		}
	}
	else
	{
		return def;
	}
}

const Level& OptionConverter::toLevel(const tstring& value, const Level& defaultValue)
{
	return Level::toLevel(value, defaultValue);
}

ObjectPtr OptionConverter::instantiateByKey(Properties& props, const tstring& key,
	const Class& superClass, ObjectPtr defaultValue)
{
	// Get the value of the property in string form
	tstring className = findAndSubst(key, props);
	if(className.empty())
	{
		LogLog::error(_T("Could not find value for key ") + key);
		return defaultValue;
	}

	tstring::size_type pos = className.find_last_of(_T('.'));
	if (pos != tstring::npos)
	{
		className = className.substr(pos + 1);
	}

	// Trim className to avoid trailing spaces that cause problems.
	return OptionConverter::instantiateByClassName(
		StringHelper::trim(className), superClass, defaultValue);
}

ObjectPtr OptionConverter::instantiateByClassName(const tstring& className,
	const Class& superClass, ObjectPtr defaultValue)
{
	if(!className.empty())
	{
		try
		{
			const Class& classObj = Loader::loadClass(className);
			ObjectPtr newObject =  classObj.newInstance();
			if (!newObject->instanceof(superClass))
			{
				return defaultValue;
			}

			return newObject;
		}
		catch (Exception& e)
		{
			LogLog::error(_T("Could not instantiate class [") + className
				+ _T("]."), e);
		}
	}
	return defaultValue;
}
<commit_msg>added missing features from log4j<commit_after>/***************************************************************************
                          optionconverter.cpp  -  class OptionConverter
                             -------------------
    begin                : mer avr 30 2003
    copyright            : (C) 2003 by Michael CATANZARITI
    email                : mcatan@free.fr
 ***************************************************************************/

/***************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.      *
 *                                                                         *
 * This software is published under the terms of the Apache Software       *
 * License version 1.1, a copy of which has been included with this        *
 * distribution in the LICENSE.txt file.                                   *
 ***************************************************************************/

#include <log4cxx/spi/loggerfactory.h>
#include <log4cxx/spi/loggerrepository.h>
#include <log4cxx/helpers/optionconverter.h>
#include <algorithm>
#include <ctype.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/exception.h>
#include <stdlib.h>
#include <log4cxx/helpers/properties.h>
#include <log4cxx/helpers/loglog.h>
#include <log4cxx/level.h>
#include <log4cxx/helpers/object.h>
#include <log4cxx/helpers/class.h>
#include <log4cxx/helpers/loader.h>
#include <log4cxx/helpers/system.h>
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/xml/domconfigurator.h>

using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::spi;
using namespace log4cxx::xml;

tstring OptionConverter::DELIM_START = _T("${");
TCHAR OptionConverter::DELIM_STOP  = _T('}');
int OptionConverter::DELIM_START_LEN = 2;
int OptionConverter::DELIM_STOP_LEN  = 1;

namespace {
    // Function object to turn a lower case character into an upper case one
    class ToUpper {
    public:
        void operator()(TCHAR& c){c = toupper(c);}
    };
}

tstring OptionConverter::convertSpecialChars(const tstring& s)
{
	TCHAR c;
    int len = s.length();
    tostringstream sbuf;

	tstring::const_iterator i = s.begin();
    while(i != s.end())
	{
		c = *i++;
		if (c == _T('\\'))
		{
			c =  *i++;

			switch (c)
			{
			case _T('n'):
				c = _T('\n');
				break;

			case _T('r'):
				c = _T('\r');
				break;

			case _T('t'):
				c = _T('\t');
				break;

			case _T('f'):
				c = _T('\f');
				break;

			case _T('\b'):
				c = _T('\b');
				break;

			case _T('\"'):
				c = _T('\"');
				break;

			case _T('\''):
				c = _T('\'');
				break;

			case _T('\\'):
				c = _T('\\');
				break;
			}
		}
		sbuf.put(c);
    }
    return sbuf.str();
}

bool OptionConverter::toBoolean(const tstring& value, bool dEfault)
{
	if (value.empty())
	{
		return dEfault;
	}

	tstring trimmedVal = StringHelper::toLowerCase(StringHelper::trim(value));

	if (trimmedVal == _T("true"))
	{
		return true;
	}
	if (trimmedVal == _T("false"))
	{
		return false;
	}

	return dEfault;
}

int OptionConverter::toInt(const tstring& value, int dEfault)
{
	if (value.empty())
	{
		return dEfault;
	}

	return (int)ttol(StringHelper::trim(value).c_str());
}

long OptionConverter::toFileSize(const tstring& value, long dEfault)
{
	if(value.empty())
	{
		return dEfault;
	}

	tstring s = StringHelper::toLowerCase(StringHelper::trim(value));

	long multiplier = 1;
	int index;

	if((index = s.find(_T("kb"))) != -1)
	{
		multiplier = 1024;
		s = s.substr(0, index);
	}
	else if((index = s.find(_T("mb"))) != -1)
	{
		multiplier = 1024*1024;
		s = s.substr(0, index);
	}
	else if((index = s.find(_T("gb"))) != -1)
	{
		multiplier = 1024*1024*1024;
		s = s.substr(0, index);
	}
	if(!s.empty())
	{
		return ttol(s.c_str()) * multiplier;
	}

	return dEfault;
}

tstring OptionConverter::findAndSubst(const tstring& key, Properties& props)
{
	tstring value = props.getProperty(key);

	if(value.empty())
		return value;

	try
	{
		return substVars(value, props);
	}
	catch(IllegalArgumentException& e)
	{
		LogLog::error(_T("Bad option value [")+value+_T("]."), e);
		return value;
	}
}

tstring OptionConverter::substVars(const tstring& val, Properties& props)
{
	tostringstream sbuf;

	int i = 0;
	int j, k;

	while(true)
	{
		j = val.find(DELIM_START, i);
		if(j == -1)
		{
			// no more variables
			if(i==0)
			{ // this is a simple string
				return val;
			}
			else
			{ // add the tail string which contails no variables and return the result.
				sbuf << val.substr(i, val.length() - i);
				return sbuf.str();
			}
		}
		else
		{
			sbuf << val.substr(i, j - i);
			k = val.find(DELIM_STOP, j);
			if(k == -1)
			{
				tostringstream oss;
				oss << _T("\"") << val
					<< _T("\" has no closing brace. Opening brace at position ")
					<< j << _T(".");
				throw new IllegalArgumentException(oss.str());
			}
			else
			{
				j += DELIM_START_LEN;
				tstring key = val.substr(j, k - j);
				// first try in System properties
				tstring replacement = getSystemProperty(key, _T(""));
				// then try props parameter
				if(replacement.empty())
				{
					replacement = props.getProperty(key);
				}

				if(!replacement.empty())
				{
					// Do variable substitution on the replacement string
					// such that we can solve "Hello ${x2}" as "Hello p1"
					// the where the properties are
					// x1=p1
					// x2=${x1}
					tstring recursiveReplacement = substVars(replacement, props);
					sbuf << (recursiveReplacement);
				}
				i = k + DELIM_STOP_LEN;
			}
		}
	}
}

tstring OptionConverter::getSystemProperty(const tstring& key, const tstring& def)
{
	if (!key.empty())
	{
		tstring value = System::getProperty(def);

		if (!value.empty())
		{
			return value;
		}
		else
		{
			return def;
		}
	}
	else
	{
		return def;
	}
}

const Level& OptionConverter::toLevel(const tstring& value, const Level& defaultValue)
{
	return Level::toLevel(value, defaultValue);
}

ObjectPtr OptionConverter::instantiateByKey(Properties& props, const tstring& key,
	const Class& superClass, ObjectPtr defaultValue)
{
	// Get the value of the property in string form
	tstring className = findAndSubst(key, props);
	if(className.empty())
	{
		LogLog::error(_T("Could not find value for key ") + key);
		return defaultValue;
	}

	tstring::size_type pos = className.find_last_of(_T('.'));
	if (pos != tstring::npos)
	{
		className = className.substr(pos + 1);
	}

	// Trim className to avoid trailing spaces that cause problems.
	return OptionConverter::instantiateByClassName(
		StringHelper::trim(className), superClass, defaultValue);
}

ObjectPtr OptionConverter::instantiateByClassName(const tstring& className,
	const Class& superClass, ObjectPtr defaultValue)
{
	if(!className.empty())
	{
		try
		{
			const Class& classObj = Loader::loadClass(className);
			ObjectPtr newObject =  classObj.newInstance();
			if (!newObject->instanceof(superClass))
			{
				return defaultValue;
			}

			return newObject;
		}
		catch (Exception& e)
		{
			LogLog::error(_T("Could not instantiate class [") + className
				+ _T("]."), e);
		}
	}
	return defaultValue;
}

void OptionConverter::selectAndConfigure(const tstring& configFileName,
	 const tstring& _clazz, spi::LoggerRepositoryPtr hierarchy)
{
	ConfiguratorPtr configurator;
	tstring clazz = _clazz;

	if(clazz.empty() && !configFileName.empty()
		&& StringHelper::endsWith(configFileName, _T(".xml")))
	{
		clazz = DOMConfigurator::getStaticClass().toString();
	}

	if(!clazz.empty())
	{
		LogLog::debug(_T("Preferred configurator class: ") + clazz);
		configurator = instantiateByClassName(clazz,
			Configurator::getStaticClass(),
			0);
		if(configurator == 0)
		{
			LogLog::error(_T("Could not instantiate configurator [")+
				clazz+_T("]."));
			return;
		}
	}
	else
	{
		configurator = new PropertyConfigurator();
	}

	configurator->doConfigure(configFileName, hierarchy);
}
<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's 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.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation 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.
//
//M*/

#ifndef __OPENCV_GPU_COMMON_HPP__
#define __OPENCV_GPU_COMMON_HPP__

#include <cuda_runtime.h>
#include "opencv2/core/cuda_devptrs.hpp"

#ifndef CV_PI
    #define CV_PI   3.1415926535897932384626433832795
#endif

#ifndef CV_PI_F
    #ifndef CV_PI
        #define CV_PI_F 3.14159265f
    #else
        #define CV_PI_F ((float)CV_PI)
    #endif
#endif

#if defined(__GNUC__)
    #define cudaSafeCall(expr)  ___cudaSafeCall(expr, __FILE__, __LINE__, __func__)
#else /* defined(__CUDACC__) || defined(__MSVC__) */
    #define cudaSafeCall(expr)  ___cudaSafeCall(expr, __FILE__, __LINE__)
#endif

namespace cv { namespace gpu
{
    void error(const char *error_string, const char *file, const int line, const char *func);

    template <typename T> static inline bool isAligned(const T* ptr, size_t size)
    {
        return reinterpret_cast<size_t>(ptr) % size == 0;
    }

    static inline bool isAligned(size_t step, size_t size)
    {
        return step % size == 0;
    }
}}

static inline void ___cudaSafeCall(cudaError_t err, const char *file, const int line, const char *func = "")
{
    if (cudaSuccess != err)
        cv::gpu::error(cudaGetErrorString(err), file, line, func);
}

namespace cv { namespace gpu
{
    __host__ __device__ __forceinline__ int divUp(int total, int grain)
    {
        return (total + grain - 1) / grain;
    }

    namespace device
    {
        using cv::gpu::divUp;

#ifdef __CUDACC__
        typedef unsigned char uchar;
        typedef unsigned short ushort;
        typedef signed char schar;
        #if defined (_WIN32) || defined (__APPLE__)
            typedef unsigned int uint;
        #endif

        template<class T> inline void bindTexture(const textureReference* tex, const PtrStepSz<T>& img)
        {
            cudaChannelFormatDesc desc = cudaCreateChannelDesc<T>();
            cudaSafeCall( cudaBindTexture2D(0, tex, img.ptr(), &desc, img.cols, img.rows, img.step) );
        }
#endif // __CUDACC__
    }
}}

#endif // __OPENCV_GPU_COMMON_HPP__
<commit_msg>Build fix for QNX 6.6 neitrino.<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's 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.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation 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.
//
//M*/

#ifndef __OPENCV_GPU_COMMON_HPP__
#define __OPENCV_GPU_COMMON_HPP__

#include <cuda_runtime.h>
#include "opencv2/core/cuda_devptrs.hpp"

#ifndef CV_PI
    #define CV_PI   3.1415926535897932384626433832795
#endif

#ifndef CV_PI_F
    #ifndef CV_PI
        #define CV_PI_F 3.14159265f
    #else
        #define CV_PI_F ((float)CV_PI)
    #endif
#endif

#if defined(__GNUC__)
    #define cudaSafeCall(expr)  ___cudaSafeCall(expr, __FILE__, __LINE__, __func__)
#else /* defined(__CUDACC__) || defined(__MSVC__) */
    #define cudaSafeCall(expr)  ___cudaSafeCall(expr, __FILE__, __LINE__)
#endif

namespace cv { namespace gpu
{
    void error(const char *error_string, const char *file, const int line, const char *func);

    template <typename T> static inline bool isAligned(const T* ptr, size_t size)
    {
        return reinterpret_cast<size_t>(ptr) % size == 0;
    }

    static inline bool isAligned(size_t step, size_t size)
    {
        return step % size == 0;
    }
}}

static inline void ___cudaSafeCall(cudaError_t err, const char *file, const int line, const char *func = "")
{
    if (cudaSuccess != err)
        cv::gpu::error(cudaGetErrorString(err), file, line, func);
}

namespace cv { namespace gpu
{
    __host__ __device__ __forceinline__ int divUp(int total, int grain)
    {
        return (total + grain - 1) / grain;
    }

    namespace device
    {
        using cv::gpu::divUp;

#ifdef __CUDACC__
        typedef unsigned char uchar;
        typedef unsigned short ushort;
        typedef signed char schar;
        #if defined (_WIN32) || defined (__APPLE__) || defined (__QNX__)
            typedef unsigned int uint;
        #endif

        template<class T> inline void bindTexture(const textureReference* tex, const PtrStepSz<T>& img)
        {
            cudaChannelFormatDesc desc = cudaCreateChannelDesc<T>();
            cudaSafeCall( cudaBindTexture2D(0, tex, img.ptr(), &desc, img.cols, img.rows, img.step) );
        }
#endif // __CUDACC__
    }
}}

#endif // __OPENCV_GPU_COMMON_HPP__
<|endoftext|>


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

/**
 * @file vcdevtest_example.cpp
 * Example for Linux
 *
 * @author Mark Charlebois <charlebm@gmail.com>
 */

#include <px4_tasks.h>
#include <px4_time.h>
#include "vcdevtest_example.h"
#include <drivers/drv_device.h>
#include <drivers/device/device.h>
#include <unistd.h>
#include <stdio.h>

px4::AppState VCDevExample::appState;

using namespace device;

#define TESTDEV "/dev/vdevtest"

static bool g_exit = false;

static int writer_main(int argc, char *argv[])
{
	char buf[1];

	int fd = px4_open(TESTDEV, PX4_F_WRONLY);
	if (fd < 0) {
		PX4_INFO("Writer: Open failed %d %d", fd, px4_errno);
		return -px4_errno;
	}

	int ret;
	int i = 0;

	while (!g_exit) {
		// Wait for 2 seconds
		PX4_INFO("Writer: Sleeping for 2 sec");
		ret = sleep(2);

		if (ret < 0) {
			PX4_INFO("Writer: sleep failed %d %d", ret, errno);
			return ret;
		}

		buf[0] = 'A' + (char)(i % 26);
		PX4_INFO("Writer: writing char '%c'", buf[0]);
		ret = px4_write(fd, buf, 1);
		++i;
	}

	px4_close(fd);
	PX4_INFO("Writer: stopped");
	return ret;
}

class PrivData
{
public:
	PrivData() : _read_offset(0) {}
	~PrivData() {}

	size_t _read_offset;
};

class VCDevNode : public VDev
{
public:
	VCDevNode() :
		VDev("vcdevtest", TESTDEV),
		_is_open_for_write(false),
		_write_offset(0) {};

	~VCDevNode() {}

	virtual int open(device::file_t *handlep);
	virtual int close(device::file_t *handlep);
	virtual ssize_t write(device::file_t *handlep, const char *buffer, size_t buflen);
	virtual ssize_t read(device::file_t *handlep, char *buffer, size_t buflen);
private:
	bool _is_open_for_write;
	size_t _write_offset;
	char     _buf[1000];
};

int VCDevNode::open(device::file_t *handlep)
{
	// Only allow one writer
	if (_is_open_for_write && (handlep->flags & PX4_F_WRONLY)) {
		errno = EBUSY;
		return -1;
	}

	int ret = VDev::open(handlep);

	if (ret != 0) {
		return ret;
	}

	handlep->priv = new PrivData;

	if (_is_open_for_write && (handlep->flags & PX4_F_WRONLY)) {
		_is_open_for_write = true;
	}

	return 0;
}

int VCDevNode::close(device::file_t *handlep)
{
	delete(PrivData *)handlep->priv;
	handlep->priv = nullptr;
	VDev::close(handlep);

	// Enable a new writer of the device is re-opened for write
	if ((handlep->flags & PX4_F_WRONLY) && _is_open_for_write) {
		_is_open_for_write = false;
	}

	return 0;
}

ssize_t VCDevNode::write(device::file_t *handlep, const char *buffer, size_t buflen)
{
	for (size_t i = 0; i < buflen && _write_offset < 1000; i++) {
		_buf[_write_offset] = buffer[i];
		_write_offset++;
	}

	// ignore what was written, but let pollers know something was written
	poll_notify(POLLIN);

	return buflen;
}

ssize_t VCDevNode::read(device::file_t *handlep, char *buffer, size_t buflen)
{
	PrivData *p = (PrivData *)handlep->priv;
	ssize_t chars_read = 0;
	PX4_INFO("read %zu write %zu", p->_read_offset, _write_offset);

	for (size_t i = 0; i < buflen && (p->_read_offset < _write_offset); i++) {
		buffer[i] = _buf[p->_read_offset];
		p->_read_offset++;
		chars_read++;
	}

	return chars_read;
}

VCDevExample::~VCDevExample()
{
	if (_node) {
		delete _node;
		_node = 0;
	}
}

static int test_pub_block(int fd, unsigned long blocked)
{
	int ret = px4_ioctl(fd, DEVIOCSPUBBLOCK, blocked);

	if (ret < 0) {
		PX4_INFO("ioctl PX4_DEVIOCSPUBBLOCK failed %d %d", ret, px4_errno);
		return -px4_errno;
	}

	ret = px4_ioctl(fd, DEVIOCGPUBBLOCK, 0);

	if (ret < 0) {
		PX4_INFO("ioctl PX4_DEVIOCGPUBBLOCK failed %d %d", ret, px4_errno);
		return -px4_errno;
	}

	PX4_INFO("pub_blocked = %d %s", ret, (unsigned long)ret == blocked ? "PASS" : "FAIL");

	return 0;
}

int VCDevExample::do_poll(int fd, int timeout, int iterations, int delayms_after_poll)
{
	int pollret, readret;
	int loop_count = 0;
	char readbuf[10];
	px4_pollfd_struct_t fds[1];

	fds[0].fd = fd;
	fds[0].events = POLLIN;
	fds[0].revents = 0;

	bool mustblock = (timeout < 0);

	// Test indefinte blocking poll
	while ((!appState.exitRequested()) && (loop_count < iterations)) {
		pollret = px4_poll(fds, 1, timeout);

		if (pollret < 0) {
			PX4_ERR("Reader: px4_poll failed %d %d FAIL", pollret, px4_errno);
			goto fail;
		}

		PX4_INFO("Reader: px4_poll returned %d", pollret);

		if (pollret) {
			readret = px4_read(fd, readbuf, 10);

			if (readret != 1) {
				if (mustblock) {
					PX4_ERR("Reader:     read failed %d FAIL", readret);
					goto fail;

				} else {
					PX4_INFO("Reader:     read failed %d FAIL", readret);
				}

			} else {
				readbuf[readret] = '\0';
				PX4_INFO("Reader: px4_poll     returned %d, read '%s' PASS", pollret, readbuf);
			}
		}

		if (delayms_after_poll) {
			usleep(delayms_after_poll * 1000);
		}

		loop_count++;
	}

	return 0;
fail:
	return 1;
}
int VCDevExample::main()
{
	appState.setRunning(true);

	_node = new VCDevNode();

	if (_node == 0) {
		PX4_INFO("Failed to allocate VCDevNode");
		return -ENOMEM;
	}

	if (_node->init() != PX4_OK) {
		PX4_INFO("Failed to init VCDevNode");
		return 1;
	}

	int fd = px4_open(TESTDEV, PX4_F_RDONLY);

	if (fd < 0) {
		PX4_INFO("Open failed %d %d", fd, px4_errno);
		return -px4_errno;
	}

	void *p = 0;
	int ret = px4_ioctl(fd, DIOC_GETPRIV, (unsigned long)&p);

	if (ret < 0) {
		PX4_INFO("ioctl DIOC_GETPRIV failed %d %d", ret, px4_errno);
		return -px4_errno;
	}

	PX4_INFO("priv data = %p %s", p, p == (void *)_node ? "PASS" : "FAIL");

	ret = test_pub_block(fd, 1);

	if (ret < 0) {
		return ret;
	}

	ret = test_pub_block(fd, 0);

	if (ret < 0) {
		return ret;
	}

	// Start a task that will write something in 4 seconds
	(void)px4_task_spawn_cmd("writer",
				 SCHED_DEFAULT,
				 SCHED_PRIORITY_MAX - 6,
				 2000,
				 writer_main,
				 (char *const *)NULL);

	ret = 0;
	PX4_INFO("TEST: BLOCKING POLL ---------------");

	if (do_poll(fd, -1, 3, 0)) {
		ret = 1;
		goto fail2;
	PX4_INFO("TEST: ZERO TIMEOUT POLL -----------");
	if(do_poll(fd, 0, 3, 0)) {
		ret = 1;
		goto fail2;
		goto fail2;
	}

	PX4_INFO("TEST: ZERO TIMEOUT POLL -----------");

	if (do_poll(fd, 0, 3, 0)) {
		ret = 1;
		goto fail2;
	}

	PX4_INFO("TEST: 100ms TIMEOUT POLL -----------");

	if (do_poll(fd, 0, 30, 100)) {
		ret = 1;
		goto fail2;
	}

	PX4_INFO("TEST: 1 SEC TIMOUT POLL ------------");

	if (do_poll(fd, 1000, 3, 0)) {
		ret = 1;
		goto fail2;
	PX4_INFO("TEST: waiting for writer to stop");
fail2:
	g_exit = true;
	px4_close(fd);
	PX4_INFO("TEST: waiting for writer to stop");
	sleep(3);
	return ret;
}
<commit_msg>Whitespace fixes<commit_after>
/****************************************************************************
 *
 *   Copyright (C) 2015 Mark Charlebois. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file vcdevtest_example.cpp
 * Example for Linux
 *
 * @author Mark Charlebois <charlebm@gmail.com>
 */

#include <px4_tasks.h>
#include <px4_time.h>
#include "vcdevtest_example.h"
#include <drivers/drv_device.h>
#include <drivers/device/device.h>
#include <unistd.h>
#include <stdio.h>

px4::AppState VCDevExample::appState;

using namespace device;

#define TESTDEV "/dev/vdevtest"

static bool g_exit = false;

static int writer_main(int argc, char *argv[])
{
	char buf[1];

	int fd = px4_open(TESTDEV, PX4_F_WRONLY);

	if (fd < 0) {
		PX4_INFO("Writer: Open failed %d %d", fd, px4_errno);
		return -px4_errno;
	}

	int ret;
	int i = 0;

	while (!g_exit) {
		// Wait for 2 seconds
		PX4_INFO("Writer: Sleeping for 2 sec");
		ret = sleep(2);

		if (ret < 0) {
			PX4_INFO("Writer: sleep failed %d %d", ret, errno);
			return ret;
		}

		buf[0] = 'A' + (char)(i % 26);
		PX4_INFO("Writer: writing char '%c'", buf[0]);
		ret = px4_write(fd, buf, 1);
		++i;
	}

	px4_close(fd);
	PX4_INFO("Writer: stopped");
	return ret;
}

class PrivData
{
public:
	PrivData() : _read_offset(0) {}
	~PrivData() {}

	size_t _read_offset;
};

class VCDevNode : public VDev
{
public:
	VCDevNode() :
		VDev("vcdevtest", TESTDEV),
		_is_open_for_write(false),
		_write_offset(0) {};

	~VCDevNode() {}

	virtual int open(device::file_t *handlep);
	virtual int close(device::file_t *handlep);
	virtual ssize_t write(device::file_t *handlep, const char *buffer, size_t buflen);
	virtual ssize_t read(device::file_t *handlep, char *buffer, size_t buflen);
private:
	bool _is_open_for_write;
	size_t _write_offset;
	char     _buf[1000];
};

int VCDevNode::open(device::file_t *handlep)
{
	// Only allow one writer
	if (_is_open_for_write && (handlep->flags & PX4_F_WRONLY)) {
		errno = EBUSY;
		return -1;
	}

	int ret = VDev::open(handlep);

	if (ret != 0) {
		return ret;
	}

	handlep->priv = new PrivData;

	if (_is_open_for_write && (handlep->flags & PX4_F_WRONLY)) {
		_is_open_for_write = true;
	}

	return 0;
}

int VCDevNode::close(device::file_t *handlep)
{
	delete(PrivData *)handlep->priv;
	handlep->priv = nullptr;
	VDev::close(handlep);

	// Enable a new writer of the device is re-opened for write
	if ((handlep->flags & PX4_F_WRONLY) && _is_open_for_write) {
		_is_open_for_write = false;
	}

	return 0;
}

ssize_t VCDevNode::write(device::file_t *handlep, const char *buffer, size_t buflen)
{
	for (size_t i = 0; i < buflen && _write_offset < 1000; i++) {
		_buf[_write_offset] = buffer[i];
		_write_offset++;
	}

	// ignore what was written, but let pollers know something was written
	poll_notify(POLLIN);

	return buflen;
}

ssize_t VCDevNode::read(device::file_t *handlep, char *buffer, size_t buflen)
{
	PrivData *p = (PrivData *)handlep->priv;
	ssize_t chars_read = 0;
	PX4_INFO("read %zu write %zu", p->_read_offset, _write_offset);

	for (size_t i = 0; i < buflen && (p->_read_offset < _write_offset); i++) {
		buffer[i] = _buf[p->_read_offset];
		p->_read_offset++;
		chars_read++;
	}

	return chars_read;
}

VCDevExample::~VCDevExample()
{
	if (_node) {
		delete _node;
		_node = 0;
	}
}

static int test_pub_block(int fd, unsigned long blocked)
{
	int ret = px4_ioctl(fd, DEVIOCSPUBBLOCK, blocked);

	if (ret < 0) {
		PX4_INFO("ioctl PX4_DEVIOCSPUBBLOCK failed %d %d", ret, px4_errno);
		return -px4_errno;
	}

	ret = px4_ioctl(fd, DEVIOCGPUBBLOCK, 0);

	if (ret < 0) {
		PX4_INFO("ioctl PX4_DEVIOCGPUBBLOCK failed %d %d", ret, px4_errno);
		return -px4_errno;
	}

	PX4_INFO("pub_blocked = %d %s", ret, (unsigned long)ret == blocked ? "PASS" : "FAIL");

	return 0;
}

int VCDevExample::do_poll(int fd, int timeout, int iterations, int delayms_after_poll)
{
	int pollret, readret;
	int loop_count = 0;
	char readbuf[10];
	px4_pollfd_struct_t fds[1];

	fds[0].fd = fd;
	fds[0].events = POLLIN;
	fds[0].revents = 0;

	bool mustblock = (timeout < 0);

	// Test indefinte blocking poll
	while ((!appState.exitRequested()) && (loop_count < iterations)) {
		pollret = px4_poll(fds, 1, timeout);

		if (pollret < 0) {
			PX4_ERR("Reader: px4_poll failed %d %d FAIL", pollret, px4_errno);
			goto fail;
		}

		PX4_INFO("Reader: px4_poll returned %d", pollret);

		if (pollret) {
			readret = px4_read(fd, readbuf, 10);

			if (readret != 1) {
				if (mustblock) {
					PX4_ERR("Reader:     read failed %d FAIL", readret);
					goto fail;

				} else {
					PX4_INFO("Reader:     read failed %d FAIL", readret);
				}

			} else {
				readbuf[readret] = '\0';
				PX4_INFO("Reader: px4_poll     returned %d, read '%s' PASS", pollret, readbuf);
			}
		}

		if (delayms_after_poll) {
			usleep(delayms_after_poll * 1000);
		}

		loop_count++;
	}

	return 0;
fail:
	return 1;
}
int VCDevExample::main()
{
	appState.setRunning(true);

	_node = new VCDevNode();

	if (_node == 0) {
		PX4_INFO("Failed to allocate VCDevNode");
		return -ENOMEM;
	}

	if (_node->init() != PX4_OK) {
		PX4_INFO("Failed to init VCDevNode");
		return 1;
	}

	int fd = px4_open(TESTDEV, PX4_F_RDONLY);

	if (fd < 0) {
		PX4_INFO("Open failed %d %d", fd, px4_errno);
		return -px4_errno;
	}

	void *p = 0;
	int ret = px4_ioctl(fd, DIOC_GETPRIV, (unsigned long)&p);

	if (ret < 0) {
		PX4_INFO("ioctl DIOC_GETPRIV failed %d %d", ret, px4_errno);
		return -px4_errno;
	}

	PX4_INFO("priv data = %p %s", p, p == (void *)_node ? "PASS" : "FAIL");

	ret = test_pub_block(fd, 1);

	if (ret < 0) {
		return ret;
	}

	ret = test_pub_block(fd, 0);

	if (ret < 0) {
		return ret;
	}

	// Start a task that will write something in 4 seconds
	(void)px4_task_spawn_cmd("writer",
				 SCHED_DEFAULT,
				 SCHED_PRIORITY_MAX - 6,
				 2000,
				 writer_main,
				 (char *const *)NULL);

	ret = 0;
	PX4_INFO("TEST: BLOCKING POLL ---------------");

	if (do_poll(fd, -1, 3, 0)) {
		ret = 1;
		goto fail2;
	PX4_INFO("TEST: ZERO TIMEOUT POLL -----------");
	if(do_poll(fd, 0, 3, 0)) {
		ret = 1;
		goto fail2;
		goto fail2;
	}

	PX4_INFO("TEST: ZERO TIMEOUT POLL -----------");

	if (do_poll(fd, 0, 3, 0)) {
		ret = 1;
		goto fail2;
	}

	PX4_INFO("TEST: 100ms TIMEOUT POLL -----------");

	if (do_poll(fd, 0, 30, 100)) {
		ret = 1;
		goto fail2;
	}

	PX4_INFO("TEST: 1 SEC TIMOUT POLL ------------");

	if (do_poll(fd, 1000, 3, 0)) {
		ret = 1;
		goto fail2;
	PX4_INFO("TEST: waiting for writer to stop");
fail2:
	g_exit = true;
	px4_close(fd);
	PX4_INFO("TEST: waiting for writer to stop");
	sleep(3);
	return ret;
}
<|endoftext|>