<commit_before>/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/

#include "stdafx.h"

#include "material.h"
#include "renderer.h"
#include "usefull.h"
#include "Globals.h"

bool
opengl_material::deserialize( cParser &Input, bool const Loadnow ) {

    bool result { false };
    while( true == deserialize_mapping( Input, Loadnow ) ) {
        result = true; // once would suffice but, eh
    }

    has_alpha = (
        texture1 != null_handle ?
            GfxRenderer.Texture( texture1 ).has_alpha :
            false );

    return result;
}

// imports member data pair from the config file
bool
opengl_material::deserialize_mapping( cParser &Input, bool const Loadnow ) {

    if( false == Input.getTokens( 2, true, "\n\r\t;, " ) ) {
        return false;
    }

    std::string path;
    if( name.rfind( '\\' ) != std::string::npos ) {
        path = name.substr( 0, name.rfind( '\\' ) + 1 );
    }

    std::string key, value;
    Input
        >> key
        >> value;

         if( key == "texture1:" ) { texture1 = GfxRenderer.Fetch_Texture( path + value, Loadnow ); }
    else if( key == "texture2:" ) { texture2 = GfxRenderer.Fetch_Texture( path + value, Loadnow ); }

    return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
}

// create material object from data stored in specified file.
// NOTE: the deferred load parameter is passed to textures defined by material, the material itself is always loaded immediately
material_handle
material_manager::create( std::string const &Filename, bool const Loadnow ) {

    auto filename { Filename };

    if( filename.find( '|' ) != std::string::npos )
        filename.erase( filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury

    if( filename.rfind( '.' ) != std::string::npos ) {
        // we can get extension for .mat or, in legacy files, some image format. just trim it and set it to material file extension
        filename.erase( filename.rfind( '.' ) );
    }
    filename += ".mat";

	std::replace(filename.begin(), filename.end(), '\\', '/'); // fix slashes

    if( filename.find( '/' ) == std::string::npos ) {
        // jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną
        filename = global_texture_path + filename;
    }

    // try to locate requested material in the databank
    auto const databanklookup = find_in_databank( filename );
    if( databanklookup != npos ) {
        return databanklookup;
    }
    // if this fails, try to look for it on disk
    opengl_material material;
    material.name = filename;
    auto const disklookup = find_on_disk( filename );
    if( disklookup != "" ) {
        cParser materialparser( disklookup, cParser::buffer_FILE );
        if( false == material.deserialize( materialparser, Loadnow ) ) {
            // deserialization failed but the .mat file does exist, so we give up at this point
            return null_handle;
        }
    }
    else {
        // if there's no .mat file, this could be legacy method of referring just to diffuse texture directly, make a material out of it in such case
        material.texture1 = GfxRenderer.Fetch_Texture( Filename, Loadnow );
        if( material.texture1 == null_handle ) {
            // if there's also no texture, give up
            return null_handle;
        }
        material.has_alpha = GfxRenderer.Texture( material.texture1 ).has_alpha;
    }

    material_handle handle = m_materials.size();
    m_materials.emplace_back( material );
    m_materialmappings.emplace( material.name, handle );
    return handle;
};

// checks whether specified texture is in the texture bank. returns texture id, or npos.
material_handle
material_manager::find_in_databank( std::string const &Materialname ) const {

    auto lookup = m_materialmappings.find( Materialname );
    if( lookup != m_materialmappings.end() ) {
        return lookup->second;
    }
    // jeszcze próba z dodatkową ścieżką
    lookup = m_materialmappings.find( global_texture_path + Materialname );

    return (
        lookup != m_materialmappings.end() ?
            lookup->second :
            npos );
}

// checks whether specified file exists.
// NOTE: this is direct copy of the method used by texture manager. TBD, TODO: refactor into common routine?
std::string
material_manager::find_on_disk( std::string const &Materialname ) const {

    return(
        FileExists( Materialname ) ? Materialname :
        FileExists( global_texture_path + Materialname ) ? global_texture_path + Materialname :
        "" );
}

//---------------------------------------------------------------------------
<commit_msg>linux slash changes<commit_after>/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/

#include "stdafx.h"

#include "material.h"
#include "renderer.h"
#include "usefull.h"
#include "Globals.h"

bool
opengl_material::deserialize( cParser &Input, bool const Loadnow ) {

    bool result { false };
    while( true == deserialize_mapping( Input, Loadnow ) ) {
        result = true; // once would suffice but, eh
    }

    has_alpha = (
        texture1 != null_handle ?
            GfxRenderer.Texture( texture1 ).has_alpha :
            false );

    return result;
}

// imports member data pair from the config file
bool
opengl_material::deserialize_mapping( cParser &Input, bool const Loadnow ) {

    if( false == Input.getTokens( 2, true, "\n\r\t;, " ) ) {
        return false;
    }

    std::string path;
    if( name.rfind( '/' ) != std::string::npos ) {
        path = name.substr( 0, name.rfind( '/' ) + 1 );
    }

    std::string key, value;
    Input
        >> key
        >> value;

         if( key == "texture1:" ) { texture1 = GfxRenderer.Fetch_Texture( path + value, Loadnow ); }
    else if( key == "texture2:" ) { texture2 = GfxRenderer.Fetch_Texture( path + value, Loadnow ); }

    return true; // return value marks a key: value pair was extracted, nothing about whether it's recognized
}

// create material object from data stored in specified file.
// NOTE: the deferred load parameter is passed to textures defined by material, the material itself is always loaded immediately
material_handle
material_manager::create( std::string const &Filename, bool const Loadnow ) {

    auto filename { Filename };

    if( filename.find( '|' ) != std::string::npos )
        filename.erase( filename.find( '|' ) ); // po | może być nazwa kolejnej tekstury

    if( filename.rfind( '.' ) != std::string::npos ) {
        // we can get extension for .mat or, in legacy files, some image format. just trim it and set it to material file extension
        filename.erase( filename.rfind( '.' ) );
    }
    filename += ".mat";

	std::replace(filename.begin(), filename.end(), '\\', '/'); // fix slashes

    if( filename.find( '/' ) == std::string::npos ) {
        // jeśli bieżaca ścieżka do tekstur nie została dodana to dodajemy domyślną
        filename = global_texture_path + filename;
    }

    // try to locate requested material in the databank
    auto const databanklookup = find_in_databank( filename );
    if( databanklookup != npos ) {
        return databanklookup;
    }
    // if this fails, try to look for it on disk
    opengl_material material;
    material.name = filename;
    auto const disklookup = find_on_disk( filename );
    if( disklookup != "" ) {
        cParser materialparser( disklookup, cParser::buffer_FILE );
        if( false == material.deserialize( materialparser, Loadnow ) ) {
            // deserialization failed but the .mat file does exist, so we give up at this point
            return null_handle;
        }
    }
    else {
        // if there's no .mat file, this could be legacy method of referring just to diffuse texture directly, make a material out of it in such case
        material.texture1 = GfxRenderer.Fetch_Texture( Filename, Loadnow );
        if( material.texture1 == null_handle ) {
            // if there's also no texture, give up
            return null_handle;
        }
        material.has_alpha = GfxRenderer.Texture( material.texture1 ).has_alpha;
    }

    material_handle handle = m_materials.size();
    m_materials.emplace_back( material );
    m_materialmappings.emplace( material.name, handle );
    return handle;
};

// checks whether specified texture is in the texture bank. returns texture id, or npos.
material_handle
material_manager::find_in_databank( std::string const &Materialname ) const {

    auto lookup = m_materialmappings.find( Materialname );
    if( lookup != m_materialmappings.end() ) {
        return lookup->second;
    }
    // jeszcze próba z dodatkową ścieżką
    lookup = m_materialmappings.find( global_texture_path + Materialname );

    return (
        lookup != m_materialmappings.end() ?
            lookup->second :
            npos );
}

// checks whether specified file exists.
// NOTE: this is direct copy of the method used by texture manager. TBD, TODO: refactor into common routine?
std::string
material_manager::find_on_disk( std::string const &Materialname ) const {

    return(
        FileExists( Materialname ) ? Materialname :
        FileExists( global_texture_path + Materialname ) ? global_texture_path + Materialname :
        "" );
}

//---------------------------------------------------------------------------
<|endoftext|>


<commit_before>/*
 * By: ulises-jeremias
 * From: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=438
 * Name: Strategic Defense Initiative
 * Date: 07/09/2017
 */

#include <iostream>

using namespace std;

int main(int argc, char const *argv[]) {
      ios_base::sync_with_stdio(false);
      cin.tie(NULL);

      int n, i;

      while (cin >> n) {
            for (i = 0; i < n; i++) {

            }
      }

      return 0;
}
<commit_msg>Update<commit_after>/*
 * By: ulises-jeremias
 * From: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=438
 * Name: Strategic Defense Initiative
 * Date: 07/09/2017
 */

#include <iostream>
#include <cstdio>

using namespace std;

int main(int argc, char const *argv[]) {
      ios_base::sync_with_stdio(false);
      cin.tie(NULL);

      int tc, i;
      char n[10];

      cin >> tc;
      getchar();
      gets(n);
      while (tc--) {

      }

      return 0;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "MainScene.h"
#include "MCScene.h"
#include "TWScene.h"
#include "JWScene.h"
#include "GameScene.h"
#include "Sling.h"
#include "GameManager.h"
#include "StageScene.h"
#include "ConstVars.h"
#include "FileStuff.h"
#include "MapEditer.h"
#include <AudioEngine.h>
#include <SimpleAudioEngine.h>
#include "IntroScene.h"

Scene* MainScene::createScene()
{
    Scene* scene = Scene::create();

    MainScene* layer = MainScene::create();

    scene->addChild(layer);

    return scene;
}

bool MainScene::init()
{
	if (!Layer::init())
	{
		return false;
	}

	SpriteFrameCache::getInstance()->addSpriteFramesWithFile(FileStuff::IMG_SOURCE);

	m_StreetLight = Sprite::create(FileStuff::GARO_OFF);
	m_StreetLight->setPosition(Vec2(110, 320));
	m_StreetLightPos = m_StreetLight->getPosition();
	addChild(m_StreetLight);

	Size visibleSize = Director::getInstance()->getVisibleSize();
	Vec2 origin = Director::getInstance()->getVisibleOrigin();
	float selectedScale = 1.2;
	Point selectedAnchor = Point(selectedScale - 1.0, selectedScale - 1.0) / 2;

	CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(
		FileStuff::SOUND_MAIN_BACKGROUND, true);

	/*Game start Button*/
	MenuItemImage* startGame = MenuItemImage::create();

	startGame->setNormalImage(Sprite::createWithSpriteFrame(
		SpriteFrameCache::getInstance()->getSpriteFrameByName(FileStuff::CHARACTER_STANDING)
		)
		);

	startGame->setSelectedImage(
		Sprite::createWithSpriteFrame(
		SpriteFrameCache::getInstance()->getSpriteFrameByName(FileStuff::CHARACTER_SELECTED)
		)
		);

	startGame->setCallback(CC_CALLBACK_1(MainScene::ChangeToStageSceneEffect, this));

	startGame->setPosition(m_StreetLightPos + Vec2(30, -200));
#ifdef _DEBUG
	/*MapEditer Button*/
	MenuItemLabel* mapEditer = MenuItemLabel::create(Label::create("MapEditer", "res/NanumGothic.ttf", 20), CC_CALLBACK_1(MainScene::ChangeToMapEditScene, this));
	mapEditer->setPosition(visibleSize.width / 2, visibleSize.height - startGame->getContentSize().height - mapEditer->getContentSize().height);

#else
	Action* action = CallFunc::create(CC_CALLBACK_0(MainScene::SetDisplayStat, this, false));
	runAction(action);

#endif

	/* End Button */
	MenuItemImage* closeItem = MenuItemImage::create(
		FileStuff::CLOSE_BUTTON,
		FileStuff::CLOSE_BUTTON,
		CC_CALLBACK_1(MainScene::menuCloseCallback, this));
	float scale = 2.0f;
	closeItem->setScale(scale);
	closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width * scale / 2,
		closeItem->getContentSize().height * scale / 2));

	auto paulScene = MenuItemFont::create("WATCH ENDING", CC_CALLBACK_1(MainScene::ChangeToMCScene,this));
	paulScene->setScale(0.5f);
	paulScene->setPosition(Vec2(origin.x + visibleSize.width - paulScene->getContentSize().width / 2,
		origin.y + closeItem->getContentSize().height*scale + paulScene->getContentSize().height/2));

	auto jwScene = MenuItemFont::create("RESET GAME", CC_CALLBACK_1(MainScene::ChangeToJWScene, this));
	jwScene->setScaleX(0.5);
	jwScene->setScaleY(0.5);
	jwScene->setPosition(Point(110, 10));

	auto menu = Menu::create(startGame, mapEditer, closeItem, paulScene, jwScene, NULL);
	menu->setPosition(Vec2::ZERO);
	menu->setName("Buttons");
	addChild(menu, 1);

	return true;
}

