<commit_before>/**
 * @file lltoolbar.cpp
 * @author Richard Nelson
 * @brief User customizable toolbar class
 *
 * $LicenseInfo:firstyear=2011&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2011, 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$
 */

#include "linden_common.h"

#include "boost/foreach.hpp"
#include "lltoolbar.h"

// uncomment this and remove the one in llui.cpp when there is an external reference to this translation unit
// thanks, MSVC!
//static LLDefaultChildRegistry::Register<LLToolBar> r1("toolbar");

namespace LLToolBarEnums
{
	LLLayoutStack::ELayoutOrientation getOrientation(SideType sideType)
	{
		LLLayoutStack::ELayoutOrientation orientation = LLLayoutStack::HORIZONTAL;

		if ((sideType == SIDE_LEFT) || (sideType == SIDE_RIGHT))
		{
			orientation = LLLayoutStack::VERTICAL;
		}

		return orientation;
	}
}
using namespace LLToolBarEnums;

LLToolBar::Params::Params()
:	button_display_mode("button_display_mode"),
	buttons("button"),
	side("side"),
	button_icon("button_icon"),
	button_icon_and_text("button_icon_and_text"),
	wrap("wrap", true),
	min_button_width("min_button_width", 0),
	max_button_width("max_button_width", S32_MAX),
	background_image("background_image")
{}

LLToolBar::LLToolBar(const Params& p)
:	LLUICtrl(p),
	mButtonType(p.button_display_mode),
	mSideType(p.side),
	mWrap(p.wrap),
	mNeedsLayout(false),
	mCenterPanel(NULL),
	mCenteringStack(NULL),
	mMinButtonWidth(p.min_button_width),
	mMaxButtonWidth(p.max_button_width),
	mBackgroundImage(p.background_image)
{
}

void LLToolBar::initFromParams(const LLToolBar::Params& p)
{
	LLLayoutStack::ELayoutOrientation orientation = getOrientation(p.side);

	LLLayoutStack::Params centering_stack_p;
	centering_stack_p.name = "centering_stack";
	centering_stack_p.rect = getLocalRect();
	centering_stack_p.follows.flags = FOLLOWS_ALL;
	centering_stack_p.orientation = orientation;

	mCenteringStack = LLUICtrlFactory::create<LLLayoutStack>(centering_stack_p);
	addChild(mCenteringStack);

	LLLayoutPanel::Params border_panel_p;
	border_panel_p.name = "border_panel";
	border_panel_p.rect = getLocalRect();
	border_panel_p.auto_resize = true;
	border_panel_p.user_resize = false;

	mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p));

	LLLayoutPanel::Params center_panel_p;
	center_panel_p.name = "center_panel";
	center_panel_p.rect = getLocalRect();
	center_panel_p.auto_resize = false;
	center_panel_p.user_resize = false;
	center_panel_p.fit_content = true;
	mCenterPanel = LLUICtrlFactory::create<LLLayoutPanel>(center_panel_p);
	mCenteringStack->addChild(mCenterPanel);

	mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p));

	BOOST_FOREACH (LLToolBarButton::Params button_p, p.buttons)
	{
		// buttons always follow left and top, for all orientations
		button_p.follows.flags = FOLLOWS_LEFT|FOLLOWS_TOP;
		button_p.fillFrom((mButtonType == BTNTYPE_ICONS_ONLY)
							? p.button_icon						// icon only
							: p.button_icon_and_text);			// icon + text

		LLRect button_rect(button_p.rect);
		{ // remove any offset from button
			if (orientation == LLLayoutStack::HORIZONTAL)
			{
				button_rect.setOriginAndSize(0, 0, mMinButtonWidth, button_rect.getHeight());
			}
			else // VERTICAL
			{
				button_rect.setOriginAndSize(0, 0, mMinButtonWidth, button_rect.getHeight());
			}
		}

		// use our calculated rect
		button_p.rect = button_rect;
		LLToolBarButton* buttonp = LLUICtrlFactory::create<LLToolBarButton>(button_p);

		mButtons.push_back(buttonp);
		mCenterPanel->addChild(buttonp);

		mNeedsLayout = true;
	}
}

void LLToolBar::updateLayoutAsNeeded()
{
	if (!mNeedsLayout) return;

	LLLayoutStack::ELayoutOrientation orientation = getOrientation(mSideType);

	// our terminology for orientation-agnostic layout is that
	// length refers to a distance in the direction we stack the buttons
	// and girth refers to a distance in the direction buttons wrap
	S32 total_length = 0;
	S32 max_length = (orientation == LLLayoutStack::HORIZONTAL)
					? getRect().getWidth()
					: getRect().getHeight();
	S32 max_row_girth = 0;
	S32 cur_start = 0;
	S32 cur_row = 0;

	LLRect panel_rect = mCenterPanel->getLocalRect();

	std::vector<LLToolBarButton*> buttons_in_row;

	BOOST_FOREACH(LLToolBarButton* button, mButtons)
	{
		S32 button_clamped_width = llclamp(button->getRect().getWidth(), mMinButtonWidth, mMaxButtonWidth);
		S32 button_length = (orientation == LLLayoutStack::HORIZONTAL)
							? button_clamped_width
							: button->getRect().getHeight();
		S32 button_girth = (orientation == LLLayoutStack::HORIZONTAL)
							? button->getRect().getHeight()
							: button_clamped_width;

		// handle wrapping
		if (total_length + button_length > max_length
			&& cur_start != 0) // not first button in row
		{ // go ahead and wrap
			if (orientation == LLLayoutStack::VERTICAL)
			{
				// row girth is clamped to allowable button widths
				max_row_girth = llclamp(max_row_girth, mMinButtonWidth, mMaxButtonWidth);
			}
			// make buttons in current row all same girth
			BOOST_FOREACH(LLToolBarButton* button, buttons_in_row)
			{
				if (orientation == LLLayoutStack::HORIZONTAL)
				{
					button->reshape(llclamp(button->getRect().getWidth(), mMinButtonWidth, mMaxButtonWidth), max_row_girth);
				}
				else // VERTICAL
				{
					button->reshape(max_row_girth, button->getRect().getHeight());
				}
			}
			buttons_in_row.clear();

			total_length = 0;
			cur_start = 0;
			cur_row += max_row_girth;
			max_row_girth = 0;
		}

		LLRect button_rect;
		if (orientation == LLLayoutStack::HORIZONTAL)
		{
			button_rect.setLeftTopAndSize(cur_start, panel_rect.mTop - cur_row, button_clamped_width, button->getRect().getHeight());
		}
		else // VERTICAL
		{
			button_rect.setLeftTopAndSize(cur_row, panel_rect.mTop - cur_start, button_clamped_width, button->getRect().getHeight());
		}
		button->setShape(button_rect);

		buttons_in_row.push_back(button);

		total_length += button_length;
		cur_start = total_length;
		max_row_girth = llmax(button_girth, max_row_girth);
	}

	// final resizing in "girth" direction
	S32 total_girth = cur_row + max_row_girth; // increment by size of final row

	// grow and optionally shift toolbar to accomodate buttons
	if (orientation == LLLayoutStack::HORIZONTAL)
	{
		if (mSideType == SIDE_TOP)
		{ // shift down to maintain top edge
			translate(0, getRect().getHeight() - total_girth);
		}

		reshape(getRect().getWidth(), total_girth);
	}
	else // VERTICAL
	{
		if (mSideType == SIDE_RIGHT)
		{ // shift left to maintain right edge
			translate(getRect().getWidth() - total_girth, 0);
		}
		reshape(total_girth, getRect().getHeight());
	}

	// recenter toolbar buttons
	mCenteringStack->updateLayout();

	// don't clear flag until after we've resized ourselves, to avoid laying out every frame
	mNeedsLayout = false;
}

void LLToolBar::draw()
{
	updateLayoutAsNeeded();

	{	// draw background
		LLRect bg_rect;
		localRectToOtherView(mCenterPanel->getRect(),&bg_rect, this);
		mBackgroundImage->draw(bg_rect);
	}
	LLUICtrl::draw();
}

void LLToolBar::reshape(S32 width, S32 height, BOOL called_from_parent)
{
	LLUICtrl::reshape(width, height, called_from_parent);
	mNeedsLayout = true;
}

namespace LLInitParam
{
	void TypeValues<ButtonType>::declareValues()
	{
		declare("icons_only",		BTNTYPE_ICONS_ONLY);
		declare("icons_with_text",	BTNTYPE_ICONS_WITH_TEXT);
	}

	void TypeValues<SideType>::declareValues()
	{
		declare("none",		SIDE_NONE);
		declare("bottom",	SIDE_BOTTOM);
		declare("left",		SIDE_LEFT);
		declare("right",	SIDE_RIGHT);
		declare("top",		SIDE_TOP);
	}
}
<commit_msg>variable rename<commit_after>/**
 * @file lltoolbar.cpp
 * @author Richard Nelson
 * @brief User customizable toolbar class
 *
 * $LicenseInfo:firstyear=2011&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2011, 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$
 */

#include "linden_common.h"

#include "boost/foreach.hpp"
#include "lltoolbar.h"

// uncomment this and remove the one in llui.cpp when there is an external reference to this translation unit
// thanks, MSVC!
//static LLDefaultChildRegistry::Register<LLToolBar> r1("toolbar");

namespace LLToolBarEnums
{
	LLLayoutStack::ELayoutOrientation getOrientation(SideType sideType)
	{
		LLLayoutStack::ELayoutOrientation orientation = LLLayoutStack::HORIZONTAL;

		if ((sideType == SIDE_LEFT) || (sideType == SIDE_RIGHT))
		{
			orientation = LLLayoutStack::VERTICAL;
		}

		return orientation;
	}
}
using namespace LLToolBarEnums;

LLToolBar::Params::Params()
:	button_display_mode("button_display_mode"),
	buttons("button"),
	side("side"),
	button_icon("button_icon"),
	button_icon_and_text("button_icon_and_text"),
	wrap("wrap", true),
	min_button_width("min_button_width", 0),
	max_button_width("max_button_width", S32_MAX),
	background_image("background_image")
{}

LLToolBar::LLToolBar(const Params& p)
:	LLUICtrl(p),
	mButtonType(p.button_display_mode),
	mSideType(p.side),
	mWrap(p.wrap),
	mNeedsLayout(false),
	mCenterPanel(NULL),
	mCenteringStack(NULL),
	mMinButtonWidth(p.min_button_width),
	mMaxButtonWidth(p.max_button_width),
	mBackgroundImage(p.background_image)
{
}

void LLToolBar::initFromParams(const LLToolBar::Params& p)
{
	LLLayoutStack::ELayoutOrientation orientation = getOrientation(p.side);

	LLLayoutStack::Params centering_stack_p;
	centering_stack_p.name = "centering_stack";
	centering_stack_p.rect = getLocalRect();
	centering_stack_p.follows.flags = FOLLOWS_ALL;
	centering_stack_p.orientation = orientation;

	mCenteringStack = LLUICtrlFactory::create<LLLayoutStack>(centering_stack_p);
	addChild(mCenteringStack);

	LLLayoutPanel::Params border_panel_p;
	border_panel_p.name = "border_panel";
	border_panel_p.rect = getLocalRect();
	border_panel_p.auto_resize = true;
	border_panel_p.user_resize = false;

	mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p));

	LLLayoutPanel::Params center_panel_p;
	center_panel_p.name = "center_panel";
	center_panel_p.rect = getLocalRect();
	center_panel_p.auto_resize = false;
	center_panel_p.user_resize = false;
	center_panel_p.fit_content = true;
	mCenterPanel = LLUICtrlFactory::create<LLLayoutPanel>(center_panel_p);
	mCenteringStack->addChild(mCenterPanel);

	mCenteringStack->addChild(LLUICtrlFactory::create<LLLayoutPanel>(border_panel_p));

	BOOST_FOREACH (LLToolBarButton::Params button_p, p.buttons)
	{
		// buttons always follow left and top, for all orientations
		button_p.follows.flags = FOLLOWS_LEFT|FOLLOWS_TOP;
		button_p.fillFrom((mButtonType == BTNTYPE_ICONS_ONLY)
							? p.button_icon						// icon only
							: p.button_icon_and_text);			// icon + text

		LLRect button_rect(button_p.rect);
		{ // remove any offset from button
			if (orientation == LLLayoutStack::HORIZONTAL)
			{
				button_rect.setOriginAndSize(0, 0, mMinButtonWidth, button_rect.getHeight());
			}
			else // VERTICAL
			{
				button_rect.setOriginAndSize(0, 0, mMinButtonWidth, button_rect.getHeight());
			}
		}

		// use our calculated rect
		button_p.rect = button_rect;
		LLToolBarButton* buttonp = LLUICtrlFactory::create<LLToolBarButton>(button_p);

		mButtons.push_back(buttonp);
		mCenterPanel->addChild(buttonp);

		mNeedsLayout = true;
	}
}