void MainScene::SetDisplayStat(bool isOn)
{
	Director::getInstance()->setDisplayStats(isOn);
}

void MainScene::ChangeToStageScene(Ref* pSender)
{
	int stageToPlay = UserDefault::getInstance()->getIntegerForKey(ConstVars::LASTSTAGE);
	if (stageToPlay == 0)
		Director::getInstance()->replaceScene(IntroScene::createScene());
	else
		Director::getInstance()->replaceScene(StageScene::createScene());
}

void MainScene::ChangeToStageSceneEffect(Ref* pSender)
{

	removeChildByName("Buttons");

	m_character = Sprite::createWithSpriteFrameName(FileStuff::CHARACTER_HARDPIXEL);
	addChild(m_character, 2);

	m_character->setPosition(m_StreetLightPos + Vec2(30, -200));
	m_character->runAction(MoveTo::create(2.0f, m_StreetLight->getPosition() + Vec2(9, -45)));
	CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(FileStuff::SOUND_FOOTSTEP, false, 2.0f);

	Sequence* seq = Sequence::create(
		DelayTime::create(2.5f),
		CallFuncN::create(CC_CALLBACK_0(MainScene::BlinkStreetLight, this)),
		DelayTime::create(2.0f),
		CallFuncN::create(CC_CALLBACK_0(MainScene::TurnStreetLight, this)),
		DelayTime::create(2.0f),
		CallFuncN::create(CC_CALLBACK_1(MainScene::ChangeToStageScene, this)),
		nullptr);

	runAction(seq);
}

void MainScene::ChangeToMapEditScene(Ref* pSender)
{
	Director::getInstance()->replaceScene(MapEditer::createScene());
}

void MainScene::ChangeToMCScene(Ref* pSender)
{
	Director::getInstance()->replaceScene(MCScene::createScene());
}

void MainScene::ChangeToTWScene(Ref* pSender)
{
	Director::getInstance()->replaceScene(TWScene::createScene());
}

void MainScene::ChangeToJWScene(Ref* pSender)
{
	Director::getInstance()->replaceScene(JWScene::createScene());
}

void MainScene::menuCloseCallback(Ref* pSender)
{
    Director::getInstance()->end();
}

void MainScene::BlinkStreetLight()
{
	CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(FileStuff::SOUND_STREETLIGHTS);

	CallFunc* StreetLightOff =  CallFunc::create(CC_CALLBACK_0(MainScene::StreetLightOff, this));
	CallFunc* StreetLightOn = CallFunc::create(CC_CALLBACK_0(MainScene::StreetLightOn, this));

	Sequence* seq =  Sequence::create(
		StreetLightOn,
		DelayTime::create(0.25f),
		StreetLightOff,
		DelayTime::create(1.0f),
		StreetLightOn,
		DelayTime::create(0.2f),
		StreetLightOff,
		DelayTime::create(0.2f),
		StreetLightOn,
		nullptr);

	runAction(seq);
}

void MainScene::StreetLightOff()
{
	m_StreetLight->removeFromParent();
	m_StreetLight = Sprite::create(FileStuff::GARO_OFF);
	addChild(m_StreetLight);
	m_StreetLight->setPosition(m_StreetLightPos);
}

void MainScene::StreetLightOn()
{
	m_StreetLight->removeFromParent();
	m_StreetLight = Sprite::create(FileStuff::GARO_ON);
	addChild(m_StreetLight);
	m_StreetLight->setPosition(m_StreetLightPos);
}

void MainScene::TurnStreetLight()
{
	Sprite* light_beam = Sprite::create(FileStuff::LIGHT_BEAM);
	light_beam->setPosition(Vec2(3, -3));
	light_beam->setAnchorPoint(Vec2(0, 0));
	m_StreetLight->addChild(light_beam, -1);
}<commit_msg>change effect of main scene fade in of light<commit_after>#include "stdafx.h"
#include "MainScene.h"
#include "MCScene.h"
#include "TWScene.h"
#include "JWScene.h"
#include "GameScene.h"
#include "Sling.h"
#include "GameManager.h"
#include "StageScene.h"
#include "ConstVars.h"
#include "FileStuff.h"
#include "MapEditer.h"
#include <AudioEngine.h>
#include <SimpleAudioEngine.h>
#include "IntroScene.h"

Scene* MainScene::createScene()
{
    Scene* scene = Scene::create();

    MainScene* layer = MainScene::create();

    scene->addChild(layer);

    return scene;
}

bool MainScene::init()
{
	if (!Layer::init())
	{
		return false;
	}
	SpriteFrameCache::getInstance()->addSpriteFramesWithFile(FileStuff::IMG_SOURCE);
	Size visibleSize = Director::getInstance()->getVisibleSize();
	Vec2 origin = Director::getInstance()->getVisibleOrigin();

	m_StreetLight = Sprite::create(FileStuff::GARO_OFF);
	m_StreetLight->setPosition(Vec2(visibleSize.width /2 , visibleSize.height /2));
	m_StreetLight->setOpacity(40); //ó ε Ӱ
	m_StreetLightPos = m_StreetLight->getPosition();
	addChild(m_StreetLight);

	float selectedScale = 1.2;
	Point selectedAnchor = Point(selectedScale - 1.0, selectedScale - 1.0) / 2;

	CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(
		FileStuff::SOUND_MAIN_BACKGROUND, true);

	/*Game start Button*/
	MenuItemImage* startGame = MenuItemImage::create();

	startGame->setNormalImage(Sprite::createWithSpriteFrame(
		SpriteFrameCache::getInstance()->getSpriteFrameByName(FileStuff::CHARACTER_STANDING)
		)
		);

	startGame->setSelectedImage(
		Sprite::createWithSpriteFrame(
		SpriteFrameCache::getInstance()->getSpriteFrameByName(FileStuff::CHARACTER_SELECTED)
		)
		);

	startGame->setCallback(CC_CALLBACK_1(MainScene::ChangeToStageSceneEffect, this));

	startGame->setPosition(m_StreetLightPos + Vec2(0, -100));

#ifdef _DEBUG
	/*MapEditer Button*/
	MenuItemLabel* mapEditer = MenuItemLabel::create(Label::create("MapEditer", "res/NanumGothic.ttf", 20), CC_CALLBACK_1(MainScene::ChangeToMapEditScene, this));
	mapEditer->setPosition(visibleSize.width / 2, visibleSize.height - startGame->getContentSize().height - mapEditer->getContentSize().height);

#else
	Action* action = CallFunc::create(CC_CALLBACK_0(MainScene::SetDisplayStat, this, false));
	runAction(action);

#endif

	/* End Button */
	MenuItemImage* closeItem = MenuItemImage::create(
		FileStuff::CLOSE_BUTTON,
		FileStuff::CLOSE_BUTTON,
		CC_CALLBACK_1(MainScene::menuCloseCallback, this));
	float scale = 2.0f;
	closeItem->setScale(scale);
	closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width * scale / 2,
		closeItem->getContentSize().height * scale / 2));

	auto paulScene = MenuItemFont::create("WATCH ENDING", CC_CALLBACK_1(MainScene::ChangeToMCScene,this));
	paulScene->setScale(0.5f);
	paulScene->setPosition(Vec2(origin.x + visibleSize.width - paulScene->getContentSize().width / 2,
		origin.y + closeItem->getContentSize().height*scale + paulScene->getContentSize().height/2));

	auto jwScene = MenuItemFont::create("RESET GAME", CC_CALLBACK_1(MainScene::ChangeToJWScene, this));
	jwScene->setScaleX(0.5);
	jwScene->setScaleY(0.5);
	jwScene->setPosition(Point(110, 10));

	auto menu = Menu::create(startGame, mapEditer, closeItem, paulScene, jwScene, NULL);
	menu->setPosition(Vec2::ZERO);
	menu->setName("Buttons");
	addChild(menu, 1);

	return true;
}