void LLToolBar::updateLayoutAsNeeded()
{
	if (!mNeedsLayout) return;

	LLLayoutStack::ELayoutOrientation orientation = getOrientation(mSideType);

	// our terminology for orientation-agnostic layout is that
	// length refers to a distance in the direction we stack the buttons
	// and girth refers to a distance in the direction buttons wrap
	S32 row_running_length = 0;
	S32 max_length = (orientation == LLLayoutStack::HORIZONTAL)
					? getRect().getWidth()
					: getRect().getHeight();
	S32 max_row_girth = 0;
	S32 cur_start = 0;
	S32 cur_row = 0;

	LLRect panel_rect = mCenterPanel->getLocalRect();

	std::vector<LLToolBarButton*> buttons_in_row;

	BOOST_FOREACH(LLToolBarButton* button, mButtons)
	{
		S32 button_clamped_width = llclamp(button->getRect().getWidth(), mMinButtonWidth, mMaxButtonWidth);
		S32 button_length = (orientation == LLLayoutStack::HORIZONTAL)
							? button_clamped_width
							: button->getRect().getHeight();
		S32 button_girth = (orientation == LLLayoutStack::HORIZONTAL)
							? button->getRect().getHeight()
							: button_clamped_width;

		// handle wrapping
		if (row_running_length + button_length > max_length
			&& cur_start != 0) // not first button in row
		{ // go ahead and wrap
			if (orientation == LLLayoutStack::VERTICAL)
			{
				// row girth is clamped to allowable button widths
				max_row_girth = llclamp(max_row_girth, mMinButtonWidth, mMaxButtonWidth);
			}
			// make buttons in current row all same girth
			BOOST_FOREACH(LLToolBarButton* button, buttons_in_row)
			{
				if (orientation == LLLayoutStack::HORIZONTAL)
				{
					button->reshape(llclamp(button->getRect().getWidth(), mMinButtonWidth, mMaxButtonWidth), max_row_girth);
				}
				else // VERTICAL
				{
					button->reshape(max_row_girth, button->getRect().getHeight());
				}
			}
			buttons_in_row.clear();

			row_running_length = 0;
			cur_start = 0;
			cur_row += max_row_girth;
			max_row_girth = 0;
		}

		LLRect button_rect;
		if (orientation == LLLayoutStack::HORIZONTAL)
		{
			button_rect.setLeftTopAndSize(cur_start, panel_rect.mTop - cur_row, button_clamped_width, button->getRect().getHeight());
		}
		else // VERTICAL
		{
			button_rect.setLeftTopAndSize(cur_row, panel_rect.mTop - cur_start, button_clamped_width, button->getRect().getHeight());
		}
		button->setShape(button_rect);

		buttons_in_row.push_back(button);

		row_running_length += button_length;
		cur_start = row_running_length;
		max_row_girth = llmax(button_girth, max_row_girth);
	}

	// final resizing in "girth" direction
	S32 total_girth = cur_row + max_row_girth; // increment by size of final row

	// grow and optionally shift toolbar to accomodate buttons
	if (orientation == LLLayoutStack::HORIZONTAL)
	{
		if (mSideType == SIDE_TOP)
		{ // shift down to maintain top edge
			translate(0, getRect().getHeight() - total_girth);
		}

		reshape(getRect().getWidth(), total_girth);
	}
	else // VERTICAL
	{
		if (mSideType == SIDE_RIGHT)
		{ // shift left to maintain right edge
			translate(getRect().getWidth() - total_girth, 0);
		}
		reshape(total_girth, getRect().getHeight());
	}

	// recenter toolbar buttons
	mCenteringStack->updateLayout();

	// don't clear flag until after we've resized ourselves, to avoid laying out every frame
	mNeedsLayout = false;
}

void LLToolBar::draw()
{
	updateLayoutAsNeeded();

	{	// draw background
		LLRect bg_rect;
		localRectToOtherView(mCenterPanel->getRect(),&bg_rect, this);
		mBackgroundImage->draw(bg_rect);
	}
	LLUICtrl::draw();
}

void LLToolBar::reshape(S32 width, S32 height, BOOL called_from_parent)
{
	LLUICtrl::reshape(width, height, called_from_parent);
	mNeedsLayout = true;
}

namespace LLInitParam
{
	void TypeValues<ButtonType>::declareValues()
	{
		declare("icons_only",		BTNTYPE_ICONS_ONLY);
		declare("icons_with_text",	BTNTYPE_ICONS_WITH_TEXT);
	}

	void TypeValues<SideType>::declareValues()
	{
		declare("none",		SIDE_NONE);
		declare("bottom",	SIDE_BOTTOM);
		declare("left",		SIDE_LEFT);
		declare("right",	SIDE_RIGHT);
		declare("top",		SIDE_TOP);
	}
}
<|endoftext|>


<commit_before>/* Copyright 2016 Streampunk Media Ltd.

  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 <nan.h>
#include "ScaleConverter.h"
#include "MyWorker.h"
#include "Timer.h"
#include "Packers.h"
#include "Memory.h"
#include "ScaleConverterFF.h"
#include "EssenceInfo.h"

#include <memory>

using namespace v8;

namespace streampunk {

class ScaleConvertProcessData : public iProcessData {
public:
  ScaleConvertProcessData (std::shared_ptr<Memory> srcBuf, std::shared_ptr<Memory> dstBuf,
                           std::shared_ptr<Memory> convertDstBuf, std::shared_ptr<Memory> scaleSrcBuf)
    : mSrcBuf(srcBuf), mDstBuf(dstBuf), mConvertDstBuf(convertDstBuf), mScaleSrcBuf(scaleSrcBuf)
  { }
  ~ScaleConvertProcessData() { }

  std::shared_ptr<Memory> srcBuf() const { return mSrcBuf; }
  std::shared_ptr<Memory> dstBuf() const { return mDstBuf; }
  std::shared_ptr<Memory> convertDstBuf() const { return mConvertDstBuf; }
  std::shared_ptr<Memory> scaleSrcBuf() const { return mConvertDstBuf; }

private:
  std::shared_ptr<Memory> mSrcBuf;
  std::shared_ptr<Memory> mDstBuf;
  std::shared_ptr<Memory> mConvertDstBuf;
  std::shared_ptr<Memory> mScaleSrcBuf;
};

ScaleConverter::ScaleConverter(Nan::Callback *callback)
  : mWorker(new MyWorker(callback)), mSetInfoOK(false), mUnityPacking(true), mUnityScale(true), mSrcFormatBytes(0), mDstBytesReq(0) {
  AsyncQueueWorker(mWorker);
}
ScaleConverter::~ScaleConverter() {}

// iProcess
uint32_t ScaleConverter::processFrame (std::shared_ptr<iProcessData> processData) {
  Timer t;
  std::shared_ptr<ScaleConvertProcessData> scpd = std::dynamic_pointer_cast<ScaleConvertProcessData>(processData);

  if (mUnityPacking && mUnityScale) {
    memcpy (scpd->dstBuf()->buf(), scpd->srcBuf()->buf(), std::min<uint32_t>(scpd->dstBuf()->numBytes(), scpd->srcBuf()->numBytes()));
  }
  else {
    if (!mUnityPacking) {
      mPacker->convert(scpd->srcBuf(), scpd->convertDstBuf());
      printf("convert: %.2fms\n", t.delta());
    }

    if (!mUnityScale) {
      mScaleConverterFF->scaleConvertFrame (scpd->scaleSrcBuf(), scpd->dstBuf());
      printf("scale  : %.2fms\n", t.delta());
    }
  }
  return mDstBytesReq;
}

void ScaleConverter::doSetInfo(Local<Object> srcTags, Local<Object> dstTags) {
  mSrcVidInfo = std::make_shared<EssenceInfo>(srcTags);
  printf ("Converter SrcVidInfo: %s\n", mSrcVidInfo->toString().c_str());
  mDstVidInfo = std::make_shared<EssenceInfo>(dstTags);
  printf("Converter DstVidInfo: %s\n", mDstVidInfo->toString().c_str());

  if (mSrcVidInfo->packing().compare("pgroup") && mSrcVidInfo->packing().compare("v210") &&
      mSrcVidInfo->packing().compare("YUV422P10") && mSrcVidInfo->packing().compare("UYVY10") && mSrcVidInfo->packing().compare("420P")) {
    std::string err = std::string("Unsupported source format \'") + mSrcVidInfo->packing() + "\'";
    return Nan::ThrowError(err.c_str());
  }
  if (mDstVidInfo->packing().compare("420P") && mDstVidInfo->packing().compare("YUV422P10")) {
    std::string err = std::string("Unsupported destination packing type \'") + mDstVidInfo->packing() + "\'";
    Nan::ThrowError(err.c_str());
  }
  if ((mSrcVidInfo->width() % 2) || (mDstVidInfo->width() % 2)) {
    std::string err = std::string("Width must be divisible by 2 - src ") + std::to_string(mSrcVidInfo->width()) + ", dst " + std::to_string(mDstVidInfo->width());
    Nan::ThrowError(err.c_str());
  }

  mScaleConverterFF = std::make_shared<ScaleConverterFF>(mSrcVidInfo, mDstVidInfo);
  mPacker = std::make_shared<Packers>(mSrcVidInfo->width(), mSrcVidInfo->height(),
                                      mSrcVidInfo->packing(), mScaleConverterFF->packingRequired());
  mUnityPacking = (mSrcVidInfo->packing() == mScaleConverterFF->packingRequired());
  mUnityScale = ((mSrcVidInfo->width() == mDstVidInfo->width()) &&
                 (mSrcVidInfo->height() == mDstVidInfo->height()) &&
                 (0==mSrcVidInfo->interlace().compare(mDstVidInfo->interlace())));
  mDstBytesReq = getFormatBytes(mDstVidInfo->packing(), mDstVidInfo->width(), mDstVidInfo->height());
}

NAN_METHOD(ScaleConverter::SetInfo) {
  if (info.Length() != 2)
    return Nan::ThrowError("Converter SetInfo expects 2 arguments");
  Local<Object> srcTags = Local<Object>::Cast(info[0]);
  Local<Object> dstTags = Local<Object>::Cast(info[1]);

  ScaleConverter* obj = Nan::ObjectWrap::Unwrap<ScaleConverter>(info.Holder());

  Nan::TryCatch try_catch;
  obj->doSetInfo(srcTags, dstTags);
  if (try_catch.HasCaught()) {
    obj->mSetInfoOK = false;
    try_catch.ReThrow();
    return;
  }

  obj->mSetInfoOK = true;
  info.GetReturnValue().Set(Nan::New(obj->mDstBytesReq));
}

NAN_METHOD(ScaleConverter::ScaleConvert) {
  if (info.Length() != 3)
    return Nan::ThrowError("ScaleConverter ScaleConvert expects 3 arguments");
  if (!info[0]->IsArray())
    return Nan::ThrowError("ScaleConverter ScaleConvert requires a valid source buffer array as the first parameter");
  if (!info[1]->IsObject())
    return Nan::ThrowError("ScaleConverter ScaleConvert requires a valid destination buffer as the second parameter");
  if (!info[2]->IsFunction())
    return Nan::ThrowError("ScaleConverter ScaleConvert requires a valid callback as the third parameter");

  Local<Array> srcBufArray = Local<Array>::Cast(info[0]);
  Local<Object> dstBufObj = Local<Object>::Cast(info[1]);
  Local<Function> callback = Local<Function>::Cast(info[2]);

  Local<Object> srcBufObj = Local<Object>::Cast(srcBufArray->Get(0));

  ScaleConverter* obj = Nan::ObjectWrap::Unwrap<ScaleConverter>(info.Holder());

  if (!obj->mSetInfoOK)
    return Nan::ThrowError("ScaleConvert called with incorrect setup parameters");

  obj->mSrcFormatBytes = getFormatBytes(obj->mSrcVidInfo->packing(), obj->mSrcVidInfo->width(), obj->mSrcVidInfo->height());
  if (obj->mSrcFormatBytes > (uint32_t)node::Buffer::Length(srcBufObj))
    Nan::ThrowError("Insufficient source buffer for conversion\n");

  if (obj->mDstBytesReq > node::Buffer::Length(dstBufObj))
    return Nan::ThrowError("Insufficient destination buffer for specified format");

  std::shared_ptr<Memory> srcBuf = Memory::makeNew((uint8_t *)node::Buffer::Data(srcBufObj), (uint32_t)node::Buffer::Length(srcBufObj));
  std::shared_ptr<Memory> dstBuf = Memory::makeNew((uint8_t *)node::Buffer::Data(dstBufObj), (uint32_t)node::Buffer::Length(dstBufObj));
  std::shared_ptr<Memory> convertDstBuf = dstBuf;
  std::shared_ptr<Memory> scaleSrcBuf = srcBuf;
  if (!obj->mUnityPacking && !obj->mUnityScale) {
    convertDstBuf = Memory::makeNew(getFormatBytes(obj->mScaleConverterFF->packingRequired(), obj->mSrcVidInfo->width(), obj->mSrcVidInfo->height()));
    scaleSrcBuf = convertDstBuf;
    if (!convertDstBuf->buf())
      Nan::ThrowError("Failed to allocate buffer for packer result");
  }

  std::shared_ptr<iProcessData> scpd =
    std::make_shared<ScaleConvertProcessData>(srcBuf, dstBuf, convertDstBuf, scaleSrcBuf);
  obj->mWorker->doFrame(scpd, obj, new Nan::Callback(callback));

  info.GetReturnValue().Set(Nan::New(obj->mWorker->numQueued()));
}

NAN_METHOD(ScaleConverter::Quit) {
  if (info.Length() != 1)
    return Nan::ThrowError("ScaleConverter quit expects 1 argument");
  if (!info[0]->IsFunction())
    return Nan::ThrowError("ScaleConverter quit requires a valid callback as the parameter");
  Nan::Callback *callback = new Nan::Callback(Local<Function>::Cast(info[0]));
  ScaleConverter* obj = Nan::ObjectWrap::Unwrap<ScaleConverter>(info.Holder());

  if (obj->mWorker != NULL)
    obj->mWorker->quit(callback);

  info.GetReturnValue().SetUndefined();
}

NAN_MODULE_INIT(ScaleConverter::Init) {
  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
  tpl->SetClassName(Nan::New("ScaleConverter").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  SetPrototypeMethod(tpl, "setInfo", SetInfo);
  SetPrototypeMethod(tpl, "scaleConvert", ScaleConvert);
  SetPrototypeMethod(tpl, "quit", Quit);

  constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
  Nan::Set(target, Nan::New("ScaleConverter").ToLocalChecked(),
    Nan::GetFunction(tpl).ToLocalChecked());
}

} // namespace streampunk
<commit_msg>Fix scaling when no packing required<commit_after>/* Copyright 2016 Streampunk Media Ltd.

  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 <nan.h>
#include "ScaleConverter.h"
#include "MyWorker.h"
#include "Timer.h"
#include "Packers.h"
#include "Memory.h"
#include "ScaleConverterFF.h"
#include "EssenceInfo.h"

#include <memory>

using namespace v8;

namespace streampunk {

class ScaleConvertProcessData : public iProcessData {
public:
  ScaleConvertProcessData (std::shared_ptr<Memory> srcBuf, std::shared_ptr<Memory> dstBuf,
                           std::shared_ptr<Memory> convertDstBuf, std::shared_ptr<Memory> scaleSrcBuf)
    : mSrcBuf(srcBuf), mDstBuf(dstBuf), mConvertDstBuf(convertDstBuf), mScaleSrcBuf(scaleSrcBuf)
  { }
  ~ScaleConvertProcessData() { }

  std::shared_ptr<Memory> srcBuf() const { return mSrcBuf; }
  std::shared_ptr<Memory> dstBuf() const { return mDstBuf; }
  std::shared_ptr<Memory> convertDstBuf() const { return mConvertDstBuf; }
  std::shared_ptr<Memory> scaleSrcBuf() const { return mConvertDstBuf; }

private:
  std::shared_ptr<Memory> mSrcBuf;
  std::shared_ptr<Memory> mDstBuf;
  std::shared_ptr<Memory> mConvertDstBuf;
  std::shared_ptr<Memory> mScaleSrcBuf;
};

ScaleConverter::ScaleConverter(Nan::Callback *callback)
  : mWorker(new MyWorker(callback)), mSetInfoOK(false), mUnityPacking(true), mUnityScale(true), mSrcFormatBytes(0), mDstBytesReq(0) {
  AsyncQueueWorker(mWorker);
}
ScaleConverter::~ScaleConverter() {}

// iProcess
uint32_t ScaleConverter::processFrame (std::shared_ptr<iProcessData> processData) {
  Timer t;
  std::shared_ptr<ScaleConvertProcessData> scpd = std::dynamic_pointer_cast<ScaleConvertProcessData>(processData);

  if (mUnityPacking && mUnityScale) {
    memcpy (scpd->dstBuf()->buf(), scpd->srcBuf()->buf(), std::min<uint32_t>(scpd->dstBuf()->numBytes(), scpd->srcBuf()->numBytes()));
  }
  else {
    if (!mUnityPacking) {
      mPacker->convert(scpd->srcBuf(), scpd->convertDstBuf());
      printf("convert: %.2fms\n", t.delta());
    }

    if (!mUnityScale) {
      mScaleConverterFF->scaleConvertFrame (scpd->scaleSrcBuf(), scpd->dstBuf());
      printf("scale  : %.2fms\n", t.delta());
    }
  }
  return mDstBytesReq;
}

void ScaleConverter::doSetInfo(Local<Object> srcTags, Local<Object> dstTags) {
  mSrcVidInfo = std::make_shared<EssenceInfo>(srcTags);
  printf ("Converter SrcVidInfo: %s\n", mSrcVidInfo->toString().c_str());
  mDstVidInfo = std::make_shared<EssenceInfo>(dstTags);
  printf("Converter DstVidInfo: %s\n", mDstVidInfo->toString().c_str());

  if (mSrcVidInfo->packing().compare("pgroup") && mSrcVidInfo->packing().compare("v210") &&
      mSrcVidInfo->packing().compare("YUV422P10") && mSrcVidInfo->packing().compare("UYVY10") && mSrcVidInfo->packing().compare("420P")) {
    std::string err = std::string("Unsupported source format \'") + mSrcVidInfo->packing() + "\'";
    return Nan::ThrowError(err.c_str());
  }
  if (mDstVidInfo->packing().compare("420P") && mDstVidInfo->packing().compare("YUV422P10")) {
    std::string err = std::string("Unsupported destination packing type \'") + mDstVidInfo->packing() + "\'";
    Nan::ThrowError(err.c_str());
  }
  if ((mSrcVidInfo->width() % 2) || (mDstVidInfo->width() % 2)) {
    std::string err = std::string("Width must be divisible by 2 - src ") + std::to_string(mSrcVidInfo->width()) + ", dst " + std::to_string(mDstVidInfo->width());
    Nan::ThrowError(err.c_str());
  }

  mScaleConverterFF = std::make_shared<ScaleConverterFF>(mSrcVidInfo, mDstVidInfo);
  mUnityPacking = (mSrcVidInfo->packing() == mScaleConverterFF->packingRequired());
  if (!mUnityPacking)
    mPacker = std::make_shared<Packers>(mSrcVidInfo->width(), mSrcVidInfo->height(),
                                        mSrcVidInfo->packing(), mScaleConverterFF->packingRequired());
  mUnityScale = ((mSrcVidInfo->width() == mDstVidInfo->width()) &&
                 (mSrcVidInfo->height() == mDstVidInfo->height()) &&
                 (0==mSrcVidInfo->interlace().compare(mDstVidInfo->interlace())));
  mDstBytesReq = getFormatBytes(mDstVidInfo->packing(), mDstVidInfo->width(), mDstVidInfo->height());
}

NAN_METHOD(ScaleConverter::SetInfo) {
  if (info.Length() != 2)
    return Nan::ThrowError("Converter SetInfo expects 2 arguments");
  Local<Object> srcTags = Local<Object>::Cast(info[0]);
  Local<Object> dstTags = Local<Object>::Cast(info[1]);

  ScaleConverter* obj = Nan::ObjectWrap::Unwrap<ScaleConverter>(info.Holder());

  Nan::TryCatch try_catch;
  obj->doSetInfo(srcTags, dstTags);
  if (try_catch.HasCaught()) {
    obj->mSetInfoOK = false;
    try_catch.ReThrow();
    return;
  }

  obj->mSetInfoOK = true;
  info.GetReturnValue().Set(Nan::New(obj->mDstBytesReq));
}

NAN_METHOD(ScaleConverter::ScaleConvert) {
  if (info.Length() != 3)
    return Nan::ThrowError("ScaleConverter ScaleConvert expects 3 arguments");
  if (!info[0]->IsArray())
    return Nan::ThrowError("ScaleConverter ScaleConvert requires a valid source buffer array as the first parameter");
  if (!info[1]->IsObject())
    return Nan::ThrowError("ScaleConverter ScaleConvert requires a valid destination buffer as the second parameter");
  if (!info[2]->IsFunction())
    return Nan::ThrowError("ScaleConverter ScaleConvert requires a valid callback as the third parameter");

  Local<Array> srcBufArray = Local<Array>::Cast(info[0]);
  Local<Object> dstBufObj = Local<Object>::Cast(info[1]);
  Local<Function> callback = Local<Function>::Cast(info[2]);

  Local<Object> srcBufObj = Local<Object>::Cast(srcBufArray->Get(0));

  ScaleConverter* obj = Nan::ObjectWrap::Unwrap<ScaleConverter>(info.Holder());

  if (!obj->mSetInfoOK)
    return Nan::ThrowError("ScaleConvert called with incorrect setup parameters");

  obj->mSrcFormatBytes = getFormatBytes(obj->mSrcVidInfo->packing(), obj->mSrcVidInfo->width(), obj->mSrcVidInfo->height());
  if (obj->mSrcFormatBytes > (uint32_t)node::Buffer::Length(srcBufObj))
    Nan::ThrowError("Insufficient source buffer for conversion\n");

  if (obj->mDstBytesReq > node::Buffer::Length(dstBufObj))
    return Nan::ThrowError("Insufficient destination buffer for specified format");

  std::shared_ptr<Memory> srcBuf = Memory::makeNew((uint8_t *)node::Buffer::Data(srcBufObj), (uint32_t)node::Buffer::Length(srcBufObj));
  std::shared_ptr<Memory> dstBuf = Memory::makeNew((uint8_t *)node::Buffer::Data(dstBufObj), (uint32_t)node::Buffer::Length(dstBufObj));
  std::shared_ptr<Memory> convertDstBuf = dstBuf;
  std::shared_ptr<Memory> scaleSrcBuf = srcBuf;
  if (!obj->mUnityPacking && !obj->mUnityScale) {
    convertDstBuf = Memory::makeNew(getFormatBytes(obj->mScaleConverterFF->packingRequired(), obj->mSrcVidInfo->width(), obj->mSrcVidInfo->height()));
    scaleSrcBuf = convertDstBuf;
    if (!convertDstBuf->buf())
      Nan::ThrowError("Failed to allocate buffer for packer result");
  }

  std::shared_ptr<iProcessData> scpd =
    std::make_shared<ScaleConvertProcessData>(srcBuf, dstBuf, convertDstBuf, scaleSrcBuf);
  obj->mWorker->doFrame(scpd, obj, new Nan::Callback(callback));

  info.GetReturnValue().Set(Nan::New(obj->mWorker->numQueued()));
}

NAN_METHOD(ScaleConverter::Quit) {
  if (info.Length() != 1)
    return Nan::ThrowError("ScaleConverter quit expects 1 argument");
  if (!info[0]->IsFunction())
    return Nan::ThrowError("ScaleConverter quit requires a valid callback as the parameter");
  Nan::Callback *callback = new Nan::Callback(Local<Function>::Cast(info[0]));
  ScaleConverter* obj = Nan::ObjectWrap::Unwrap<ScaleConverter>(info.Holder());

  if (obj->mWorker != NULL)
    obj->mWorker->quit(callback);

  info.GetReturnValue().SetUndefined();
}

NAN_MODULE_INIT(ScaleConverter::Init) {
  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
  tpl->SetClassName(Nan::New("ScaleConverter").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  SetPrototypeMethod(tpl, "setInfo", SetInfo);
  SetPrototypeMethod(tpl, "scaleConvert", ScaleConvert);
  SetPrototypeMethod(tpl, "quit", Quit);

  constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
  Nan::Set(target, Nan::New("ScaleConverter").ToLocalChecked(),
    Nan::GetFunction(tpl).ToLocalChecked());
}

} // namespace streampunk
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2019 Inviwo Foundation
 * 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.
 *
 * 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.
 *
 *********************************************************************************/