void MainScene::SetDisplayStat(bool isOn)
{
	Director::getInstance()->setDisplayStats(isOn);
}

void MainScene::ChangeToStageScene(Ref* pSender)
{
	int stageToPlay = UserDefault::getInstance()->getIntegerForKey(ConstVars::LASTSTAGE);
	if (stageToPlay == 0)
		Director::getInstance()->replaceScene(IntroScene::createScene());
	else
		Director::getInstance()->replaceScene(StageScene::createScene());
}

void MainScene::ChangeToStageSceneEffect(Ref* pSender)
{
	Vec2 characterPosition = static_cast<MenuItemImage*>(pSender)->getPosition(); //ֱ  ġ س
	removeChildByName("Buttons");

	//character ɾ κ
	m_character = Sprite::createWithSpriteFrameName(FileStuff::CHARACTER_HARDPIXEL);
	addChild(m_character, 2);

	m_character->setPosition(characterPosition);
	m_character->runAction(MoveTo::create(2.0f, m_StreetLight->getPosition() + Vec2(9, -45)));
	CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(FileStuff::SOUND_FOOTSTEP, false, 2.0f);

	//ε  fadein ϴ κ
	m_StreetLight->runAction(FadeIn::create(2.5));

	Sequence* seq = Sequence::create(
		DelayTime::create(2.5f),
		CallFuncN::create(CC_CALLBACK_0(MainScene::BlinkStreetLight, this)),
		DelayTime::create(2.0f),
		CallFuncN::create(CC_CALLBACK_0(MainScene::TurnStreetLight, this)),
		DelayTime::create(2.0f),
		CallFuncN::create(CC_CALLBACK_1(MainScene::ChangeToStageScene, this)),
		nullptr);

	runAction(seq);
}

void MainScene::ChangeToMapEditScene(Ref* pSender)
{
	Director::getInstance()->replaceScene(MapEditer::createScene());
}

void MainScene::ChangeToMCScene(Ref* pSender)
{
	Director::getInstance()->replaceScene(MCScene::createScene());
}

void MainScene::ChangeToTWScene(Ref* pSender)
{
	Director::getInstance()->replaceScene(TWScene::createScene());
}

void MainScene::ChangeToJWScene(Ref* pSender)
{
	Director::getInstance()->replaceScene(JWScene::createScene());
}

void MainScene::menuCloseCallback(Ref* pSender)
{
    Director::getInstance()->end();
}

void MainScene::BlinkStreetLight()
{
	CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(FileStuff::SOUND_STREETLIGHTS);

	CallFunc* StreetLightOff =  CallFunc::create(CC_CALLBACK_0(MainScene::StreetLightOff, this));
	CallFunc* StreetLightOn = CallFunc::create(CC_CALLBACK_0(MainScene::StreetLightOn, this));

	Sequence* seq =  Sequence::create(
		StreetLightOn,
		DelayTime::create(0.25f),
		StreetLightOff,
		DelayTime::create(1.0f),
		StreetLightOn,
		DelayTime::create(0.2f),
		StreetLightOff,
		DelayTime::create(0.2f),
		StreetLightOn,
		nullptr);

	runAction(seq);
}

void MainScene::StreetLightOff()
{
	m_StreetLight->removeFromParent();
	m_StreetLight = Sprite::create(FileStuff::GARO_OFF);
	addChild(m_StreetLight);
	m_StreetLight->setPosition(m_StreetLightPos);
}

void MainScene::StreetLightOn()
{
	m_StreetLight->removeFromParent();
	m_StreetLight = Sprite::create(FileStuff::GARO_ON);
	addChild(m_StreetLight);
	m_StreetLight->setPosition(m_StreetLightPos);
}

void MainScene::TurnStreetLight()
{
	Sprite* light_beam = Sprite::create(FileStuff::LIGHT_BEAM);
	light_beam->setPosition(Vec2(3, -3));
	light_beam->setAnchorPoint(Vec2(0, 0));
	m_StreetLight->addChild(light_beam, -1);
}<|endoftext|>


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

#include "hdfs.h"

// POSIX
#include <errno.h>

// STL
#include <tr1/unordered_map>
#include <tr1/memory>

// po6
#include <po6/error.h>
#include <po6/threads/thread.h>

// e
#include <e/guard.h>
#include <e/time.h>
#include <numbers.h>
#include <armnod.h>

// WTF
#include "common/network_msgtype.h"
#include "client/wtf.h"

static long _done = 0;
static long _number = 1000;
static long _threads = 1;
static long _backup = 0;
static long _connect_port = 0;
static long _hyper_port = 1981;
static long _concurrent = 50;
static const char* _output = "wtf-hadoop-benchmark.log";
static const char* _dir = ".";
static const char* _connect_host = "default";
static const char* _hyper_host = "127.0.0.1";

#define BILLION (1000ULL * 1000ULL * 1000ULL)

static uint64_t
get_random()
{
    po6::io::fd sysrand(open("/dev/urandom", O_RDONLY));

    if (sysrand.get() < 0)
    {
        abort();
        return 0xcafebabe;
    }

    uint64_t ret;

    if (sysrand.read(&ret, sizeof(ret)) != sizeof(ret))
    {
        abort();
        return 0xdeadbeef;
    }

    return ret;
}

void
worker_thread( numbers::throughput_latency_logger* tll,
        const armnod::argparser& _f,
        const armnod::argparser& _v)
{
    armnod::generator file(armnod::argparser(_f).config());
    armnod::generator val(armnod::argparser(_v).config());
    file.seed(get_random());
    val.seed(get_random());
    numbers::throughput_latency_logger::thread_state ts;
    tll->initialize_thread(&ts);

    try
    {
        hdfsFS cl = hdfsConnect(_connect_host, 0);

        while (__sync_fetch_and_add(&_done, 1) < _number)
        {
            wtf_returncode status = WTF_GARBAGE;
            std::string f = file();
            std::string v = val();
            char filename[71] = "/tmp/";
            strcat(filename, f.data());
            std::cout << filename << std::endl;

            hdfsFile fd = hdfsOpenFile(cl, filename, O_WRONLY|O_CREAT, 0, 0, 0);
            if(!fd) {
                std::cerr << "Failed to open " << f.data() << " for writing!\n";
                exit(-1);
            }

            tSize num_written_bytes = hdfsWrite(cl, fd, (void*)v.data(), v.size());
            if (hdfsFlush(cl, fd)) {
                std::cerr << "Failed to 'flush' " << f.data()<< std::endl;
                exit(-1);
            }

            hdfsCloseFile(cl, fd);
        }
    }
    catch (po6::error& e)
    {
        std::cerr << "system error: " << e.what() << std::endl;
    }
    catch (std::exception& e)
    {
        std::cerr << "error: " << e.what() << std::endl;
    }

    tll->terminate_thread(&ts);
}

int
main(int argc, const char* argv[])
{
    e::argparser ap;
    ap.autohelp();
    ap.arg().name('p', "port")
        .description("port on the wtf coordinator")
        .metavar("p")
        .as_long(&_connect_port);
    ap.arg().name('P', "Port")
        .description("port on the hyperdex coordinator")
        .metavar("P")
        .as_long(&_hyper_port);
    ap.arg().name('h', "host")
        .description("address of wtf coordinator")
        .metavar("h")
        .as_string(&_connect_host);
    ap.arg().name('H', "host")
        .description("address of hyperdex coordinator")
        .metavar("H")
        .as_string(&_hyper_host);
    ap.arg().name('n', "number")
        .description("perform N operations against the database (default: 1000000)")
        .metavar("N")
        .as_long(&_number);
    ap.arg().name('t', "threads")
        .description("run the test with T concurrent threads (default: 1)")
        .metavar("T")
        .as_long(&_threads);
    ap.arg().name('o', "output")
        .description("output file for benchmark results (default: benchmark.log)")
        .as_string(&_output);
    ap.arg().name('c', "concurrent")
        .description("number of concurrent ops (default=50)")
        .as_long(&_concurrent);
    armnod::argparser file_parser("file-");
    armnod::argparser value_parser("value-");
    ap.add("Filename Generation:", file_parser.parser());
    ap.add("Value Generation:", value_parser.parser());

    if (!ap.parse(argc, argv))
    {
        return EXIT_FAILURE;
    }

    typedef std::tr1::shared_ptr<po6::threads::thread> thread_ptr;
    std::vector<thread_ptr> threads;

    numbers::throughput_latency_logger tll;
    if (!tll.open(_output))
    {
        std::cerr << "could not open log: " << strerror(errno) << std::endl;
        return EXIT_FAILURE;
    }

    for (size_t i = 0; i < _threads; ++i)
    {
        thread_ptr t(new po6::threads::thread(std::tr1::bind(worker_thread, &tll, file_parser, value_parser)));
        threads.push_back(t);
        t->start();
    }

    for (size_t i = 0; i < threads.size(); ++i)
    {
        threads[i]->join();
    }

    if (!tll.close())
    {
        std::cerr << "could not close log: " << strerror(errno) << std::endl;
        return EXIT_FAILURE;
    }

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

#include "hdfs.h"

// POSIX
#include <errno.h>

// STL
#include <tr1/unordered_map>
#include <tr1/memory>

// po6
#include <po6/error.h>
#include <po6/threads/thread.h>

// e
#include <e/guard.h>
#include <e/time.h>
#include <numbers.h>
#include <armnod.h>

// WTF
#include "common/network_msgtype.h"
#include "client/wtf.h"

static long _done = 0;
static long _number = 1000;
static long _threads = 1;
static long _backup = 0;
static long _connect_port = 0;
static long _hyper_port = 1981;
static long _concurrent = 50;
static const char* _output = "wtf-hadoop-benchmark.log";
static const char* _dir = ".";
static const char* _connect_host = "default";
static const char* _hyper_host = "127.0.0.1";

#define BILLION (1000ULL * 1000ULL * 1000ULL)

static uint64_t
get_random()
{
    po6::io::fd sysrand(open("/dev/urandom", O_RDONLY));

    if (sysrand.get() < 0)
    {
        abort();
        return 0xcafebabe;
    }

    uint64_t ret;

    if (sysrand.read(&ret, sizeof(ret)) != sizeof(ret))
    {
        abort();
        return 0xdeadbeef;
    }

    return ret;
}

void
worker_thread( numbers::throughput_latency_logger* tll,
        const armnod::argparser& _f,
        const armnod::argparser& _v)
{
    armnod::generator file(armnod::argparser(_f).config());
    armnod::generator val(armnod::argparser(_v).config());
    file.seed(get_random());
    val.seed(get_random());
    numbers::throughput_latency_logger::thread_state ts;
    tll->initialize_thread(&ts);

    try
    {
        hdfsFS cl = hdfsConnect(_connect_host, 0);

        while (__sync_fetch_and_add(&_done, 1) < _number)
        {
            wtf_returncode status = WTF_GARBAGE;
            std::string f = file();
            std::string v = val();
            char filename[71] = "/tmp/";
            strcat(filename, f.data());

            tll->start(&ts,1);
            hdfsFile fd = hdfsOpenFile(cl, filename, O_WRONLY|O_CREAT, 0, 0, 0);
            if(!fd) {
                std::cerr << "Failed to open " << f.data() << " for writing!\n";
                exit(-1);
            }

            tSize num_written_bytes = hdfsWrite(cl, fd, (void*)v.data(), v.size());
            if (hdfsFlush(cl, fd)) {
                std::cerr << "Failed to 'flush' " << f.data()<< std::endl;
                exit(-1);
            }

            hdfsCloseFile(cl, fd);
            tll->finish(&ts);
        }
    }
    catch (po6::error& e)
    {
        std::cerr << "system error: " << e.what() << std::endl;
    }
    catch (std::exception& e)
    {
        std::cerr << "error: " << e.what() << std::endl;
    }

    tll->terminate_thread(&ts);
}

int
main(int argc, const char* argv[])
{
    e::argparser ap;
    ap.autohelp();
    ap.arg().name('p', "port")
        .description("port on the wtf coordinator")
        .metavar("p")
        .as_long(&_connect_port);
    ap.arg().name('P', "Port")
        .description("port on the hyperdex coordinator")
        .metavar("P")
        .as_long(&_hyper_port);
    ap.arg().name('h', "host")
        .description("address of wtf coordinator")
        .metavar("h")
        .as_string(&_connect_host);
    ap.arg().name('H', "host")
        .description("address of hyperdex coordinator")
        .metavar("H")
        .as_string(&_hyper_host);
    ap.arg().name('n', "number")
        .description("perform N operations against the database (default: 1000000)")
        .metavar("N")
        .as_long(&_number);
    ap.arg().name('t', "threads")
        .description("run the test with T concurrent threads (default: 1)")
        .metavar("T")
        .as_long(&_threads);
    ap.arg().name('o', "output")
        .description("output file for benchmark results (default: benchmark.log)")
        .as_string(&_output);
    ap.arg().name('c', "concurrent")
        .description("number of concurrent ops (default=50)")
        .as_long(&_concurrent);
    armnod::argparser file_parser("file-");
    armnod::argparser value_parser("value-");
    ap.add("Filename Generation:", file_parser.parser());
    ap.add("Value Generation:", value_parser.parser());

    if (!ap.parse(argc, argv))
    {
        return EXIT_FAILURE;
    }

    typedef std::tr1::shared_ptr<po6::threads::thread> thread_ptr;
    std::vector<thread_ptr> threads;

    numbers::throughput_latency_logger tll;
    if (!tll.open(_output))
    {
        std::cerr << "could not open log: " << strerror(errno) << std::endl;
        return EXIT_FAILURE;
    }

    for (size_t i = 0; i < _threads; ++i)
    {
        thread_ptr t(new po6::threads::thread(std::tr1::bind(worker_thread, &tll, file_parser, value_parser)));
        threads.push_back(t);
        t->start();
    }

    for (size_t i = 0; i < threads.size(); ++i)
    {
        threads[i]->join();
    }

    if (!tll.close())
    {
        std::cerr << "could not close log: " << strerror(errno) << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before><commit_msg>Prediction: add TODO on semantic_LSTM<commit_after><|endoftext|>


<commit_before>/** \file    add_synonyms.cc
 *  \brief   Generic version for augmenting title data with synonyms found
             in the authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*  We offer a list of tags and subfields where the primary data resides along
    with a list of tags and subfields where the synonym data is found and
    a list of unused fields in the title data where the synonyms can be stored
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

std::string GetTag(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(0, 3);
}

std::string GetSubfieldCodes(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(3);
}

bool FilterPasses(const MarcRecord &record, const std::map<std::string, std::pair<std::string, std::string>> &filter_specs, const std::string &field_spec) {
      auto filter_spec(filter_specs.find(field_spec));
      if (filter_spec == filter_specs.cend())
          return true;

      auto rule(filter_spec->second);
      // We have field_spec in key and rule to match in value
      std::string subfield_codes(GetSubfieldCodes(rule.first));
      if (subfield_codes.length() != 1)
         Error("Invalid subfield specification "  + subfield_codes + " for filter");

      std::string subfield_value;
      if ((subfield_value = record.extractFirstSubfield(GetTag(rule.first), subfield_codes.c_str()[0])).empty())
          return false;

      return subfield_value == rule.second;
}

void ExtractSynonyms(MarcReader * const authority_reader,
                     const std::set<std::string> &primary_tags_and_subfield_codes,
                     const std::set<std::string> &synonym_tags_and_subfield_codes,
                     std::vector<std::map<std::string, std::string>> * const synonym_maps,
                     const std::map<std::string, std::pair<std::string, std::string>> &filter_spec)
{
    while (const MarcRecord record = authority_reader->read()) {
        std::set<std::string>::const_iterator primary;
        std::set<std::string>::const_iterator synonym;
        unsigned int i(0);
        for (primary = primary_tags_and_subfield_codes.begin(), synonym = synonym_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++synonym, ++i)
        {
            // Fill maps with synonyms
            std::vector<std::string> primary_values;
            std::vector<std::string> synonym_values;

            if (FilterPasses(record, filter_spec, *primary) and
                record.extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values) and
                record.extractSubfields(GetTag(*synonym), GetSubfieldCodes(*synonym), &synonym_values))
                    (*synonym_maps)[i].emplace(StringUtil::Join(primary_values, ','),
                                               StringUtil::Join(synonym_values, ','));
        }
    }
}

inline std::string GetMapValueOrEmptyString(const std::map<std::string, std::string> &map,
                                            const std::string &searchterm)
{
    auto value(map.find(searchterm));
    return (value != map.cend()) ? value->second : "";
}

void ProcessRecord(MarcRecord * const record, const std::vector<std::map<std::string, std::string>> &synonym_maps,
                   const std::set<std::string> &primary_tags_and_subfield_codes,
                   const std::set<std::string> &output_tags_and_subfield_codes)
{
    std::set<std::string>::const_iterator primary;
    std::set<std::string>::const_iterator output;
    unsigned int i(0);
    bool modified_record(false);

    if (primary_tags_and_subfield_codes.size() == output_tags_and_subfield_codes.size()) {
        for (primary = primary_tags_and_subfield_codes.begin(), output = output_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++output, ++i)
        {
            std::vector<std::string> primary_values;
            std::set<std::string> synonym_values;
            std::vector<size_t> field_indices;
            if (record->getFieldIndices(GetTag(*primary), &field_indices) != MarcRecord::FIELD_NOT_FOUND) {
                for (auto field_index : field_indices) {
                     primary_values.clear();
                     if (record->getSubfields(field_index).extractSubfields(GetSubfieldCodes(*primary), &primary_values)) {
                        std::string searchterm = StringUtil::Join(primary_values, ',');
                        // First case: Look up synonyms only in one category
                        if (i < synonym_maps.size()) {
                            const auto &synonym_map(synonym_maps[i]);
                            const auto synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                            if (not synonym.empty())
                                synonym_values.insert(synonym);
                        }

                        // Second case: Look up synonyms in all categories
                        else {
                            for (auto &synonym_map : synonym_maps) {
                                const auto &synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                                if (not synonym.empty())
                                   synonym_values.insert(synonym);
                            }
                        }
                    }
                 }

                if (synonym_values.empty())
                     continue;

                // Insert synonyms
                // Abort if field is already populated
                std::string tag(GetTag(*output));
                if (record->getFieldIndex(tag) != MarcRecord::FIELD_NOT_FOUND)
                    Error("Field with tag " + tag + " is not empty for PPN " + record->getControlNumber() + '\n');
                std::string subfield_spec(GetSubfieldCodes(*output));
                if (unlikely(subfield_spec.size() != 1))
                    Error("We currently only support a single subfield and thus specifying " + subfield_spec
                          + " as output subfield is not valid\n");

                std::string synonyms;
                unsigned current_length(0);
                unsigned indicator2(0);

                for (auto synonym_it(synonym_values.cbegin()); synonym_it != synonym_values.cend(); /*Intentionally empty*/) {
                    if (indicator2 > 9)
                        Error ("Currently cannot handle synonyms with total length greater than " + std::to_string(9 * (MarcRecord::MAX_FIELD_LENGTH - 4)) + '\n');

                    if (current_length + synonym_it->length() < MarcRecord::MAX_FIELD_LENGTH - 7) {
                         bool synonyms_empty(synonyms.empty());
                         synonyms += (synonyms_empty ? *synonym_it : " , " + *synonym_it);
                         current_length += synonym_it->length() + (synonyms_empty ? 0 : 3);
                         ++synonym_it;
                    } else {
                        if (not(record->insertSubfield(tag, subfield_spec[0], synonyms, '0', indicator2 + '0')))
                            Error("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                        synonyms.clear();
                        current_length = 0;
                        ++indicator2;
                        modified_record = true;
                    }
                }
                // Write rest of data
                if (not synonyms.empty()) {
                    if (not(record->insertSubfield(tag, subfield_spec[0], synonyms, '0', indicator2 + '0')))
                            Error("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                    modified_record = true;
                }
            }
        }
        if (modified_record)
            ++modified_count;
    }
}