#include <modules/webbrowser/webbrowsermodule.h>
#include <modules/webbrowser/processors/webbrowserprocessor.h>
#include <modules/webbrowser/webbrowserapp.h>

#include <modules/json/io/json/boolpropertyjsonconverter.h>
#include <modules/json/io/json/buttonpropertyjsonconverter.h>
#include <modules/json/io/json/directorypropertyjsonconverter.h>
#include <modules/json/io/json/filepropertyjsonconverter.h>
#include <modules/json/io/json/minmaxpropertyjsonconverter.h>
#include <modules/json/io/json/optionpropertyjsonconverter.h>
#include <modules/json/io/json/ordinalpropertyjsonconverter.h>
#include <modules/json/io/json/templatepropertyjsonconverter.h>

#include <inviwo/dataframe/io/json/dataframepropertyjsonconverter.h>

#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/settings/systemsettings.h>

#include <modules/opengl/shader/shadermanager.h>

// Autogenerated
#include <modules/webbrowser/shader_resources.h>

#include <warn/push>
#include <warn/ignore/all>
#include "include/cef_app.h"
#include "include/cef_command_line.h"
#include "include/cef_parser.h"
#include <warn/pop>

namespace inviwo {

struct OrdinalCEFWidgetReghelper {
    template <typename T>
    auto operator()(WebBrowserModule& m) {
        using PropertyType = OrdinalProperty<T>;
        m.registerPropertyWidgetCEF<PropertyWidgetCEF, PropertyType>();
    }
};

struct MinMaxCEFWidgetReghelper {
    template <typename T>
    auto operator()(WebBrowserModule& m) {
        using PropertyType = MinMaxProperty<T>;
        m.registerPropertyWidgetCEF<PropertyWidgetCEF, PropertyType>();
    }
};

struct OptionCEFWidgetReghelper {
    template <typename T>
    auto operator()(WebBrowserModule& m) {
        using PropertyType = TemplateOptionProperty<T>;
        m.registerPropertyWidgetCEF<PropertyWidgetCEF, PropertyType>();
    }
};

WebBrowserModule::WebBrowserModule(InviwoApplication* app)
    : InviwoModule(app, "WebBrowser")
    // Call 60 times per second
    , doChromiumWork_(Timer::Milliseconds(1000 / 60), []() { CefDoMessageLoopWork(); }) {

    // Register widgets
    registerPropertyWidgetCEF<PropertyWidgetCEF, BoolProperty>();
    registerPropertyWidgetCEF<PropertyWidgetCEF, ButtonProperty>();
    registerPropertyWidgetCEF<PropertyWidgetCEF, FileProperty>();
    registerPropertyWidgetCEF<PropertyWidgetCEF, DirectoryProperty>();
    registerPropertyWidgetCEF<PropertyWidgetCEF, StringProperty>();

    registerPropertyWidgetCEF<PropertyWidgetCEF, DataFrameColumnProperty>();

    // Register ordinal property widgets
    using OrdinalTypes =
        std::tuple<float, vec2, vec3, vec4, mat2, mat3, mat4, double, dvec2, dvec3, dvec4, dmat2,
                   dmat3, dmat4, int, ivec2, ivec3, ivec4, glm::i64, unsigned int, uvec2, uvec3,
                   uvec4, size_t, size2_t, size3_t, size4_t, glm::fquat, glm::dquat>;

    using ScalarTypes = std::tuple<float, double, int, glm::i64, size_t>;
    util::for_each_type<OrdinalTypes>{}(OrdinalCEFWidgetReghelper{}, *this);

    // Register MinMaxProperty widgets
    util::for_each_type<ScalarTypes>{}(MinMaxCEFWidgetReghelper{}, *this);

    // Register option property widgets
    using OptionTypes = std::tuple<unsigned int, int, size_t, float, double, std::string>;
    util::for_each_type<OptionTypes>{}(OptionCEFWidgetReghelper{}, *this);

    if (!app->getSystemSettings().enablePickingProperty_) {
        LogInfo(
            "Enabling picking system setting since it is required for interaction "
            "(View->Settings->System settings->Enable picking).");
        app->getSystemSettings().enablePickingProperty_.set(true);
    }
    // CEF initialization
    // Specify the path for the sub-process executable.
    auto exeExtension = filesystem::getFileExtension(filesystem::getExecutablePath());
    // Assume that inviwo_web_helper is next to the main executable
    auto exeDirectory = filesystem::getFileDirectory(filesystem::getExecutablePath());

    auto locale = app->getUILocale().name();
    if (locale == "C") {
        // Crash when default locale "C" is used. Reproduce with GLFWMinimum application
        locale = std::locale("en_US").name();
    }

    void* sandbox_info = NULL;  // Windows specific

#ifdef __APPLE__  // Mac specific

    // Find CEF framework and helper app in
    // exe.app/Contents/Frameworks directory first
    auto cefParentDir = filesystem::getCanonicalPath(exeDirectory + std::string("/.."));
    auto frameworkDirectory = cefParentDir + "/Frameworks/Chromium Embedded Framework.framework";
    auto frameworkPath = frameworkDirectory + "/Chromium Embedded Framework";
    // Load the CEF framework library at runtime instead of linking directly
    // as required by the macOS sandbox implementation.
    if (!cefLib_.LoadInMain()) {
        throw ModuleInitException("Could not find Chromium Embedded Framework.framework: " +
                                  frameworkPath);
    }

    CefMainArgs args(app->getCommandLineParser().getARGC(), app->getCommandLineParser().getARGV());
    CefSettings settings;
    // CefString(&settings.framework_dir_path).FromASCII((frameworkDirectory).c_str());
    // Crashes if not set and non-default locale is used
    CefString(&settings.locales_dir_path)
        .FromASCII((frameworkDirectory + std::string("/Resources")).c_str());
    CefString(&settings.resources_dir_path)
        .FromASCII((frameworkDirectory + std::string("/Resources")).c_str());
    // Locale returns "en_US.UFT8" but "en.UTF8" is needed by CEF
    auto startErasePos = locale.find('_');
    if (startErasePos != std::string::npos) {
        locale.erase(startErasePos, locale.find('.') - startErasePos);
    }

#else
    CefMainArgs args;
    CefSettings settings;
    // Non-mac systems uses a single helper executable so here we can specify name
    auto subProcessExecutable = exeDirectory + "/cef_web_helper." + exeExtension;
    if (!filesystem::fileExists(subProcessExecutable)) {
        throw ModuleInitException("Could not find web helper executable:" + subProcessExecutable);
    }

    // Necessary to run helpers in separate sub-processes
    // Needed since we do not want to edit the "main" function
    CefString(&settings.browser_subprocess_path).FromASCII(subProcessExecutable.c_str());
#endif

#ifdef WIN32
    // Enable High-DPI support on Windows 7 or newer.
    CefEnableHighDPISupport();
#if defined(CEF_USE_SANDBOX)
    // Manage the life span of the sandbox information object. This is necessary
    // for sandbox support on Windows. See cef_sandbox_win.h for complete details.
    CefScopedSandboxInfo scoped_sandbox;
    sandbox_info = scoped_sandbox.sandbox_info();
#endif
#endif
    // When generating projects with CMake the CEF_USE_SANDBOX value will be defined
    // automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
    // use of the sandbox.
#if !defined(CEF_USE_SANDBOX)
    settings.no_sandbox = true;
#endif
    // checkout detailed settings options
    // http://magpcss.org/ceforum/apidocs/projects/%28default%29/_cef_settings_t.html nearly all
    // the settings can be set via args too.
    settings.multi_threaded_message_loop = false;  // not supported, except windows

    // We want to use off-screen rendering
    settings.windowless_rendering_enabled = true;

    // Let the Inviwo application (Qt/GLFW) handle operating system event processing
    // instead of CEF. Setting external message pump to false will cause mouse events
    // to be processed in CefDoMessageLoopWork() instead of in the Qt application loop.
    settings.external_message_pump = true;

    CefString(&settings.locale).FromASCII(locale.c_str());

    // Optional implementation of the CefApp interface.
    CefRefPtr<WebBrowserApp> browserApp(new WebBrowserApp);

    bool result = CefInitialize(args, settings, browserApp, sandbox_info);

    if (!result) {
        throw ModuleInitException("Failed to initialize Chromium Embedded Framework");
    }

    // Add a directory to the search path of the Shadermanager
    webbrowser::addShaderResources(ShaderManager::getPtr(), {getPath(ModulePath::GLSL)});
    // ShaderManager::getPtr()->addShaderSearchPath(getPath(ModulePath::GLSL));

    // Register objects that can be shared with the rest of inviwo here:

    // Processors
    registerProcessor<WebBrowserProcessor>();

    doChromiumWork_.start();
}

WebBrowserModule::~WebBrowserModule() {
    // Stop message pumping and make sure that app has finished processing before CefShutdown
    doChromiumWork_.stop();
    app_->waitForPool();
    CefShutdown();
}

std::string WebBrowserModule::getDataURI(const std::string& data, const std::string& mime_type) {
    return "data:" + mime_type + ";base64," +
           CefURIEncode(CefBase64Encode(data.data(), data.size()), false).ToString();
}

std::string WebBrowserModule::getCefErrorString(cef_errorcode_t code) {
    switch (code) {
        case ERR_NONE:
            return "ERR_NONE";
        case ERR_FAILED:
            return "ERR_FAILED";
        case ERR_ABORTED:
            return "ERR_ABORTED";
        case ERR_INVALID_ARGUMENT:
            return "ERR_INVALID_ARGUMENT";
        case ERR_INVALID_HANDLE:
            return "ERR_INVALID_HANDLE";
        case ERR_FILE_NOT_FOUND:
            return "ERR_FILE_NOT_FOUND";
        case ERR_TIMED_OUT:
            return "ERR_TIMED_OUT";
        case ERR_FILE_TOO_BIG:
            return "ERR_FILE_TOO_BIG";
        case ERR_UNEXPECTED:
            return "ERR_UNEXPECTED";
        case ERR_ACCESS_DENIED:
            return "ERR_ACCESS_DENIED";
        case ERR_NOT_IMPLEMENTED:
            return "ERR_NOT_IMPLEMENTED";
        case ERR_CONNECTION_CLOSED:
            return "ERR_CONNECTION_CLOSED";
        case ERR_CONNECTION_RESET:
            return "ERR_CONNECTION_RESET";
        case ERR_CONNECTION_REFUSED:
            return "ERR_CONNECTION_REFUSED";
        case ERR_CONNECTION_ABORTED:
            return "ERR_CONNECTION_ABORTED";
        case ERR_CONNECTION_FAILED:
            return "ERR_CONNECTION_FAILED";
        case ERR_NAME_NOT_RESOLVED:
            return "ERR_NAME_NOT_RESOLVED";
        case ERR_INTERNET_DISCONNECTED:
            return "ERR_INTERNET_DISCONNECTED";
        case ERR_SSL_PROTOCOL_ERROR:
            return "ERR_SSL_PROTOCOL_ERROR";
        case ERR_ADDRESS_INVALID:
            return "ERR_ADDRESS_INVALID";
        case ERR_ADDRESS_UNREACHABLE:
            return "ERR_ADDRESS_UNREACHABLE";
        case ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
            return "ERR_SSL_CLIENT_AUTH_CERT_NEEDED";
        case ERR_TUNNEL_CONNECTION_FAILED:
            return "ERR_TUNNEL_CONNECTION_FAILED";
        case ERR_NO_SSL_VERSIONS_ENABLED:
            return "ERR_NO_SSL_VERSIONS_ENABLED";
        case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
            return "ERR_SSL_VERSION_OR_CIPHER_MISMATCH";
        case ERR_SSL_RENEGOTIATION_REQUESTED:
            return "ERR_SSL_RENEGOTIATION_REQUESTED";
        case ERR_CERT_COMMON_NAME_INVALID:
            return "ERR_CERT_COMMON_NAME_INVALID";
        case ERR_CERT_DATE_INVALID:
            return "ERR_CERT_DATE_INVALID";
        case ERR_CERT_AUTHORITY_INVALID:
            return "ERR_CERT_AUTHORITY_INVALID";
        case ERR_CERT_CONTAINS_ERRORS:
            return "ERR_CERT_CONTAINS_ERRORS";
        case ERR_CERT_NO_REVOCATION_MECHANISM:
            return "ERR_CERT_NO_REVOCATION_MECHANISM";
        case ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
            return "ERR_CERT_UNABLE_TO_CHECK_REVOCATION";
        case ERR_CERT_REVOKED:
            return "ERR_CERT_REVOKED";
        case ERR_CERT_INVALID:
            return "ERR_CERT_INVALID";
        case ERR_CERT_END:
            return "ERR_CERT_END";
        case ERR_INVALID_URL:
            return "ERR_INVALID_URL";
        case ERR_DISALLOWED_URL_SCHEME:
            return "ERR_DISALLOWED_URL_SCHEME";
        case ERR_UNKNOWN_URL_SCHEME:
            return "ERR_UNKNOWN_URL_SCHEME";
        case ERR_TOO_MANY_REDIRECTS:
            return "ERR_TOO_MANY_REDIRECTS";
        case ERR_UNSAFE_REDIRECT:
            return "ERR_UNSAFE_REDIRECT";
        case ERR_UNSAFE_PORT:
            return "ERR_UNSAFE_PORT";
        case ERR_INVALID_RESPONSE:
            return "ERR_INVALID_RESPONSE";
        case ERR_INVALID_CHUNKED_ENCODING:
            return "ERR_INVALID_CHUNKED_ENCODING";
        case ERR_METHOD_NOT_SUPPORTED:
            return "ERR_METHOD_NOT_SUPPORTED";
        case ERR_UNEXPECTED_PROXY_AUTH:
            return "ERR_UNEXPECTED_PROXY_AUTH";
        case ERR_EMPTY_RESPONSE:
            return "ERR_EMPTY_RESPONSE";
        case ERR_RESPONSE_HEADERS_TOO_BIG:
            return "ERR_RESPONSE_HEADERS_TOO_BIG";
        case ERR_CACHE_MISS:
            return "ERR_CACHE_MISS";
        case ERR_INSECURE_RESPONSE:
            return "ERR_INSECURE_RESPONSE";
        default:
            return "UNKNOWN";
    }
}
}  // namespace inviwo
<commit_msg>Webbrowser: Exexutable extension path fix<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2018-2019 Inviwo Foundation
 * 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.
 *
 * 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.
 *
 *********************************************************************************/