void InsertSynonyms(MarcReader * const marc_reader, MarcWriter * const marc_writer,
                    const std::set<std::string> &primary_tags_and_subfield_codes,
                    const std::set<std::string> &output_tags_and_subfield_codes,
                    std::vector<std::map<std::string, std::string>> &synonym_maps)
{
    while (MarcRecord record = marc_reader->read()) {
        ProcessRecord(&record, synonym_maps, primary_tags_and_subfield_codes, output_tags_and_subfield_codes);
        marc_writer->write(record);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

bool ParseSpec(std::string spec_str, std::set<std::string> * const field_specs, std::map<std::string, std::pair<std::string, std::string>> * filter_specs = nullptr) {
    std::set<std::string> raw_field_specs;

    if (unlikely(StringUtil::Split(spec_str, ':', &raw_field_specs) == 0)) {
        Error("Need at least one field");
        return false;
    }

    if (filter_specs == nullptr) {
        *field_specs = raw_field_specs;
	return true;
    }

    // Iterate over all Field-specs and extract possible filters
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("(\\d{1,3}[a-z]+)\\[(\\d{1,3}[a-z])=(.*)\\]"));

    for (auto field_spec : raw_field_specs) {
        if (matcher->matched(field_spec)) {
            filter_specs->emplace((*matcher)[1], std::make_pair((*matcher)[2], (*matcher)[3]));
            auto bracket = field_spec.find("[");
            field_spec = (bracket != std::string::npos) ? field_spec.erase(bracket, field_spec.length()) : field_spec;
        }
        field_specs->insert(field_spec);
    }
    return true;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        Error("Title data input file name equals output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        Error("Authority data input file name equals output file name!");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(marc_input_filename, MarcReader::BINARY));
    std::unique_ptr<MarcReader> authority_reader(MarcReader::Factory(authority_data_marc_input_filename,
                                                                     MarcReader::BINARY));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(marc_output_filename, MarcWriter::BINARY));

    try {
        // Determine possible mappings
        // Values in square brackets specify a positive criterion for values to be taken into account
        const std::string AUTHORITY_DATA_PRIMARY_SPEC("100abcd[079v=piz]:110abcd:111abcd:130abcd:150abcd:151abcd");
        const std::string AUTHORITY_DATA_SYNONYM_SPEC("400abcd:410abcd:411abcd:430abcd:450abcd:451abcd");
        const std::string TITLE_DATA_PRIMARY_SPEC("600abcd:610abcd:611abcd:630abcd:650abcd:651abcd:689abcd");
        const std::string TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS("180a:181a:182a:183a:184a:185a:186a");

        // Determine fields to handle
        std::set<std::string> primary_tags_and_subfield_codes;
        std::set<std::string> synonym_tags_and_subfield_codes;
        std::set<std::string> input_tags_and_subfield_codes;
        std::set<std::string> output_tags_and_subfield_codes;

        std::map<std::string, std::pair<std::string, std::string>> filter_specs;

        if (not unlikely(ParseSpec(AUTHORITY_DATA_PRIMARY_SPEC, &primary_tags_and_subfield_codes, &filter_specs)))
            Error("Could not properly parse " + AUTHORITY_DATA_PRIMARY_SPEC);

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_SYNONYM_SPEC, ":", &synonym_tags_and_subfield_codes) == 0))
            Error("Need at least one synonym field");

        if (unlikely(StringUtil::Split(TITLE_DATA_PRIMARY_SPEC, ":", &input_tags_and_subfield_codes) == 0))
            Error("Need at least one input field");

        if (unlikely(StringUtil::Split(TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS, ":", &output_tags_and_subfield_codes)
                     == 0))
            Error("Need at least one output field");

        unsigned num_of_authority_entries(primary_tags_and_subfield_codes.size());

        if (synonym_tags_and_subfield_codes.size() != num_of_authority_entries)
            Error("Number of authority primary specs must match number of synonym specs");
        if (input_tags_and_subfield_codes.size() != output_tags_and_subfield_codes.size())
            Error("Number of fields title entry specs must match number of output specs");

        std::vector<std::map<std::string, std::string>> synonym_maps(num_of_authority_entries,
                                                                     std::map<std::string, std::string>());

        // Extract the synonyms from authority data
        ExtractSynonyms(authority_reader.get(), primary_tags_and_subfield_codes, synonym_tags_and_subfield_codes,
                        &synonym_maps, filter_specs);

        // Iterate over the title data
        InsertSynonyms(marc_reader.get(), marc_writer.get(), input_tags_and_subfield_codes,
                       output_tags_and_subfield_codes, synonym_maps);

    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Clarified one aspect<commit_after>/** \file    add_synonyms.cc
 *  \brief   Generic version for augmenting title data with synonyms found
             in the authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*  We offer a list of tags and subfields where the primary data resides along
    with a list of tags and subfields where the synonym data is found and
    a list of unused fields in the title data where the synonyms can be stored
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);
const unsigned FIELD_METADATA_SIZE(4);

void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

std::string GetTag(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(0, 3);
}

std::string GetSubfieldCodes(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(3);
}

bool FilterPasses(const MarcRecord &record, const std::map<std::string, std::pair<std::string, std::string>> &filter_specs, const std::string &field_spec) {
      auto filter_spec(filter_specs.find(field_spec));
      if (filter_spec == filter_specs.cend())
          return true;

      auto rule(filter_spec->second);
      // We have field_spec in key and rule to match in value
      std::string subfield_codes(GetSubfieldCodes(rule.first));
      if (subfield_codes.length() != 1)
         Error("Invalid subfield specification "  + subfield_codes + " for filter");

      std::string subfield_value;
      if ((subfield_value = record.extractFirstSubfield(GetTag(rule.first), subfield_codes.c_str()[0])).empty())
          return false;

      return subfield_value == rule.second;
}

void ExtractSynonyms(MarcReader * const authority_reader,
                     const std::set<std::string> &primary_tags_and_subfield_codes,
                     const std::set<std::string> &synonym_tags_and_subfield_codes,
                     std::vector<std::map<std::string, std::string>> * const synonym_maps,
                     const std::map<std::string, std::pair<std::string, std::string>> &filter_spec)
{
    while (const MarcRecord record = authority_reader->read()) {
        std::set<std::string>::const_iterator primary;
        std::set<std::string>::const_iterator synonym;
        unsigned int i(0);
        for (primary = primary_tags_and_subfield_codes.begin(), synonym = synonym_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++synonym, ++i)
        {
            // Fill maps with synonyms
            std::vector<std::string> primary_values;
            std::vector<std::string> synonym_values;

            if (FilterPasses(record, filter_spec, *primary) and
                record.extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values) and
                record.extractSubfields(GetTag(*synonym), GetSubfieldCodes(*synonym), &synonym_values))
                    (*synonym_maps)[i].emplace(StringUtil::Join(primary_values, ','),
                                               StringUtil::Join(synonym_values, ','));
        }
    }
}

inline std::string GetMapValueOrEmptyString(const std::map<std::string, std::string> &map,
                                            const std::string &searchterm)
{
    auto value(map.find(searchterm));
    return (value != map.cend()) ? value->second : "";
}

void ProcessRecord(MarcRecord * const record, const std::vector<std::map<std::string, std::string>> &synonym_maps,
                   const std::set<std::string> &primary_tags_and_subfield_codes,
                   const std::set<std::string> &output_tags_and_subfield_codes)
{
    std::set<std::string>::const_iterator primary;
    std::set<std::string>::const_iterator output;
    unsigned int i(0);
    bool modified_record(false);

    if (primary_tags_and_subfield_codes.size() == output_tags_and_subfield_codes.size()) {
        for (primary = primary_tags_and_subfield_codes.begin(), output = output_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++output, ++i)
        {
            std::vector<std::string> primary_values;
            std::set<std::string> synonym_values;
            std::vector<size_t> field_indices;
            if (record->getFieldIndices(GetTag(*primary), &field_indices) != MarcRecord::FIELD_NOT_FOUND) {
                for (auto field_index : field_indices) {
                     primary_values.clear();
                     if (record->getSubfields(field_index).extractSubfields(GetSubfieldCodes(*primary), &primary_values)) {
                        std::string searchterm = StringUtil::Join(primary_values, ',');
                        // First case: Look up synonyms only in one category
                        if (i < synonym_maps.size()) {
                            const auto &synonym_map(synonym_maps[i]);
                            const auto synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                            if (not synonym.empty())
                                synonym_values.insert(synonym);
                        }

                        // Second case: Look up synonyms in all categories
                        else {
                            for (auto &synonym_map : synonym_maps) {
                                const auto &synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                                if (not synonym.empty())
                                   synonym_values.insert(synonym);
                            }
                        }
                    }
                 }

                if (synonym_values.empty())
                     continue;

                // Insert synonyms
                // Abort if field is already populated
                std::string tag(GetTag(*output));
                if (record->getFieldIndex(tag) != MarcRecord::FIELD_NOT_FOUND)
                    Error("Field with tag " + tag + " is not empty for PPN " + record->getControlNumber() + '\n');
                std::string subfield_spec(GetSubfieldCodes(*output));
                if (unlikely(subfield_spec.size() != 1))
                    Error("We currently only support a single subfield and thus specifying " + subfield_spec
                          + " as output subfield is not valid\n");

                std::string synonyms;
                unsigned current_length(0);
                unsigned indicator2(0);

                for (auto synonym_it(synonym_values.cbegin()); synonym_it != synonym_values.cend(); /*Intentionally empty*/) {
                    if (indicator2 > 9)
                        Error ("Currently cannot handle synonyms with total length greater than " + std::to_string(9 * (MarcRecord::MAX_FIELD_LENGTH - FIELD_METADATA_SIZE)) + '\n');

                    if (current_length + synonym_it->length() < MarcRecord::MAX_FIELD_LENGTH - (FIELD_METADATA_SIZE + 3 /* consider " , " */) {
                         bool synonyms_empty(synonyms.empty());
                         synonyms += (synonyms_empty ? *synonym_it : " , " + *synonym_it);
                         current_length += synonym_it->length() + (synonyms_empty ? 0 : 3);
                         ++synonym_it;
                    } else {
                        if (not(record->insertSubfield(tag, subfield_spec[0], synonyms, '0', indicator2 + '0')))
                            Error("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                        synonyms.clear();
                        current_length = 0;
                        ++indicator2;
                        modified_record = true;
                    }
                }
                // Write rest of data
                if (not synonyms.empty()) {
                    if (not(record->insertSubfield(tag, subfield_spec[0], synonyms, '0', indicator2 + '0')))
                            Error("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                    modified_record = true;
                }
            }
        }
        if (modified_record)
            ++modified_count;
    }
}

void InsertSynonyms(MarcReader * const marc_reader, MarcWriter * const marc_writer,
                    const std::set<std::string> &primary_tags_and_subfield_codes,
                    const std::set<std::string> &output_tags_and_subfield_codes,
                    std::vector<std::map<std::string, std::string>> &synonym_maps)
{
    while (MarcRecord record = marc_reader->read()) {
        ProcessRecord(&record, synonym_maps, primary_tags_and_subfield_codes, output_tags_and_subfield_codes);
        marc_writer->write(record);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

bool ParseSpec(std::string spec_str, std::set<std::string> * const field_specs, std::map<std::string, std::pair<std::string, std::string>> * filter_specs = nullptr) {
    std::set<std::string> raw_field_specs;

    if (unlikely(StringUtil::Split(spec_str, ':', &raw_field_specs) == 0)) {
        Error("Need at least one field");
        return false;
    }

    if (filter_specs == nullptr) {
        *field_specs = raw_field_specs;
	return true;
    }

    // Iterate over all Field-specs and extract possible filters
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("(\\d{1,3}[a-z]+)\\[(\\d{1,3}[a-z])=(.*)\\]"));

    for (auto field_spec : raw_field_specs) {
        if (matcher->matched(field_spec)) {
            filter_specs->emplace((*matcher)[1], std::make_pair((*matcher)[2], (*matcher)[3]));
            auto bracket = field_spec.find("[");
            field_spec = (bracket != std::string::npos) ? field_spec.erase(bracket, field_spec.length()) : field_spec;
        }
        field_specs->insert(field_spec);
    }
    return true;
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        Error("Title data input file name equals output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        Error("Authority data input file name equals output file name!");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(marc_input_filename, MarcReader::BINARY));
    std::unique_ptr<MarcReader> authority_reader(MarcReader::Factory(authority_data_marc_input_filename,
                                                                     MarcReader::BINARY));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(marc_output_filename, MarcWriter::BINARY));

    try {
        // Determine possible mappings
        // Values in square brackets specify a positive criterion for values to be taken into account
        const std::string AUTHORITY_DATA_PRIMARY_SPEC("100abcd[079v=piz]:110abcd:111abcd:130abcd:150abcd:151abcd");
        const std::string AUTHORITY_DATA_SYNONYM_SPEC("400abcd:410abcd:411abcd:430abcd:450abcd:451abcd");
        const std::string TITLE_DATA_PRIMARY_SPEC("600abcd:610abcd:611abcd:630abcd:650abcd:651abcd:689abcd");
        const std::string TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS("180a:181a:182a:183a:184a:185a:186a");

        // Determine fields to handle
        std::set<std::string> primary_tags_and_subfield_codes;
        std::set<std::string> synonym_tags_and_subfield_codes;
        std::set<std::string> input_tags_and_subfield_codes;
        std::set<std::string> output_tags_and_subfield_codes;

        std::map<std::string, std::pair<std::string, std::string>> filter_specs;

        if (not unlikely(ParseSpec(AUTHORITY_DATA_PRIMARY_SPEC, &primary_tags_and_subfield_codes, &filter_specs)))
            Error("Could not properly parse " + AUTHORITY_DATA_PRIMARY_SPEC);

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_SYNONYM_SPEC, ":", &synonym_tags_and_subfield_codes) == 0))
            Error("Need at least one synonym field");

        if (unlikely(StringUtil::Split(TITLE_DATA_PRIMARY_SPEC, ":", &input_tags_and_subfield_codes) == 0))
            Error("Need at least one input field");

        if (unlikely(StringUtil::Split(TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS, ":", &output_tags_and_subfield_codes)
                     == 0))
            Error("Need at least one output field");

        unsigned num_of_authority_entries(primary_tags_and_subfield_codes.size());

        if (synonym_tags_and_subfield_codes.size() != num_of_authority_entries)
            Error("Number of authority primary specs must match number of synonym specs");
        if (input_tags_and_subfield_codes.size() != output_tags_and_subfield_codes.size())
            Error("Number of fields title entry specs must match number of output specs");

        std::vector<std::map<std::string, std::string>> synonym_maps(num_of_authority_entries,
                                                                     std::map<std::string, std::string>());

        // Extract the synonyms from authority data
        ExtractSynonyms(authority_reader.get(), primary_tags_and_subfield_codes, synonym_tags_and_subfield_codes,
                        &synonym_maps, filter_specs);

        // Iterate over the title data
        InsertSynonyms(marc_reader.get(), marc_writer.get(), input_tags_and_subfield_codes,
                       output_tags_and_subfield_codes, synonym_maps);

    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/Atomic.hpp"
#include "libbirch/type.hpp"
#include "libbirch/memory.hpp"

namespace libbirch {
/**
 * %Shared object.
 *
 * @tparam T Type, must derive from Any.
 *
 * Supports reference counted garbage collection. Cycles are collected by
 * periodically calling collect(); currently this must be done manually at
 * opportune times.
 *
 * @attention While Shared maintains a pointer to a referent object, it likes
 * to pretend it's not a pointer. This behavior differs from
 * [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr).
 * In particular, its default constructor does not initialize the pointer to
 * `nullptr`, but rather default-constructs an object of type `T` and sets the
 * pointer to that. Consider using a [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional/optional)
 * with a Shared value instead of `nullptr`.
 */
template<class T>
class Shared {
  template<class U> friend class Shared;
  friend class Marker;
  friend class Scanner;
  friend class Reacher;
  friend class Collector;
  friend class BiconnectedCollector;
  friend class Spanner;
  friend class Bridger;
  friend class Copier;
  friend class BiconnectedCopier;
  friend class Destroyer;
public:
  using value_type = T;

  /**
   * Default constructor. Constructs a new referent using the default
   * constructor.
   */
  Shared() :
      Shared(new T(), false) {
    //
  }

  /**
   * Constructor. Constructs a new referent with the given arguments. The
   * first is a placeholder (pass [`std::in_place`](https://en.cppreference.com/w/cpp/utility/in_place))
   * to distinguish this constructor from copy and move constructors.
   *
   * @note [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional/)
   * behaves similarly with regard to [`std::in_place`](https://en.cppreference.com/w/cpp/utility/in_place).
   */
  template<class... Args>
  Shared(std::in_place_t, Args&&... args) :
      Shared(new T(std::forward<Args>(args)...), false) {
    //
  }

  /**
   * Constructor.
   *
   * @param ptr Raw pointer.
   * @param b Is this a bridge?
   */
  Shared(T* ptr, const bool b = false) :
      ptr(pack(ptr)),
      a(ptr->isAcyclic_()),
      b(b) {
    if (ptr) {
      ptr->incShared_();
    }
  }

  /**
   * Copy constructor.
   */
  Shared(const Shared& o) : ptr(o.ptr), a(o.a), b(o.b) {
    if (ptr) {
      if (biconnected_copy()) {
        if (b) {
          unpack(ptr)->incShared_();
        } else {
          // deferred until Copier or BiconnectedCopier visits and updates
        }
      } else {
        if (b) {
          store(o.get());  // copy next biconnected component
          b = false;
        }
        unpack(ptr)->incShared_();
      }
    }
  }

  /**
   * Generic copy constructor.
   */
  template<class U, std::enable_if_t<std::is_base_of<T,U>::value,int> = 0>
  Shared(const Shared<U>& o) :
      ptr(pack(o.get())),
      a(o.a),
      b(false) {
    if (ptr) {
      unpack(ptr)->incShared_();
    }
  }

  /**
   * Move constructor.
   */
  Shared(Shared&& o) : ptr(o.ptr), a(o.a), b(o.b) {
    o.store(nullptr);
    o.a = false;
    o.b = false;
  }

  /**
   * Generic move constructor.
   */
  template<class U, std::enable_if_t<std::is_base_of<T,U>::value,int> = 0>
  Shared(Shared<U>&& o) : ptr(o.ptr), a(o.a), b(o.b) {
    o.store(nullptr);
    o.a = false;
    o.b = false;
  }