#include <modules/webbrowser/webbrowsermodule.h>
#include <modules/webbrowser/processors/webbrowserprocessor.h>
#include <modules/webbrowser/webbrowserapp.h>

#include <modules/json/io/json/boolpropertyjsonconverter.h>
#include <modules/json/io/json/buttonpropertyjsonconverter.h>
#include <modules/json/io/json/directorypropertyjsonconverter.h>
#include <modules/json/io/json/filepropertyjsonconverter.h>
#include <modules/json/io/json/minmaxpropertyjsonconverter.h>
#include <modules/json/io/json/optionpropertyjsonconverter.h>
#include <modules/json/io/json/ordinalpropertyjsonconverter.h>
#include <modules/json/io/json/templatepropertyjsonconverter.h>

#include <inviwo/dataframe/io/json/dataframepropertyjsonconverter.h>

#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/util/settings/systemsettings.h>

#include <modules/opengl/shader/shadermanager.h>

// Autogenerated
#include <modules/webbrowser/shader_resources.h>

#include <warn/push>
#include <warn/ignore/all>
#include "include/cef_app.h"
#include "include/cef_command_line.h"
#include "include/cef_parser.h"
#include <warn/pop>

namespace inviwo {

struct OrdinalCEFWidgetReghelper {
    template <typename T>
    auto operator()(WebBrowserModule& m) {
        using PropertyType = OrdinalProperty<T>;
        m.registerPropertyWidgetCEF<PropertyWidgetCEF, PropertyType>();
    }
};

struct MinMaxCEFWidgetReghelper {
    template <typename T>
    auto operator()(WebBrowserModule& m) {
        using PropertyType = MinMaxProperty<T>;
        m.registerPropertyWidgetCEF<PropertyWidgetCEF, PropertyType>();
    }
};

struct OptionCEFWidgetReghelper {
    template <typename T>
    auto operator()(WebBrowserModule& m) {
        using PropertyType = TemplateOptionProperty<T>;
        m.registerPropertyWidgetCEF<PropertyWidgetCEF, PropertyType>();
    }
};

WebBrowserModule::WebBrowserModule(InviwoApplication* app)
    : InviwoModule(app, "WebBrowser")
    // Call 60 times per second
    , doChromiumWork_(Timer::Milliseconds(1000 / 60), []() { CefDoMessageLoopWork(); }) {

    // Register widgets
    registerPropertyWidgetCEF<PropertyWidgetCEF, BoolProperty>();
    registerPropertyWidgetCEF<PropertyWidgetCEF, ButtonProperty>();
    registerPropertyWidgetCEF<PropertyWidgetCEF, FileProperty>();
    registerPropertyWidgetCEF<PropertyWidgetCEF, DirectoryProperty>();
    registerPropertyWidgetCEF<PropertyWidgetCEF, StringProperty>();

    registerPropertyWidgetCEF<PropertyWidgetCEF, DataFrameColumnProperty>();

    // Register ordinal property widgets
    using OrdinalTypes =
        std::tuple<float, vec2, vec3, vec4, mat2, mat3, mat4, double, dvec2, dvec3, dvec4, dmat2,
                   dmat3, dmat4, int, ivec2, ivec3, ivec4, glm::i64, unsigned int, uvec2, uvec3,
                   uvec4, size_t, size2_t, size3_t, size4_t, glm::fquat, glm::dquat>;

    using ScalarTypes = std::tuple<float, double, int, glm::i64, size_t>;
    util::for_each_type<OrdinalTypes>{}(OrdinalCEFWidgetReghelper{}, *this);

    // Register MinMaxProperty widgets
    util::for_each_type<ScalarTypes>{}(MinMaxCEFWidgetReghelper{}, *this);

    // Register option property widgets
    using OptionTypes = std::tuple<unsigned int, int, size_t, float, double, std::string>;
    util::for_each_type<OptionTypes>{}(OptionCEFWidgetReghelper{}, *this);

    if (!app->getSystemSettings().enablePickingProperty_) {
        LogInfo(
            "Enabling picking system setting since it is required for interaction "
            "(View->Settings->System settings->Enable picking).");
        app->getSystemSettings().enablePickingProperty_.set(true);
    }
    // CEF initialization
    // Specify the path for the sub-process executable.
    auto exeExtension = filesystem::getFileExtension(filesystem::getExecutablePath());
    // Assume that inviwo_web_helper is next to the main executable
    auto exeDirectory = filesystem::getFileDirectory(filesystem::getExecutablePath());

    auto locale = app->getUILocale().name();
    if (locale == "C") {
        // Crash when default locale "C" is used. Reproduce with GLFWMinimum application
        locale = std::locale("en_US").name();
    }

    void* sandbox_info = NULL;  // Windows specific

#ifdef __APPLE__  // Mac specific

    // Find CEF framework and helper app in
    // exe.app/Contents/Frameworks directory first
    auto cefParentDir = filesystem::getCanonicalPath(exeDirectory + std::string("/.."));
    auto frameworkDirectory = cefParentDir + "/Frameworks/Chromium Embedded Framework.framework";
    auto frameworkPath = frameworkDirectory + "/Chromium Embedded Framework";
    // Load the CEF framework library at runtime instead of linking directly
    // as required by the macOS sandbox implementation.
    if (!cefLib_.LoadInMain()) {
        throw ModuleInitException("Could not find Chromium Embedded Framework.framework: " +
                                  frameworkPath);
    }

    CefMainArgs args(app->getCommandLineParser().getARGC(), app->getCommandLineParser().getARGV());
    CefSettings settings;
    // CefString(&settings.framework_dir_path).FromASCII((frameworkDirectory).c_str());
    // Crashes if not set and non-default locale is used
    CefString(&settings.locales_dir_path)
        .FromASCII((frameworkDirectory + std::string("/Resources")).c_str());
    CefString(&settings.resources_dir_path)
        .FromASCII((frameworkDirectory + std::string("/Resources")).c_str());
    // Locale returns "en_US.UFT8" but "en.UTF8" is needed by CEF
    auto startErasePos = locale.find('_');
    if (startErasePos != std::string::npos) {
        locale.erase(startErasePos, locale.find('.') - startErasePos);
    }

#else
    CefMainArgs args;
    CefSettings settings;
    // Non-mac systems uses a single helper executable so here we can specify name
    // Linux will have empty extension
    auto subProcessExecutable = fmt::format("{}/{}{}{}", exeDirectory, "cef_web_helper", exeExtension.empty() ? "": ".", exeExtension);
    if (!filesystem::fileExists(subProcessExecutable)) {
        throw ModuleInitException("Could not find web helper executable:" + subProcessExecutable);
    }

    // Necessary to run helpers in separate sub-processes
    // Needed since we do not want to edit the "main" function
    CefString(&settings.browser_subprocess_path).FromASCII(subProcessExecutable.c_str());
#endif

#ifdef WIN32
    // Enable High-DPI support on Windows 7 or newer.
    CefEnableHighDPISupport();
#if defined(CEF_USE_SANDBOX)
    // Manage the life span of the sandbox information object. This is necessary
    // for sandbox support on Windows. See cef_sandbox_win.h for complete details.
    CefScopedSandboxInfo scoped_sandbox;
    sandbox_info = scoped_sandbox.sandbox_info();
#endif
#endif
    // When generating projects with CMake the CEF_USE_SANDBOX value will be defined
    // automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
    // use of the sandbox.
#if !defined(CEF_USE_SANDBOX)
    settings.no_sandbox = true;
#endif
    // checkout detailed settings options
    // http://magpcss.org/ceforum/apidocs/projects/%28default%29/_cef_settings_t.html nearly all
    // the settings can be set via args too.
    settings.multi_threaded_message_loop = false;  // not supported, except windows

    // We want to use off-screen rendering
    settings.windowless_rendering_enabled = true;

    // Let the Inviwo application (Qt/GLFW) handle operating system event processing
    // instead of CEF. Setting external message pump to false will cause mouse events
    // to be processed in CefDoMessageLoopWork() instead of in the Qt application loop.
    settings.external_message_pump = true;

    CefString(&settings.locale).FromASCII(locale.c_str());

    // Optional implementation of the CefApp interface.
    CefRefPtr<WebBrowserApp> browserApp(new WebBrowserApp);

    bool result = CefInitialize(args, settings, browserApp, sandbox_info);

    if (!result) {
        throw ModuleInitException("Failed to initialize Chromium Embedded Framework");
    }

    // Add a directory to the search path of the Shadermanager
    webbrowser::addShaderResources(ShaderManager::getPtr(), {getPath(ModulePath::GLSL)});
    // ShaderManager::getPtr()->addShaderSearchPath(getPath(ModulePath::GLSL));

    // Register objects that can be shared with the rest of inviwo here:

    // Processors
    registerProcessor<WebBrowserProcessor>();

    doChromiumWork_.start();
}

WebBrowserModule::~WebBrowserModule() {
    // Stop message pumping and make sure that app has finished processing before CefShutdown
    doChromiumWork_.stop();
    app_->waitForPool();
    CefShutdown();
}

std::string WebBrowserModule::getDataURI(const std::string& data, const std::string& mime_type) {
    return "data:" + mime_type + ";base64," +
           CefURIEncode(CefBase64Encode(data.data(), data.size()), false).ToString();
}

std::string WebBrowserModule::getCefErrorString(cef_errorcode_t code) {
    switch (code) {
        case ERR_NONE:
            return "ERR_NONE";
        case ERR_FAILED:
            return "ERR_FAILED";
        case ERR_ABORTED:
            return "ERR_ABORTED";
        case ERR_INVALID_ARGUMENT:
            return "ERR_INVALID_ARGUMENT";
        case ERR_INVALID_HANDLE:
            return "ERR_INVALID_HANDLE";
        case ERR_FILE_NOT_FOUND:
            return "ERR_FILE_NOT_FOUND";
        case ERR_TIMED_OUT:
            return "ERR_TIMED_OUT";
        case ERR_FILE_TOO_BIG:
            return "ERR_FILE_TOO_BIG";
        case ERR_UNEXPECTED:
            return "ERR_UNEXPECTED";
        case ERR_ACCESS_DENIED:
            return "ERR_ACCESS_DENIED";
        case ERR_NOT_IMPLEMENTED:
            return "ERR_NOT_IMPLEMENTED";
        case ERR_CONNECTION_CLOSED:
            return "ERR_CONNECTION_CLOSED";
        case ERR_CONNECTION_RESET:
            return "ERR_CONNECTION_RESET";
        case ERR_CONNECTION_REFUSED:
            return "ERR_CONNECTION_REFUSED";
        case ERR_CONNECTION_ABORTED:
            return "ERR_CONNECTION_ABORTED";
        case ERR_CONNECTION_FAILED:
            return "ERR_CONNECTION_FAILED";
        case ERR_NAME_NOT_RESOLVED:
            return "ERR_NAME_NOT_RESOLVED";
        case ERR_INTERNET_DISCONNECTED:
            return "ERR_INTERNET_DISCONNECTED";
        case ERR_SSL_PROTOCOL_ERROR:
            return "ERR_SSL_PROTOCOL_ERROR";
        case ERR_ADDRESS_INVALID:
            return "ERR_ADDRESS_INVALID";
        case ERR_ADDRESS_UNREACHABLE:
            return "ERR_ADDRESS_UNREACHABLE";
        case ERR_SSL_CLIENT_AUTH_CERT_NEEDED:
            return "ERR_SSL_CLIENT_AUTH_CERT_NEEDED";
        case ERR_TUNNEL_CONNECTION_FAILED:
            return "ERR_TUNNEL_CONNECTION_FAILED";
        case ERR_NO_SSL_VERSIONS_ENABLED:
            return "ERR_NO_SSL_VERSIONS_ENABLED";
        case ERR_SSL_VERSION_OR_CIPHER_MISMATCH:
            return "ERR_SSL_VERSION_OR_CIPHER_MISMATCH";
        case ERR_SSL_RENEGOTIATION_REQUESTED:
            return "ERR_SSL_RENEGOTIATION_REQUESTED";
        case ERR_CERT_COMMON_NAME_INVALID:
            return "ERR_CERT_COMMON_NAME_INVALID";
        case ERR_CERT_DATE_INVALID:
            return "ERR_CERT_DATE_INVALID";
        case ERR_CERT_AUTHORITY_INVALID:
            return "ERR_CERT_AUTHORITY_INVALID";
        case ERR_CERT_CONTAINS_ERRORS:
            return "ERR_CERT_CONTAINS_ERRORS";
        case ERR_CERT_NO_REVOCATION_MECHANISM:
            return "ERR_CERT_NO_REVOCATION_MECHANISM";
        case ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
            return "ERR_CERT_UNABLE_TO_CHECK_REVOCATION";
        case ERR_CERT_REVOKED:
            return "ERR_CERT_REVOKED";
        case ERR_CERT_INVALID:
            return "ERR_CERT_INVALID";
        case ERR_CERT_END:
            return "ERR_CERT_END";
        case ERR_INVALID_URL:
            return "ERR_INVALID_URL";
        case ERR_DISALLOWED_URL_SCHEME:
            return "ERR_DISALLOWED_URL_SCHEME";
        case ERR_UNKNOWN_URL_SCHEME:
            return "ERR_UNKNOWN_URL_SCHEME";
        case ERR_TOO_MANY_REDIRECTS:
            return "ERR_TOO_MANY_REDIRECTS";
        case ERR_UNSAFE_REDIRECT:
            return "ERR_UNSAFE_REDIRECT";
        case ERR_UNSAFE_PORT:
            return "ERR_UNSAFE_PORT";
        case ERR_INVALID_RESPONSE:
            return "ERR_INVALID_RESPONSE";
        case ERR_INVALID_CHUNKED_ENCODING:
            return "ERR_INVALID_CHUNKED_ENCODING";
        case ERR_METHOD_NOT_SUPPORTED:
            return "ERR_METHOD_NOT_SUPPORTED";
        case ERR_UNEXPECTED_PROXY_AUTH:
            return "ERR_UNEXPECTED_PROXY_AUTH";
        case ERR_EMPTY_RESPONSE:
            return "ERR_EMPTY_RESPONSE";
        case ERR_RESPONSE_HEADERS_TOO_BIG:
            return "ERR_RESPONSE_HEADERS_TOO_BIG";
        case ERR_CACHE_MISS:
            return "ERR_CACHE_MISS";
        case ERR_INSECURE_RESPONSE:
            return "ERR_INSECURE_RESPONSE";
        default:
            return "UNKNOWN";
    }
}
}  // namespace inviwo
<|endoftext|>