  /**
   * Destructor.
   */
  ~Shared() {
    release();
  }

  /**
   * Copy assignment.
   */
  Shared& operator=(const Shared& o) {
    replace(o);
    return *this;
  }

  /**
   * Generic copy assignment.
   */
  template<class U, std::enable_if_t<std::is_base_of<T,U>::value,int> = 0>
  Shared& operator=(const Shared<U>& o) {
    replace(o);
    return *this;
  }

  /**
   * Move assignment.
   */
  Shared& operator=(Shared&& o) {
    replace(std::move(o));
    return *this;
  }

  /**
   * Generic move assignment.
   */
  template<class U, std::enable_if_t<std::is_base_of<T,U>::value,int> = 0>
  Shared& operator=(Shared<U>&& o) {
    replace(std::move(o));
    return *this;
  }

  /**
   * Value assignment.
   */
  template<class U, std::enable_if_t<!std::is_base_of<T,U>::value,int> = 0>
  Shared<T>& operator=(const U& o) {
    *get() = o;
    return *this;
  }

  /**
   * Value assignment.
   */
  template<class U, std::enable_if_t<!std::is_base_of<T,U>::value,int> = 0>
  const Shared<T>& operator=(const U& o) const {
    *get() = o;
    return *this;
  }

  /**
   * Is the pointer not null?
   *
   * This is used instead of an `operator bool()` so as not to conflict with
   * conversion operators in the referent type.
   */
  bool query() const {
    return ptr != 0;
  }

  /**
   * Get the raw pointer.
   */
  T* get();

  /**
   * Get the raw pointer.
   */
  T* get() const {
    return const_cast<Shared<T>*>(this)->get();
  }

  /**
   * Get the raw pointer without copy-on-use.
   */
  T* load() const {
    return unpack(ptr);
  }

  /**
   * Bridge finding. Finds bridges in the reachable graph. Must be followed by
   * copy() for correct behavior.
   */
  void bridge();

  /**
   * Bridge finding.
   */
  void bridge() const {
    return const_cast<Shared<T>*>(this)->bridge();
  }

  /**
   * Deep copy. Copies the subgraph up to the nearest reachable bridges, the
   * remainder deferred until needed. If bridge() has been called previously,
   * this constitutes a lazy copy, otherwise an eager copy. It is correct
   * either way.
   */
  Shared<T> copy();

  /**
   * Deep copy.
   */
  Shared<T> copy() const {
    return const_cast<Shared<T>*>(this)->copy();
  }

  /**
   * Replace.
   */
  template<class U>
  void replace(const Shared<U>& o) {
    auto ptr = unpack(this->ptr);
    auto a = this->a;
    auto b = this->b;

    /* when duplicating a pointer, may need to trigger a biconnected copy */
    auto ptr1 = o.get();
    if (ptr1) {
      ptr1->incShared_();
    }

    this->ptr = pack(ptr1);
    this->a = o.a;
    this->b = false;  // if it was a bridge, now copied

    if (ptr) {
      if (ptr == ptr1) {
        ptr->decSharedReachable_();
      } else if (a) {
        ptr->decSharedAcyclic_();
      } else if (b) {
        ptr->decSharedBridge_();
      } else {
        ptr->decShared_();
      }
    }
  }

  /**
   * Replace.
   */
  template<class U>
  void replace(Shared<U>&& o) {
    auto ptr = unpack(this->ptr);
    auto a = this->a;
    auto b = this->b;

    this->ptr = o.ptr;
    this->a = o.a;
    this->b = o.b;

    if (ptr) {
      if (ptr == unpack(this->ptr)) {
        ptr->decSharedReachable_();
      } else if (a) {
        ptr->decSharedAcyclic_();
      } else if (b) {
        ptr->decSharedBridge_();
      } else {
        ptr->decShared_();
      }
    }

    o.ptr = 0;
    o.a = false;
    o.b = false;
  }

  /**
   * Release the referent.
   */
  void release() {
    auto ptr = unpack(this->ptr);
    auto a = this->a;
    auto b = this->b;

    this->ptr = 0;
    this->a = false;
    this->b = false;

    if (ptr) {
      if (a) {
        ptr->decSharedAcyclic_();
      } else if (b) {
        ptr->decSharedBridge_();
      } else {
        ptr->decShared_();
      }
    }
  }

  /**
   * @internal
   *
   * Release the referent, during collection of a biconnected component.
   */
  void releaseBiconnected() {
    auto ptr = unpack(this->ptr);
    auto a = this->a;
    auto b = this->b;

    this->ptr = 0;
    this->a = false;
    this->b = false;

    if (ptr) {
      if (a) {
        ptr->decSharedAcyclic_();
      } else if (b) {
        ptr->decSharedBridge_();
      } else {
        ptr->decSharedBiconnected_();
      }
    }
  }

  /**
   * Dereference.
   */
  T& operator*() {
    return *get();
  }

  /**
   * Dereference.
   */
  T& operator*() const {
    return *get();
  }

  /**
   * Member access.
   */
  T* operator->() {
    return get();
  }

  /**
   * Member access.
   */
  T* operator->() const {
    return get();
  }

  /**
   * Equality operator.
   */
  template<class U>
  bool operator==(const Shared<U>& o) const {
    return get() == o.get();
  }

  /**
   * Non-equality operator.
   */
  template<class U>
  bool operator!=(const Shared<U>& o) const {
    return get() != o.get();
  }

  /**
   * Call on referent.
   */
  template<class... Args>
  auto& operator()(Args&&... args) {
    return (*get())(std::forward<Args>(args)...);
  }

  /**
   * Call on referent.
   */
  template<class... Args>
  auto& operator()(Args&&... args) const {
    return const_cast<Shared<T>*>(this)->operator()(std::forward<Args>(args)...);
  }

private:
  /**
   * Store the raw pointer without reference count updates.
   */
  void store(T* ptr) {
    this->ptr = pack(ptr);
  }

  /**
   * Unpack a raw pointer after loading.
   */
  static T* unpack(int64_t ptr) {
    return reinterpret_cast<T*>(ptr);
  }

  /**
   * Pack a raw pointer before storing.
   */
  static int64_t pack(T* ptr) {
    return reinterpret_cast<int64_t>(ptr);
  }

  /**
   * Raw pointer.
   */
  int64_t ptr:(8*sizeof(int64_t) - 2);

  /**
   * Is this an acyclic edge?
   */
  bool a:1;

  /**
   * Is this a bridge edge?
   */
  bool b:1;
};

template<class T>
struct is_pointer<Shared<T>> {
  static const bool value = true;
};

template<class T>
struct unwrap_pointer<Shared<T>> {
  using type = T;
};
}

#include "libbirch/Spanner.hpp"
#include "libbirch/Bridger.hpp"
#include "libbirch/Copier.hpp"
#include "libbirch/BiconnectedCopier.hpp"

template<class T>
T* libbirch::Shared<T>::get() {
  T* o = unpack(ptr);
  if (b) {
    if (!o->isUniqueHead_()) {  // last reference optimization
      /* copy biconnected component */
      assert(!biconnected_copy());
      biconnected_copy(true);
      assert(biconnected_copy());
      o = BiconnectedCopier(o).visitObject(o);
      biconnected_copy(true);
      assert(!biconnected_copy());

      /* replace pointer */
      o->incShared_();
      auto old = unpack(ptr);
      ptr = pack(o);
      old->decSharedBridge_();
    }
    b = false;  // no longer a bridge
  }
  return o;
}

template<class T>
void libbirch::Shared<T>::bridge() {
  Spanner().visit(0, 1, *this);
  Bridger().visit(1, 0, *this);
}

template<class T>
libbirch::Shared<T> libbirch::Shared<T>::copy() {
  T* o = unpack(ptr);
  if (!b) {
    /* the copy is *not* of a biconnected component here, use the
     * general-purpose Copier for this */
    assert(!biconnected_copy());
    biconnected_copy(true);
    assert(biconnected_copy());
    o = Copier().visitObject(o);
    biconnected_copy(true);
    assert(!biconnected_copy());
  }
  return Shared<T>(o, b);
}
<commit_msg>Fix for constructing Shared with nullptr.<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/Atomic.hpp"
#include "libbirch/type.hpp"
#include "libbirch/memory.hpp"

namespace libbirch {
/**
 * %Shared object.
 *
 * @tparam T Type, must derive from Any.
 *
 * Supports reference counted garbage collection. Cycles are collected by
 * periodically calling collect(); currently this must be done manually at
 * opportune times.
 *
 * @attention While Shared maintains a pointer to a referent object, it likes
 * to pretend it's not a pointer. This behavior differs from
 * [`std::shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr).
 * In particular, its default constructor does not initialize the pointer to
 * `nullptr`, but rather default-constructs an object of type `T` and sets the
 * pointer to that. Consider using a [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional/optional)
 * with a Shared value instead of `nullptr`.
 */
template<class T>
class Shared {
  template<class U> friend class Shared;
  friend class Marker;
  friend class Scanner;
  friend class Reacher;
  friend class Collector;
  friend class BiconnectedCollector;
  friend class Spanner;
  friend class Bridger;
  friend class Copier;
  friend class BiconnectedCopier;
  friend class Destroyer;
public:
  using value_type = T;

  /**
   * Default constructor. Constructs a new referent using the default
   * constructor.
   */
  Shared() :
      Shared(new T(), false) {
    //
  }

  /**
   * Constructor. Constructs a new referent with the given arguments. The
   * first is a placeholder (pass [`std::in_place`](https://en.cppreference.com/w/cpp/utility/in_place))
   * to distinguish this constructor from copy and move constructors.
   *
   * @note [`std::optional`](https://en.cppreference.com/w/cpp/utility/optional/)
   * behaves similarly with regard to [`std::in_place`](https://en.cppreference.com/w/cpp/utility/in_place).
   */
  template<class... Args>
  Shared(std::in_place_t, Args&&... args) :
      Shared(new T(std::forward<Args>(args)...), false) {
    //
  }

  /**
   * Constructor.
   *
   * @param ptr Raw pointer.
   * @param b Is this a bridge?
   */
  Shared(T* ptr, const bool b = false) :
      ptr(pack(ptr)),
      a(ptr && ptr->isAcyclic_()),
      b(b) {
    if (ptr) {
      ptr->incShared_();
    }
  }

  /**
   * Copy constructor.
   */
  Shared(const Shared& o) : ptr(o.ptr), a(o.a), b(o.b) {
    if (ptr) {
      if (biconnected_copy()) {
        if (b) {
          unpack(ptr)->incShared_();
        } else {
          // deferred until Copier or BiconnectedCopier visits and updates
        }
      } else {
        if (b) {
          store(o.get());  // copy next biconnected component
          b = false;
        }
        unpack(ptr)->incShared_();
      }
    }
  }

  /**
   * Generic copy constructor.
   */
  template<class U, std::enable_if_t<std::is_base_of<T,U>::value,int> = 0>
  Shared(const Shared<U>& o) :
      ptr(pack(o.get())),
      a(o.a),
      b(false) {
    if (ptr) {
      unpack(ptr)->incShared_();
    }
  }

  /**
   * Move constructor.
   */
  Shared(Shared&& o) : ptr(o.ptr), a(o.a), b(o.b) {
    o.store(nullptr);
    o.a = false;
    o.b = false;
  }

  /**
   * Generic move constructor.
   */
  template<class U, std::enable_if_t<std::is_base_of<T,U>::value,int> = 0>
  Shared(Shared<U>&& o) : ptr(o.ptr), a(o.a), b(o.b) {
    o.store(nullptr);
    o.a = false;
    o.b = false;
  }

  /**
   * Destructor.
   */
  ~Shared() {
    release();
  }

  /**
   * Copy assignment.
   */
  Shared& operator=(const Shared& o) {
    replace(o);
    return *this;
  }

  /**
   * Generic copy assignment.
   */
  template<class U, std::enable_if_t<std::is_base_of<T,U>::value,int> = 0>
  Shared& operator=(const Shared<U>& o) {
    replace(o);
    return *this;
  }

  /**
   * Move assignment.
   */
  Shared& operator=(Shared&& o) {
    replace(std::move(o));
    return *this;
  }

  /**
   * Generic move assignment.
   */
  template<class U, std::enable_if_t<std::is_base_of<T,U>::value,int> = 0>
  Shared& operator=(Shared<U>&& o) {
    replace(std::move(o));
    return *this;
  }

  /**
   * Value assignment.
   */
  template<class U, std::enable_if_t<!std::is_base_of<T,U>::value,int> = 0>
  Shared<T>& operator=(const U& o) {
    *get() = o;
    return *this;
  }

  /**
   * Value assignment.
   */
  template<class U, std::enable_if_t<!std::is_base_of<T,U>::value,int> = 0>
  const Shared<T>& operator=(const U& o) const {
    *get() = o;
    return *this;
  }

  /**
   * Is the pointer not null?
   *
   * This is used instead of an `operator bool()` so as not to conflict with
   * conversion operators in the referent type.
   */
  bool query() const {
    return ptr != 0;
  }

  /**
   * Get the raw pointer.
   */
  T* get();

  /**
   * Get the raw pointer.
   */
  T* get() const {
    return const_cast<Shared<T>*>(this)->get();
  }

  /**
   * Get the raw pointer without copy-on-use.
   */
  T* load() const {
    return unpack(ptr);
  }

  /**
   * Bridge finding. Finds bridges in the reachable graph. Must be followed by
   * copy() for correct behavior.
   */
  void bridge();

  /**
   * Bridge finding.
   */
  void bridge() const {
    return const_cast<Shared<T>*>(this)->bridge();
  }

  /**
   * Deep copy. Copies the subgraph up to the nearest reachable bridges, the
   * remainder deferred until needed. If bridge() has been called previously,
   * this constitutes a lazy copy, otherwise an eager copy. It is correct
   * either way.
   */
  Shared<T> copy();

  /**
   * Deep copy.
   */
  Shared<T> copy() const {
    return const_cast<Shared<T>*>(this)->copy();
  }

  /**
   * Replace.
   */
  template<class U>
  void replace(const Shared<U>& o) {
    auto ptr = unpack(this->ptr);
    auto a = this->a;
    auto b = this->b;

    /* when duplicating a pointer, may need to trigger a biconnected copy */
    auto ptr1 = o.get();
    if (ptr1) {
      ptr1->incShared_();
    }

    this->ptr = pack(ptr1);
    this->a = o.a;
    this->b = false;  // if it was a bridge, now copied

    if (ptr) {
      if (ptr == ptr1) {
        ptr->decSharedReachable_();
      } else if (a) {
        ptr->decSharedAcyclic_();
      } else if (b) {
        ptr->decSharedBridge_();
      } else {
        ptr->decShared_();
      }
    }
  }

  /**
   * Replace.
   */
  template<class U>
  void replace(Shared<U>&& o) {
    auto ptr = unpack(this->ptr);
    auto a = this->a;
    auto b = this->b;

    this->ptr = o.ptr;
    this->a = o.a;
    this->b = o.b;

    if (ptr) {
      if (ptr == unpack(this->ptr)) {
        ptr->decSharedReachable_();
      } else if (a) {
        ptr->decSharedAcyclic_();
      } else if (b) {
        ptr->decSharedBridge_();
      } else {
        ptr->decShared_();
      }
    }

    o.ptr = 0;
    o.a = false;
    o.b = false;
  }

  /**
   * Release the referent.
   */
  void release() {
    auto ptr = unpack(this->ptr);
    auto a = this->a;
    auto b = this->b;

    this->ptr = 0;
    this->a = false;
    this->b = false;

    if (ptr) {
      if (a) {
        ptr->decSharedAcyclic_();
      } else if (b) {
        ptr->decSharedBridge_();
      } else {
        ptr->decShared_();
      }
    }
  }

  /**
   * @internal
   *
   * Release the referent, during collection of a biconnected component.
   */
  void releaseBiconnected() {
    auto ptr = unpack(this->ptr);
    auto a = this->a;
    auto b = this->b;

    this->ptr = 0;
    this->a = false;
    this->b = false;

    if (ptr) {
      if (a) {
        ptr->decSharedAcyclic_();
      } else if (b) {
        ptr->decSharedBridge_();
      } else {
        ptr->decSharedBiconnected_();
      }
    }
  }

  /**
   * Dereference.
   */
  T& operator*() {
    return *get();
  }

  /**
   * Dereference.
   */
  T& operator*() const {
    return *get();
  }

  /**
   * Member access.
   */
  T* operator->() {
    return get();
  }

  /**
   * Member access.
   */
  T* operator->() const {
    return get();
  }

  /**
   * Equality operator.
   */
  template<class U>
  bool operator==(const Shared<U>& o) const {
    return get() == o.get();
  }

  /**
   * Non-equality operator.
   */
  template<class U>
  bool operator!=(const Shared<U>& o) const {
    return get() != o.get();
  }

  /**
   * Call on referent.
   */
  template<class... Args>
  auto& operator()(Args&&... args) {
    return (*get())(std::forward<Args>(args)...);
  }

  /**
   * Call on referent.
   */
  template<class... Args>
  auto& operator()(Args&&... args) const {
    return const_cast<Shared<T>*>(this)->operator()(std::forward<Args>(args)...);
  }

private:
  /**
   * Store the raw pointer without reference count updates.
   */
  void store(T* ptr) {
    this->ptr = pack(ptr);
  }

  /**
   * Unpack a raw pointer after loading.
   */
  static T* unpack(int64_t ptr) {
    return reinterpret_cast<T*>(ptr);
  }

  /**
   * Pack a raw pointer before storing.
   */
  static int64_t pack(T* ptr) {
    return reinterpret_cast<int64_t>(ptr);
  }

  /**
   * Raw pointer.
   */
  int64_t ptr:(8*sizeof(int64_t) - 2);

  /**
   * Is this an acyclic edge?
   */
  bool a:1;

  /**
   * Is this a bridge edge?
   */
  bool b:1;
};

template<class T>
struct is_pointer<Shared<T>> {
  static const bool value = true;
};

template<class T>
struct unwrap_pointer<Shared<T>> {
  using type = T;
};
}

#include "libbirch/Spanner.hpp"
#include "libbirch/Bridger.hpp"
#include "libbirch/Copier.hpp"
#include "libbirch/BiconnectedCopier.hpp"

template<class T>
T* libbirch::Shared<T>::get() {
  T* o = unpack(ptr);
  if (b) {
    if (!o->isUniqueHead_()) {  // last reference optimization
      /* copy biconnected component */
      assert(!biconnected_copy());
      biconnected_copy(true);
      assert(biconnected_copy());
      o = BiconnectedCopier(o).visitObject(o);
      biconnected_copy(true);
      assert(!biconnected_copy());

      /* replace pointer */
      o->incShared_();
      auto old = unpack(ptr);
      ptr = pack(o);
      old->decSharedBridge_();
    }
    b = false;  // no longer a bridge
  }
  return o;
}

template<class T>
void libbirch::Shared<T>::bridge() {
  Spanner().visit(0, 1, *this);
  Bridger().visit(1, 0, *this);
}

template<class T>
libbirch::Shared<T> libbirch::Shared<T>::copy() {
  T* o = unpack(ptr);
  if (!b) {
    /* the copy is *not* of a biconnected component here, use the
     * general-purpose Copier for this */
    assert(!biconnected_copy());
    biconnected_copy(true);
    assert(biconnected_copy());
    o = Copier().visitObject(o);
    biconnected_copy(true);
    assert(!biconnected_copy());
  }
  return Shared<T>(o, b);
}
<|endoftext|>