<commit_before>// Copyright (c) 2015-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "compat.h"
#include "prevector.h"

#include "bench/bench.h"

struct nontrivial_t {
    int x;
    nontrivial_t() :x(-1) {}
};
static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE<nontrivial_t>::value,
              "expected nontrivial_t to not be trivially constructible");

typedef unsigned char trivial_t;
static_assert(IS_TRIVIALLY_CONSTRUCTIBLE<trivial_t>::value,
              "expected trivial_t to be trivially constructible");

template <typename T>
static void PrevectorDestructor(benchmark::State& state)
{
    while (state.KeepRunning()) {
        for (auto x = 0; x < 1000; ++x) {
            prevector<28, T> t0;
            prevector<28, T> t1;
            t0.resize(28);
            t1.resize(29);
        }
    }
}

template <typename T>
static void PrevectorClear(benchmark::State& state)
{

    while (state.KeepRunning()) {
        for (auto x = 0; x < 1000; ++x) {
            prevector<28, T> t0;
            prevector<28, T> t1;
            t0.resize(28);
            t0.clear();
            t1.resize(29);
            t0.clear();
        }
    }
}

template <typename T>
void PrevectorResize(benchmark::State& state)
{
    while (state.KeepRunning()) {
        prevector<28, T> t0;
        prevector<28, T> t1;
        for (auto x = 0; x < 1000; ++x) {
            t0.resize(28);
            t0.resize(0);
            t1.resize(29);
            t1.resize(0);
        }
    }
}

#define PREVECTOR_TEST(name, nontrivops, trivops)                       \
    static void Prevector ## name ## Nontrivial(benchmark::State& state) { \
        PrevectorResize<nontrivial_t>(state);                           \
    }                                                                   \
    BENCHMARK(Prevector ## name ## Nontrivial, nontrivops);             \
    static void Prevector ## name ## Trivial(benchmark::State& state) { \
        PrevectorResize<trivial_t>(state);                              \
    }                                                                   \
    BENCHMARK(Prevector ## name ## Trivial, trivops);

PREVECTOR_TEST(Clear, 28300, 88600)
PREVECTOR_TEST(Destructor, 28800, 88900)
PREVECTOR_TEST(Resize, 28900, 90300)
<commit_msg>Temporarily remove arguments to BENCHMARK<commit_after>// Copyright (c) 2015-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "compat.h"
#include "prevector.h"

#include "bench/bench.h"

struct nontrivial_t {
    int x;
    nontrivial_t() :x(-1) {}
};
static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE<nontrivial_t>::value,
              "expected nontrivial_t to not be trivially constructible");

typedef unsigned char trivial_t;
static_assert(IS_TRIVIALLY_CONSTRUCTIBLE<trivial_t>::value,
              "expected trivial_t to be trivially constructible");

template <typename T>
static void PrevectorDestructor(benchmark::State& state)
{
    while (state.KeepRunning()) {
        for (auto x = 0; x < 1000; ++x) {
            prevector<28, T> t0;
            prevector<28, T> t1;
            t0.resize(28);
            t1.resize(29);
        }
    }
}

template <typename T>
static void PrevectorClear(benchmark::State& state)
{

    while (state.KeepRunning()) {
        for (auto x = 0; x < 1000; ++x) {
            prevector<28, T> t0;
            prevector<28, T> t1;
            t0.resize(28);
            t0.clear();
            t1.resize(29);
            t0.clear();
        }
    }
}

template <typename T>
void PrevectorResize(benchmark::State& state)
{
    while (state.KeepRunning()) {
        prevector<28, T> t0;
        prevector<28, T> t1;
        for (auto x = 0; x < 1000; ++x) {
            t0.resize(28);
            t0.resize(0);
            t1.resize(29);
            t1.resize(0);
        }
    }
}

#define PREVECTOR_TEST(name, nontrivops, trivops)                       \
    static void Prevector ## name ## Nontrivial(benchmark::State& state) { \
        PrevectorResize<nontrivial_t>(state);                           \
    }                                                                   \
    BENCHMARK(Prevector ## name ## Nontrivial/*, nontrivops*/);             \
    static void Prevector ## name ## Trivial(benchmark::State& state) { \
        PrevectorResize<trivial_t>(state);                              \
    }                                                                   \
    BENCHMARK(Prevector ## name ## Trivial/*, trivops*/);

PREVECTOR_TEST(Clear, 28300, 88600)
PREVECTOR_TEST(Destructor, 28800, 88900)
PREVECTOR_TEST(Resize, 28900, 90300)
<|endoftext|>


<commit_before>/*
 * DynBetweenness.cpp
 *
 *  Created on: 29.07.2014
 *      Author: ebergamini
 */
#include <stack>
#include <queue>
#include <memory>

#include "../auxiliary/PrioQueue.h"
#include "DynBetweenness.h"
#include "../auxiliary/PrioQueue.h"
#include "../auxiliary/Log.h"
#include "../graph/SSSP.h"
#include "../graph/Dijkstra.h"
#include "../graph/BFS.h"

namespace NetworKit {
DynBetweenness::DynBetweenness(const Graph& G, bool storePredecessors) : Centrality(G, normalized),
maxDistance(G.upperNodeIdBound()),
npaths(G.upperNodeIdBound(), std::vector<count>(G.upperNodeIdBound())),
distances(G.upperNodeIdBound(), std::vector<edgeweight>(G.upperNodeIdBound())),
dependencies(G.upperNodeIdBound(),std::vector<double>(G.upperNodeIdBound(), 0.0)),
storePreds(storePredecessors) {

}

inline bool logically_equal(double a, double b, double error_factor=1.0)
{
  return a==b || std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*error_factor;
}

void DynBetweenness::run() {
    count z = G.upperNodeIdBound();
    scoreData.clear();
    scoreData.resize(z);
    npaths.clear();
    npaths.resize(z);
    distances.clear();
    distances.resize(z);
    dependencies.clear();
    dependencies.resize(z);
    if (storePreds) {
        predecessors.clear();
        predecessors.resize(G.upperNodeIdBound());
        G.forNodes([&](node v){
            predecessors[v].resize(G.upperNodeIdBound());
        });
    }

    auto computeDependencies = [&](node s) {
        // run SSSP algorithm and keep track of everything
        std::unique_ptr<SSSP> sssp;
        if (G.isWeighted()) {
            sssp.reset(new Dijkstra(G, s, true, true));
        } else {
            sssp.reset(new BFS(G, s, true, true));
        }

        sssp->run();

        G.forNodes([&](node t){
            distances[s][t] = sssp->distance(t);
            npaths[s][t] = sssp->numberOfPaths(t);
            if (storePreds) {
                predecessors[s][t] = sssp->getPredecessors(t);
            }
        });

        // compute dependencies for nodes in order of decreasing distance from s
        std::stack<node> stack = sssp->getStack();
        // set maxDistance to the distance of the furthest vertex
        maxDistance[s] = distances[s][stack.top()];
        while (!stack.empty()) {
            node t = stack.top();
            stack.pop();
            for (node p : sssp->getPredecessors(t)) {
                dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
            }
            if (t != s) {
                scoreData[t] += dependencies[s][t];
            }
        }
    };

    G.forNodes(computeDependencies);
}

void DynBetweenness::updateUnweighted(GraphEvent e) {
    G.forNodes([&] (node s){
        node u_l, u_h;
        if (distances[s][e.u] > distances[s][e.v]){
            u_l = e.u;
            u_h = e.v;
        } else {
            u_l = e.v;
            u_h = e.u;
        }
        edgeweight difference = distances[s][u_l] - distances[s][u_h];
        if (difference > 0) {
            std::vector<count> new_npaths(G.upperNodeIdBound());
            std::vector<edgeweight> new_dist(G.upperNodeIdBound());
            G.forNodes([&] (node v){
                new_npaths[v] = npaths[s][v];
                new_dist[v] = distances[s][v];
            });
            std::vector<double> new_dep(G.upperNodeIdBound(), 0.0);
            std::vector<int> touched(G.upperNodeIdBound(), 0);
            std::vector<std::queue<node>> l_queues(maxDistance[s]+1);
            std::queue<node> queue_BFS;
            queue_BFS.push(u_l);
            // one-level update
            if (difference == 1) {
                l_queues[distances[s][u_l]].push(u_l);
                if (storePreds)
                    predecessors[s][u_l].push_back(u_h);
                new_npaths[u_l] += npaths[s][u_h];
                touched[u_l] = -1;
                // BFS traversal from u_l
                while (!queue_BFS.empty()) {
                    node v = queue_BFS.front();
                    DEBUG("extracted node ", v);
                    queue_BFS.pop();
                    G.forNeighborsOf(v, [&](node w) {
                        if (new_dist[w] == new_dist[v]+1) {
                            if (touched[w] == 0) {
                                touched[w] = -1;
                                queue_BFS.push(w);
                                l_queues[new_dist[w]].push(w);
                            }
                            new_npaths[w] = new_npaths[w] - npaths[s][v] + new_npaths[v];
                        }
                    });
                }
            } else if (difference > 1) {
                new_dist[u_l] = distances[s][u_h] + 1;
                l_queues[new_dist[u_l]].push(u_l);
                // BFS traversal from u_l
                while (!queue_BFS.empty()) {
                    node v = queue_BFS.front();
                    DEBUG("extracted node ",v);
                    if (storePreds) {
                        predecessors[s][v].clear();
                    }
                    queue_BFS.pop();
                    touched[v] = -1;
                    new_npaths[v] = 0;
                    G.forNeighborsOf(v, [&] (node w){
                            if (new_dist[w] + 1 == new_dist[v]) {
                                new_npaths[v] += new_npaths[w];
                                if (storePreds) {
                                    predecessors[s][v].push_back(w);
                                }
                            }
                            if (new_dist[w] >= new_dist[v] && touched[w] == 0) {
                                if (new_dist[w] > new_dist[v])
                                    new_dist[w] = new_dist[v]+1;
                                touched[w] = -1;
                                l_queues[new_dist[w]].push(w);
                                queue_BFS.push(w);
                            }
                    });
                }
            }
            // dependencies accumulation
            DEBUG("Dependency accumulation");
            count level = maxDistance[s];
            while(level > 0) {
                while(!l_queues[level].empty()) {
                    node w = l_queues[level].front();
                    DEBUG("Node ",w);
                    l_queues[level].pop();
                    auto updateDependency = [&](node w, node v) {
                        if (new_dist[v] < new_dist[w]) {
                            if (touched[v] == 0) {
                                touched[v] = 1;
                                new_dep[v] = dependencies[s][v];
                                l_queues[level-1].push(v);
                            }
                            double new_contrib = double(new_npaths[v])/new_npaths[w]*(1+new_dep[w]);
                            new_dep[v] += new_contrib;
                            double old_contrib = double(npaths[s][v])/npaths[s][w]*(1+dependencies[s][w]);
                            if (touched[v] == 1 && (v != u_h or w!= u_l))
                                new_dep[v] -= old_contrib;
                            DEBUG("Parent ", v);
                        }
                    };
                    if (storePreds) {
                        for (node v : predecessors[s][w]) {
                            updateDependency(w, v);
                        }
                    }
                    else {
                        G.forNeighborsOf(w, [&](node v){
                            updateDependency(w, v);
                        });
                    }
                    if (w != s) {
                        scoreData[w] = scoreData[w] + new_dep[w] - dependencies[s][w];
                    }
                }
                level = level - 1;
            }
            // data structures update
            G.forNodes([&] (node r){
                distances[s][r] = new_dist[r];
                npaths[s][r] = new_npaths[r];
                if (touched[r] != 0)
                    dependencies[s][r] = new_dep[r];
            });
        }
/*

        BFS sssp(G, s, true, true);
        sssp.run();
        G.forNodes([&](node t){
            if(distances[s][t] != sssp.distance(t) || npaths[s][t] != sssp.numberOfPaths(t)) {
                std::cout<<"Source: "<<s<<"  Node "<<t<<std::endl;
                std::cout<<"COMPUTED DISTANCE: "<<distances[s][t]<<"  REAL DISTANCE: "<<sssp.distance(t)<<std::endl;
                std::cout<<"COMPUTED NUMBER OF PATHS: "<<npaths[s][t]<<"  REAL NUMBER OF PATHS: "<<sssp.numberOfPaths(t)<<std::endl;
            }
        });

        // compute dependencies for nodes in order of decreasing distance from s
        std::vector<double> dep(G.upperNodeIdBound());
        std::stack<node> stack = sssp.getStack();
        while (!stack.empty()) {
            node t = stack.top();
            stack.pop();
            for (node p : sssp.getPredecessors(t)) {
                dep[p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dep[t]);
            }
        }

        G.forNodes([&](node t){
            if((dependencies[s][t]-dep[t]>0.000001 || dependencies[s][t]-dep[t]<-0.000001) && s!=t) {
                std::cout<<"Source: "<<s<<"  Node "<<t<<std::endl;
                std::cout<<"COMPUTED DEPENDENCY: "<<dependencies[s][t]<<"  REAL DEPENDENCY: "<<dep[t]<<std::endl;
            }
        });

*/

    });
}

void DynBetweenness::updateWeighted(GraphEvent e) {
    G.forNodes([&] (node s){
        scoreData[s] = 0.0;
    });
    G.forNodes([&] (node s){
        // update of distances and number of shortest paths
        Aux::PrioQueue<double, node> S(G.upperNodeIdBound());
        G.forNodes([&] (node t){
            auto updatePaths = [&](node u, node v, edgeweight w) {
                if (distances[s][t] == distances[s][u] + w + distances[v][t]){
                    npaths[s][t] = npaths[s][t] + npaths[s][u] * npaths[v][t];
                    if (storePreds) {
                        if (t != v){
                            DEBUG("Adding predecessors from v to t to predecessors from s to t");
                            //predecessors[s][t].insert( predecessors[s][t].end(), predecessors[v][t].begin(), predecessors[v][t].end());
                            for (node pv : predecessors[v][t]) {
                                bool wasAlreadyPred = false;
                                for (node ps : predecessors[s][t]) {
                                    if (ps == pv)
                                        wasAlreadyPred = true;
                                }
                                if (!wasAlreadyPred)
                                    predecessors[s][t].push_back(pv);
                            }
                            DEBUG("Finished adding");
                        }
                        else {
                            DEBUG("Adding u to the predecessors of v");
                            predecessors[s][t].push_back(u);
                            DEBUG("Finished adding");
                        }
                    }
                }
                if (distances[s][t] > distances[s][u] + w + distances[v][t]){
                    distances[s][t] = distances[s][u] + w + distances[v][t];
                    npaths[s][t] = npaths[s][u] * npaths[v][t];
                    if (storePreds) {
                        if (t != v) {
                            DEBUG("Replacing predecessors from v to t with predecessors from s to t");
                            predecessors[s][t] = predecessors[v][t];
                            DEBUG("Finished replacing");
                        }
                        else {
                            DEBUG("Replacing old predecessors of v with u");
                            predecessors[s][t].clear();
                            predecessors[s][t].push_back(u);
                            DEBUG("Finished replacing");
                        }
                    }
                }
            };
            if (s != t) {
                updatePaths(e.u, e.v, e.w);
                updatePaths(e.v, e.u, e.w);
                S.insert(-1*distances[s][t], t);
                dependencies[s][t] = 0.0;
            }
        });
        // dependency accumulation
        while (S.size() != 0) {
            // extract the node with the maximum distance
            node t = S.extractMin().second;
            if (storePreds) {
                DEBUG("Computing dependencies");
                for (node p : predecessors[s][t]) {
                    dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
                }
            }
            else {
                G.forNeighborsOf(t, [&] (node p){
                    if (logically_equal(distances[s][t], distances[s][p] + G.weight(p, t))) {
                        dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
                    }
                });
            }
            if (t != s) {
                scoreData[t] += dependencies[s][t];
            }
        }

    });

}

void DynBetweenness::update(GraphEvent e) {
    if (G.isWeighted())
        updateWeighted(e);
    else
        updateUnweighted(e);
}

} /* namespace NetworKit */
<commit_msg>inserted cleaning of structures at the beginning of the run method in dynbetweenness<commit_after>/*
 * DynBetweenness.cpp
 *
 *  Created on: 29.07.2014
 *      Author: ebergamini
 */
#include <stack>
#include <queue>
#include <memory>

#include "../auxiliary/PrioQueue.h"
#include "DynBetweenness.h"
#include "../auxiliary/PrioQueue.h"
#include "../auxiliary/Log.h"
#include "../graph/SSSP.h"
#include "../graph/Dijkstra.h"
#include "../graph/BFS.h"

namespace NetworKit {
DynBetweenness::DynBetweenness(const Graph& G, bool storePredecessors) : Centrality(G, normalized),
maxDistance(G.upperNodeIdBound()),
npaths(G.upperNodeIdBound(), std::vector<count>(G.upperNodeIdBound())),
distances(G.upperNodeIdBound(), std::vector<edgeweight>(G.upperNodeIdBound())),
dependencies(G.upperNodeIdBound(),std::vector<double>(G.upperNodeIdBound(), 0.0)),
storePreds(storePredecessors) {

}

inline bool logically_equal(double a, double b, double error_factor=1.0)
{
  return a==b || std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*error_factor;
}

void DynBetweenness::run() {
    count z = G.upperNodeIdBound();
    scoreData.clear();
    scoreData.resize(z);
/*    npaths.clear();
    npaths.resize(z);
    distances.clear();
    distances.resize(z);
    dependencies.clear();
    dependencies.resize(z);
*/
    if (storePreds) {
        predecessors.clear();
        predecessors.resize(G.upperNodeIdBound());
        G.forNodes([&](node v){
            predecessors[v].resize(G.upperNodeIdBound());
        });
    }

    auto computeDependencies = [&](node s) {
        // run SSSP algorithm and keep track of everything
        std::unique_ptr<SSSP> sssp;
        if (G.isWeighted()) {
            sssp.reset(new Dijkstra(G, s, true, true));
        } else {
            sssp.reset(new BFS(G, s, true, true));
        }

        sssp->run();

        G.forNodes([&](node t){
            distances[s][t] = sssp->distance(t);
            npaths[s][t] = sssp->numberOfPaths(t);
            if (storePreds) {
                predecessors[s][t] = sssp->getPredecessors(t);
            }
        });

        // compute dependencies for nodes in order of decreasing distance from s
        std::stack<node> stack = sssp->getStack();
        // set maxDistance to the distance of the furthest vertex
        maxDistance[s] = distances[s][stack.top()];
        while (!stack.empty()) {
            node t = stack.top();
            stack.pop();
            for (node p : sssp->getPredecessors(t)) {
                dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
            }
            if (t != s) {
                scoreData[t] += dependencies[s][t];
            }
        }
    };

    G.forNodes(computeDependencies);
}

void DynBetweenness::updateUnweighted(GraphEvent e) {
    G.forNodes([&] (node s){
        node u_l, u_h;
        if (distances[s][e.u] > distances[s][e.v]){
            u_l = e.u;
            u_h = e.v;
        } else {
            u_l = e.v;
            u_h = e.u;
        }
        edgeweight difference = distances[s][u_l] - distances[s][u_h];
        if (difference > 0) {
            std::vector<count> new_npaths(G.upperNodeIdBound());
            std::vector<edgeweight> new_dist(G.upperNodeIdBound());
            G.forNodes([&] (node v){
                new_npaths[v] = npaths[s][v];
                new_dist[v] = distances[s][v];
            });
            std::vector<double> new_dep(G.upperNodeIdBound(), 0.0);
            std::vector<int> touched(G.upperNodeIdBound(), 0);
            std::vector<std::queue<node>> l_queues(maxDistance[s]+1);
            std::queue<node> queue_BFS;
            queue_BFS.push(u_l);
            // one-level update
            if (difference == 1) {
                l_queues[distances[s][u_l]].push(u_l);
                if (storePreds)
                    predecessors[s][u_l].push_back(u_h);
                new_npaths[u_l] += npaths[s][u_h];
                touched[u_l] = -1;
                // BFS traversal from u_l
                while (!queue_BFS.empty()) {
                    node v = queue_BFS.front();
                    DEBUG("extracted node ", v);
                    queue_BFS.pop();
                    G.forNeighborsOf(v, [&](node w) {
                        if (new_dist[w] == new_dist[v]+1) {
                            if (touched[w] == 0) {
                                touched[w] = -1;
                                queue_BFS.push(w);
                                l_queues[new_dist[w]].push(w);
                            }
                            new_npaths[w] = new_npaths[w] - npaths[s][v] + new_npaths[v];
                        }
                    });
                }
            } else if (difference > 1) {
                new_dist[u_l] = distances[s][u_h] + 1;
                l_queues[new_dist[u_l]].push(u_l);
                // BFS traversal from u_l
                while (!queue_BFS.empty()) {
                    node v = queue_BFS.front();
                    DEBUG("extracted node ",v);
                    if (storePreds) {
                        predecessors[s][v].clear();
                    }
                    queue_BFS.pop();
                    touched[v] = -1;
                    new_npaths[v] = 0;
                    G.forNeighborsOf(v, [&] (node w){
                            if (new_dist[w] + 1 == new_dist[v]) {
                                new_npaths[v] += new_npaths[w];
                                if (storePreds) {
                                    predecessors[s][v].push_back(w);
                                }
                            }
                            if (new_dist[w] >= new_dist[v] && touched[w] == 0) {
                                if (new_dist[w] > new_dist[v])
                                    new_dist[w] = new_dist[v]+1;
                                touched[w] = -1;
                                l_queues[new_dist[w]].push(w);
                                queue_BFS.push(w);
                            }
                    });
                }
            }
            // dependencies accumulation
            DEBUG("Dependency accumulation");
            count level = maxDistance[s];
            while(level > 0) {
                while(!l_queues[level].empty()) {
                    node w = l_queues[level].front();
                    DEBUG("Node ",w);
                    l_queues[level].pop();
                    auto updateDependency = [&](node w, node v) {
                        if (new_dist[v] < new_dist[w]) {
                            if (touched[v] == 0) {
                                touched[v] = 1;
                                new_dep[v] = dependencies[s][v];
                                l_queues[level-1].push(v);
                            }
                            double new_contrib = double(new_npaths[v])/new_npaths[w]*(1+new_dep[w]);
                            new_dep[v] += new_contrib;
                            double old_contrib = double(npaths[s][v])/npaths[s][w]*(1+dependencies[s][w]);
                            if (touched[v] == 1 && (v != u_h or w!= u_l))
                                new_dep[v] -= old_contrib;
                            DEBUG("Parent ", v);
                        }
                    };
                    if (storePreds) {
                        for (node v : predecessors[s][w]) {
                            updateDependency(w, v);
                        }
                    }
                    else {
                        G.forNeighborsOf(w, [&](node v){
                            updateDependency(w, v);
                        });
                    }
                    if (w != s) {
                        scoreData[w] = scoreData[w] + new_dep[w] - dependencies[s][w];
                    }
                }
                level = level - 1;
            }
            // data structures update
            G.forNodes([&] (node r){
                distances[s][r] = new_dist[r];
                npaths[s][r] = new_npaths[r];
                if (touched[r] != 0)
                    dependencies[s][r] = new_dep[r];
            });
        }
/*

        BFS sssp(G, s, true, true);
        sssp.run();
        G.forNodes([&](node t){
            if(distances[s][t] != sssp.distance(t) || npaths[s][t] != sssp.numberOfPaths(t)) {
                std::cout<<"Source: "<<s<<"  Node "<<t<<std::endl;
                std::cout<<"COMPUTED DISTANCE: "<<distances[s][t]<<"  REAL DISTANCE: "<<sssp.distance(t)<<std::endl;
                std::cout<<"COMPUTED NUMBER OF PATHS: "<<npaths[s][t]<<"  REAL NUMBER OF PATHS: "<<sssp.numberOfPaths(t)<<std::endl;
            }
        });

        // compute dependencies for nodes in order of decreasing distance from s
        std::vector<double> dep(G.upperNodeIdBound());
        std::stack<node> stack = sssp.getStack();
        while (!stack.empty()) {
            node t = stack.top();
            stack.pop();
            for (node p : sssp.getPredecessors(t)) {
                dep[p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dep[t]);
            }
        }

        G.forNodes([&](node t){
            if((dependencies[s][t]-dep[t]>0.000001 || dependencies[s][t]-dep[t]<-0.000001) && s!=t) {
                std::cout<<"Source: "<<s<<"  Node "<<t<<std::endl;
                std::cout<<"COMPUTED DEPENDENCY: "<<dependencies[s][t]<<"  REAL DEPENDENCY: "<<dep[t]<<std::endl;
            }
        });

*/

    });
}

void DynBetweenness::updateWeighted(GraphEvent e) {
    G.forNodes([&] (node s){
        scoreData[s] = 0.0;
    });
    G.forNodes([&] (node s){
        // update of distances and number of shortest paths
        Aux::PrioQueue<double, node> S(G.upperNodeIdBound());
        G.forNodes([&] (node t){
            auto updatePaths = [&](node u, node v, edgeweight w) {
                if (distances[s][t] == distances[s][u] + w + distances[v][t]){
                    npaths[s][t] = npaths[s][t] + npaths[s][u] * npaths[v][t];
                    if (storePreds) {
                        if (t != v){
                            DEBUG("Adding predecessors from v to t to predecessors from s to t");
                            //predecessors[s][t].insert( predecessors[s][t].end(), predecessors[v][t].begin(), predecessors[v][t].end());
                            for (node pv : predecessors[v][t]) {
                                bool wasAlreadyPred = false;
                                for (node ps : predecessors[s][t]) {
                                    if (ps == pv)
                                        wasAlreadyPred = true;
                                }
                                if (!wasAlreadyPred)
                                    predecessors[s][t].push_back(pv);
                            }
                            DEBUG("Finished adding");
                        }
                        else {
                            DEBUG("Adding u to the predecessors of v");
                            predecessors[s][t].push_back(u);
                            DEBUG("Finished adding");
                        }
                    }
                }
                if (distances[s][t] > distances[s][u] + w + distances[v][t]){
                    distances[s][t] = distances[s][u] + w + distances[v][t];
                    npaths[s][t] = npaths[s][u] * npaths[v][t];
                    if (storePreds) {
                        if (t != v) {
                            DEBUG("Replacing predecessors from v to t with predecessors from s to t");
                            predecessors[s][t] = predecessors[v][t];
                            DEBUG("Finished replacing");
                        }
                        else {
                            DEBUG("Replacing old predecessors of v with u");
                            predecessors[s][t].clear();
                            predecessors[s][t].push_back(u);
                            DEBUG("Finished replacing");
                        }
                    }
                }
            };
            if (s != t) {
                updatePaths(e.u, e.v, e.w);
                updatePaths(e.v, e.u, e.w);
                S.insert(-1*distances[s][t], t);
                dependencies[s][t] = 0.0;
            }
        });
        // dependency accumulation
        while (S.size() != 0) {
            // extract the node with the maximum distance
            node t = S.extractMin().second;
            if (storePreds) {
                DEBUG("Computing dependencies");
                for (node p : predecessors[s][t]) {
                    dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
                }
            }
            else {
                G.forNeighborsOf(t, [&] (node p){
                    if (logically_equal(distances[s][t], distances[s][p] + G.weight(p, t))) {
                        dependencies[s][p] += (double(npaths[s][p]) / npaths[s][t])  * (1 + dependencies[s][t]);
                    }
                });
            }
            if (t != s) {
                scoreData[t] += dependencies[s][t];
            }
        }

    });

}

void DynBetweenness::update(GraphEvent e) {
    if (G.isWeighted())
        updateWeighted(e);
    else
        updateUnweighted(e);
}

} /* namespace NetworKit */
<|endoftext|>