<commit_before>#include <cctype>
#include <fstream>
#include <stdio.h>
#include <sstream> // ostringstream
#include "utils/logoutput.h"

#include "settings.h"

SettingsBase::SettingsBase()
: parent(NULL)
{
}
SettingsBase::SettingsBase(SettingsBase* parent)
: parent(parent)
{
}

void SettingsBase::setSetting(std::string key, std::string value)
{
    if (SettingsBase::settingRegistry.settingExists(key))
        settings[key] = value;
    else
        cura::logError("Ignoring unknown setting %s\n", key.c_str() );
}

int SettingsBase::getSettingInt(std::string key)
{
    std::string value = getSetting(key);
    return atoi(value.c_str());
}

std::string SettingsBase::getSetting(std::string key)
{
    if (settings.find(key) != settings.end())
    {
        return settings[key];
    }
    if (parent)
        return parent->getSetting(key);

    if (SettingsBase::settingRegistry.settingExists(key))
        cura::logError("Failed to find setting %s\n", key.c_str());
    else
        cura::logError("Unknown setting %s\n", key.c_str());
    settings[key] = "";
    return "";
}

void SettingsBase::copySettings(SettingsBase& other)
{
    settings = other.settings;
}

bool SettingsBase::hasSetting(std::string key)
{
    if (settings.find(key) != settings.end())
    {
        return true;
    }
    if (parent)
        return parent->hasSetting(key);

    return false;
}

const SettingRegistry SettingsBase::settingRegistry; // define settingRegistry

bool SettingRegistry::settingExists(std::string setting) const
{
    return knownSettings.find(setting) != knownSettings.end();
}

void SettingRegistry::registerSetting(std::string setting)
{
    knownSettings.insert(setting);
}

SettingRegistry::SettingRegistry()
{
    registerSetting("simpleMode");
    registerSetting("spiralizeMode");
    registerSetting("enableOozeShield");
    registerSetting("autoCenter");
    registerSetting("fixHorrible");

    registerSetting("initialSpeedupLayers");
    registerSetting("minimalFeedrate");
    registerSetting("insetXSpeed");
    registerSetting("retractionZHop");
    registerSetting("extruderOffset[3].X");
    registerSetting("extruderOffset[3].Y");
    registerSetting("gcodeFlavor");
    registerSetting("retractionSpeed");
    registerSetting("filamentFlow");
    registerSetting("infillOverlap");
    registerSetting("inset0Speed");
    registerSetting("coolHeadLift");
    registerSetting("extrusionWidth");
    registerSetting("upSkinCount");
    registerSetting("initialLayerSpeed");
    registerSetting("minimalLayerTime");
    registerSetting("infillSpeed");
    registerSetting("fanSpeedMax");
    registerSetting("enableCombing");
    registerSetting("fanSpeedMin");

    registerSetting("raftAirGapLayer0");
    registerSetting("raftBaseThickness");
    registerSetting("raftBaseLinewidth");
    registerSetting("raftBaseSpeed");
    registerSetting("raftInterfaceThickness");
    registerSetting("raftInterfaceLinewidth");
    registerSetting("raftInterfaceLineSpacing");
    registerSetting("raftInterfaceSpeed");
    registerSetting("raftLineSpacing");
    registerSetting("raftFanSpeed");
    registerSetting("raftSurfaceLinewidth");
    registerSetting("raftSurfaceLineSpacing");
    registerSetting("raftSurfaceSpeed");
    registerSetting("raftSurfaceLayers");
    registerSetting("raftSurfaceThickness");
    registerSetting("raftMargin");
    registerSetting("raftAirGap");

    registerSetting("supportXYDistance");
    registerSetting("supportExtruder");
    registerSetting("supportType");
    registerSetting("supportZDistance");
    registerSetting("supportEverywhere");
    registerSetting("supportAngle");
    registerSetting("supportZDistanceBottom");
    registerSetting("supportZDistanceTop");
    registerSetting("supportSpeed");

    registerSetting("areaSupportPolyGenerator");
    registerSetting("supportJoinDistance");
    registerSetting("supportBridgeBack");
    registerSetting("supportAreaSmoothing");
    registerSetting("supportConnectZigZags");

    registerSetting("avoidOverlappingPerimeters");

    registerSetting("preSwitchExtruderCode");
    registerSetting("postSwitchExtruderCode");
    registerSetting("filamentDiameter");
    registerSetting("fanFullOnLayerNr");
    registerSetting("extruderOffset[1].X");
    registerSetting("extruderOffset[1].Y");
    registerSetting("layerThickness");
    registerSetting("initialLayerThickness");
    registerSetting("endCode");
    registerSetting("skirtLineCount");
    registerSetting("supportBottomStairDistance");
    registerSetting("minimalExtrusionBeforeRetraction");
    registerSetting("retractionMinimalDistance");
    registerSetting("skirtMinLength");
    registerSetting("retractionAmount");
    registerSetting("skirtLineCount");
    registerSetting("startCode");
    registerSetting("skirtDistance");
    registerSetting("extruderOffset[2].Y");
    registerSetting("extruderOffset[2].X");
    registerSetting("layer0extrusionWidth");
    registerSetting("moveSpeed");
    registerSetting("skinSpeed");
    registerSetting("supportLineDistance");
    registerSetting("retractionAmountExtruderSwitch");
    registerSetting("sparseInfillLineDistance");
    registerSetting("insetCount");
    registerSetting("downSkinCount");
    registerSetting("multiVolumeOverlap");
    registerSetting("position.X");
    registerSetting("position.Y");
    registerSetting("position.Z");
    registerSetting("retractionPrimeAmount");
    registerSetting("retractionPrimeSpeed");
    registerSetting("skirtSpeed");
    registerSetting("extruderNr");
    registerSetting("sparseInfillCombineCount");
    registerSetting("retractionExtruderSwitchPrimeSpeed");
    registerSetting("retractionExtruderSwitchSpeed");
    registerSetting("infillPattern");
    registerSetting("skinPattern");
    registerSetting("wipeTowerSize");

    for(int n=0; n<MAX_EXTRUDERS; n++)
    {
        std::ostringstream stream;
        stream << "extruderOffset" << n;
        registerSetting(stream.str() + ".X");
        registerSetting(stream.str() + ".Y");
    }
}

void SettingsBase::setDefaultSettings()
{
//     setSetting("simpleMode", "0");
//     setSetting("spiralizeMode", "0");
//     setSetting("enableOozeShield", "0");
//     setSetting("wipeTowerSize", "0");
//     setSetting("extruderNr", "0");
//
//

//     setSetting("", "");
//     setSetting("", "");
//     setSetting("", "");
/*
    setSetting("layerThickness", "150");
    setSetting("initialLayerThickness", "300");
    setSetting("filamentDiameter", "2890");
    setSetting("filamentFlow", "100");
    setSetting("layer0extrusionWidth", "600");
    setSetting("extrusionWidth", "400");
    setSetting("insetCount", "2");
    setSetting("downSkinCount", "6");
    setSetting("upSkinCount", "6");
    setSetting("skinPattern", "LINES");
    setSetting("skirtDistance", "6000");
    setSetting("skirtLineCount", "1");
    setSetting("skirtMinLength", "0");

    setSetting("initialSpeedupLayers", "4");
    setSetting("initialLayerSpeed", "20");
    setSetting("skirtSpeed", "50");
    setSetting("inset0Speed", "50");
    setSetting("insetXSpeed", "50");
    setSetting("skinSpeed", "50");
    setSetting("moveSpeed", "150");
    setSetting("fanFullOnLayerNr", "2");

    setSetting("sparseInfillLineDistance", "500");
    setSetting("sparseInfillCombineCount", "1");
    setSetting("infillOverlap", "15");
    setSetting("infillSpeed", "50");
    setSetting("infillPattern", "INFILL_GRID");

    setSetting("supportType", "LINES");
    setSetting("supportAngle", "60");
    //setSetting("supportAngle", "-1");
    setSetting("supportEverywhere", "0");
    setSetting("supportLineDistance", "2667");
    setSetting("supportXYDistance", "500");
    setSetting("supportZDistance", "100");
    setSetting("supportExtruder", "-1");

    setSetting("areaSupportPolyGenerator", "1"); // TK
    setSetting("supportZDistanceBottom", "100");
    setSetting("supportZDistanceTop", "100");
    setSetting("supportJoinDistance", "1000"); // distance between support blocks which will get merged
    setSetting("supportBridgeBack", "100"); // percentage of bridge between layer and overhang which should be supported
    setSetting("supportBottomStairDistance", "100"); // height of the steps with which the lines support rests on the model

    setSetting("extruderOffset1.X", "18000");
    setSetting("extruderOffset1.Y", "0");

    setSetting("retractionAmount", "4500");
    setSetting("retractionPrimeAmount", "0");
    setSetting("retractionSpeed", "25");
    setSetting("retractionPrimeSpeed", "25");
    setSetting("retractionAmountExtruderSwitch", "14500");
    setSetting("retractionExtruderSwitchSpeed", "25");
    setSetting("retractionExtruderSwitchPrimeSpeed", "25");
    setSetting("retractionMinimalDistance", "1500");
    setSetting("minimalExtrusionBeforeRetraction", "100");
    setSetting("retractionZHop", "0");

    setSetting("enableCombing", "1");
    setSetting("enableOozeShield", "0");
    setSetting("wipeTowerSize", "0");
    setSetting("multiVolumeOverlap", "0");
    setSetting("position.X", "115000"); // UM2
    setSetting("position.Y", "112500");
    setSetting("position.Z", "0");
    setSetting("autoCenter", "1");
    setSetting("extruderNr", "0");

    setSetting("raftMargin", "5000");
    setSetting("raftLineSpacing", "1000");
    setSetting("raftBaseThickness", "0");
    setSetting("raftBaseLinewidth", "0");
    setSetting("raftInterfaceThickness", "0");
    setSetting("raftInterfaceLinewidth", "0");
    setSetting("raftInterfaceLineSpacing", "0");
    setSetting("raftAirGap", "0");
    setSetting("raftAirGapLayer0", "0");
    setSetting("raftBaseSpeed", "15");
    setSetting("raftInterfaceSpeed", "15");
    setSetting("raftFanSpeed", "0");
    setSetting("raftSurfaceThickness", "0");
    setSetting("raftSurfaceLinewidth", "0");
    setSetting("raftSurfaceLineSpacing", "0");
    setSetting("raftSurfaceLayers", "0");
    setSetting("raftSurfaceSpeed", "0");

    setSetting("minimalLayerTime", "5");
    setSetting("minimalFeedrate", "10");
    setSetting("coolHeadLift", "0");
    setSetting("fanSpeedMin", "100");
    setSetting("fanSpeedMax", "100");

    setSetting("spiralizeMode", "0");
    setSetting("simpleMode", "0");
    setSetting("gcodeFlavor", "GCODE_FLAVOR_REPRAP");

    for(int n=0; n<MAX_EXTRUDERS; n++)
    {
        std::ostringstream stream;
        stream << "extruderOffset" << n;
        setSetting(stream.str() + ".X", "0");
        setSetting(stream.str() + ".Y", "0");
    }

    setSetting("startCode",
        "M109 S210     ;Heatup to 210C\n"
        "G21           ;metric values\n"
        "G90           ;absolute positioning\n"
        "G28           ;Home\n"
        "G1 Z15.0 F300 ;move the platform down 15mm\n"
        "G92 E0        ;zero the extruded length\n"
        "G1 F200 E5    ;extrude 5mm of feed stock\n"
        "G92 E0        ;zero the extruded length again\n");
    setSetting("endCode",
        "M104 S0                     ;extruder heater off\n"
        "M140 S0                     ;heated bed heater off (if you have it)\n"
        "G91                            ;relative positioning\n"
        "G1 E-1 F300                    ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n"
        "G1 Z+0.5 E-5 X-20 Y-20 F9000   ;move Z up a bit and retract filament even more\n"
        "G28 X0 Y0                      ;move X/Y to min endstops, so the head is out of the way\n"
        "M84                         ;steppers off\n"
        "G90                         ;absolute positioning\n");
    setSetting("postSwitchExtruderCode", "");
    setSetting("preSwitchExtruderCode", "");
    */
}
<commit_msg>new support settings<commit_after>#include <cctype>
#include <fstream>
#include <stdio.h>
#include <sstream> // ostringstream
#include "utils/logoutput.h"

#include "settings.h"

SettingsBase::SettingsBase()
: parent(NULL)
{
}
SettingsBase::SettingsBase(SettingsBase* parent)
: parent(parent)
{
}

void SettingsBase::setSetting(std::string key, std::string value)
{
    if (SettingsBase::settingRegistry.settingExists(key))
        settings[key] = value;
    else
        cura::logError("Ignoring unknown setting %s\n", key.c_str() );
}

int SettingsBase::getSettingInt(std::string key)
{
    std::string value = getSetting(key);
    return atoi(value.c_str());
}

std::string SettingsBase::getSetting(std::string key)
{
    if (settings.find(key) != settings.end())
    {
        return settings[key];
    }
    if (parent)
        return parent->getSetting(key);

    if (SettingsBase::settingRegistry.settingExists(key))
        cura::logError("Failed to find setting %s\n", key.c_str());
    else
        cura::logError("Unknown setting %s\n", key.c_str());
    settings[key] = "";
    return "";
}

void SettingsBase::copySettings(SettingsBase& other)
{
    settings = other.settings;
}

bool SettingsBase::hasSetting(std::string key)
{
    if (settings.find(key) != settings.end())
    {
        return true;
    }
    if (parent)
        return parent->hasSetting(key);

    return false;
}

const SettingRegistry SettingsBase::settingRegistry; // define settingRegistry

bool SettingRegistry::settingExists(std::string setting) const
{
    return knownSettings.find(setting) != knownSettings.end();
}

void SettingRegistry::registerSetting(std::string setting)
{
    knownSettings.insert(setting);
}

SettingRegistry::SettingRegistry()
{
    registerSetting("simpleMode");
    registerSetting("spiralizeMode");
    registerSetting("enableOozeShield");
    registerSetting("autoCenter");
    registerSetting("fixHorrible");

    registerSetting("initialSpeedupLayers");
    registerSetting("minimalFeedrate");
    registerSetting("insetXSpeed");
    registerSetting("retractionZHop");
    registerSetting("extruderOffset[3].X");
    registerSetting("extruderOffset[3].Y");
    registerSetting("gcodeFlavor");
    registerSetting("retractionSpeed");
    registerSetting("filamentFlow");
    registerSetting("infillOverlap");
    registerSetting("inset0Speed");
    registerSetting("coolHeadLift");
    registerSetting("extrusionWidth");
    registerSetting("upSkinCount");
    registerSetting("initialLayerSpeed");
    registerSetting("minimalLayerTime");
    registerSetting("infillSpeed");
    registerSetting("fanSpeedMax");
    registerSetting("enableCombing");
    registerSetting("fanSpeedMin");

    registerSetting("raftAirGapLayer0");
    registerSetting("raftBaseThickness");
    registerSetting("raftBaseLinewidth");
    registerSetting("raftBaseSpeed");
    registerSetting("raftInterfaceThickness");
    registerSetting("raftInterfaceLinewidth");
    registerSetting("raftInterfaceLineSpacing");
    registerSetting("raftInterfaceSpeed");
    registerSetting("raftLineSpacing");
    registerSetting("raftFanSpeed");
    registerSetting("raftSurfaceLinewidth");
    registerSetting("raftSurfaceLineSpacing");
    registerSetting("raftSurfaceSpeed");
    registerSetting("raftSurfaceLayers");
    registerSetting("raftSurfaceThickness");
    registerSetting("raftMargin");
    registerSetting("raftAirGap");

    registerSetting("supportXYDistance");
    registerSetting("supportExtruder");
    registerSetting("supportType");
    registerSetting("supportZDistance");
    registerSetting("supportEverywhere");
    registerSetting("supportAngle");
    registerSetting("supportZDistanceBottom");
    registerSetting("supportZDistanceTop");
    registerSetting("supportSpeed");

    registerSetting("areaSupportPolyGenerator");
    registerSetting("supportJoinDistance");
    registerSetting("supportBridgeBack");
    registerSetting("supportAreaSmoothing");
    registerSetting("supportConnectZigZags");
    registerSetting("supportMinimalAreaSqrt");
    registerSetting("supportTowerDiameter");
    registerSetting("supportTowerRoofAngle");

    registerSetting("avoidOverlappingPerimeters");

    registerSetting("preSwitchExtruderCode");
    registerSetting("postSwitchExtruderCode");
    registerSetting("filamentDiameter");
    registerSetting("fanFullOnLayerNr");
    registerSetting("extruderOffset[1].X");
    registerSetting("extruderOffset[1].Y");
    registerSetting("layerThickness");
    registerSetting("initialLayerThickness");
    registerSetting("endCode");
    registerSetting("skirtLineCount");
    registerSetting("supportBottomStairDistance");
    registerSetting("minimalExtrusionBeforeRetraction");
    registerSetting("retractionMinimalDistance");
    registerSetting("skirtMinLength");
    registerSetting("retractionAmount");
    registerSetting("skirtLineCount");
    registerSetting("startCode");
    registerSetting("skirtDistance");
    registerSetting("extruderOffset[2].Y");
    registerSetting("extruderOffset[2].X");
    registerSetting("layer0extrusionWidth");
    registerSetting("moveSpeed");
    registerSetting("skinSpeed");
    registerSetting("supportLineDistance");
    registerSetting("retractionAmountExtruderSwitch");
    registerSetting("sparseInfillLineDistance");
    registerSetting("insetCount");
    registerSetting("downSkinCount");
    registerSetting("multiVolumeOverlap");
    registerSetting("position.X");
    registerSetting("position.Y");
    registerSetting("position.Z");
    registerSetting("retractionPrimeAmount");
    registerSetting("retractionPrimeSpeed");
    registerSetting("skirtSpeed");
    registerSetting("extruderNr");
    registerSetting("sparseInfillCombineCount");
    registerSetting("retractionExtruderSwitchPrimeSpeed");
    registerSetting("retractionExtruderSwitchSpeed");
    registerSetting("infillPattern");
    registerSetting("skinPattern");
    registerSetting("wipeTowerSize");

    for(int n=0; n<MAX_EXTRUDERS; n++)
    {
        std::ostringstream stream;
        stream << "extruderOffset" << n;
        registerSetting(stream.str() + ".X");
        registerSetting(stream.str() + ".Y");
    }
}

void SettingsBase::setDefaultSettings()
{
//     setSetting("simpleMode", "0");
//     setSetting("spiralizeMode", "0");
//     setSetting("enableOozeShield", "0");
//     setSetting("wipeTowerSize", "0");
//     setSetting("extruderNr", "0");
//
//

//     setSetting("", "");
//     setSetting("", "");
//     setSetting("", "");
/*
    setSetting("layerThickness", "150");
    setSetting("initialLayerThickness", "300");
    setSetting("filamentDiameter", "2890");
    setSetting("filamentFlow", "100");
    setSetting("layer0extrusionWidth", "600");
    setSetting("extrusionWidth", "400");
    setSetting("insetCount", "2");
    setSetting("downSkinCount", "6");
    setSetting("upSkinCount", "6");
    setSetting("skinPattern", "LINES");
    setSetting("skirtDistance", "6000");
    setSetting("skirtLineCount", "1");
    setSetting("skirtMinLength", "0");

    setSetting("initialSpeedupLayers", "4");
    setSetting("initialLayerSpeed", "20");
    setSetting("skirtSpeed", "50");
    setSetting("inset0Speed", "50");
    setSetting("insetXSpeed", "50");
    setSetting("skinSpeed", "50");
    setSetting("moveSpeed", "150");
    setSetting("fanFullOnLayerNr", "2");

    setSetting("sparseInfillLineDistance", "500");
    setSetting("sparseInfillCombineCount", "1");
    setSetting("infillOverlap", "15");
    setSetting("infillSpeed", "50");
    setSetting("infillPattern", "INFILL_GRID");

    setSetting("supportType", "LINES");
    setSetting("supportAngle", "60");
    //setSetting("supportAngle", "-1");
    setSetting("supportEverywhere", "0");
    setSetting("supportLineDistance", "2667");
    setSetting("supportXYDistance", "500");
    setSetting("supportZDistance", "100");
    setSetting("supportExtruder", "-1");

    setSetting("areaSupportPolyGenerator", "1"); // TK
    setSetting("supportZDistanceBottom", "100");
    setSetting("supportZDistanceTop", "100");
    setSetting("supportJoinDistance", "1000"); // distance between support blocks which will get merged
    setSetting("supportBridgeBack", "100"); // percentage of bridge between layer and overhang which should be supported
    setSetting("supportBottomStairDistance", "100"); // height of the steps with which the lines support rests on the model

    setSetting("extruderOffset1.X", "18000");
    setSetting("extruderOffset1.Y", "0");

    setSetting("retractionAmount", "4500");
    setSetting("retractionPrimeAmount", "0");
    setSetting("retractionSpeed", "25");
    setSetting("retractionPrimeSpeed", "25");
    setSetting("retractionAmountExtruderSwitch", "14500");
    setSetting("retractionExtruderSwitchSpeed", "25");
    setSetting("retractionExtruderSwitchPrimeSpeed", "25");
    setSetting("retractionMinimalDistance", "1500");
    setSetting("minimalExtrusionBeforeRetraction", "100");
    setSetting("retractionZHop", "0");

    setSetting("enableCombing", "1");
    setSetting("enableOozeShield", "0");
    setSetting("wipeTowerSize", "0");
    setSetting("multiVolumeOverlap", "0");
    setSetting("position.X", "115000"); // UM2
    setSetting("position.Y", "112500");
    setSetting("position.Z", "0");
    setSetting("autoCenter", "1");
    setSetting("extruderNr", "0");

    setSetting("raftMargin", "5000");
    setSetting("raftLineSpacing", "1000");
    setSetting("raftBaseThickness", "0");
    setSetting("raftBaseLinewidth", "0");
    setSetting("raftInterfaceThickness", "0");
    setSetting("raftInterfaceLinewidth", "0");
    setSetting("raftInterfaceLineSpacing", "0");
    setSetting("raftAirGap", "0");
    setSetting("raftAirGapLayer0", "0");
    setSetting("raftBaseSpeed", "15");
    setSetting("raftInterfaceSpeed", "15");
    setSetting("raftFanSpeed", "0");
    setSetting("raftSurfaceThickness", "0");
    setSetting("raftSurfaceLinewidth", "0");
    setSetting("raftSurfaceLineSpacing", "0");
    setSetting("raftSurfaceLayers", "0");
    setSetting("raftSurfaceSpeed", "0");

    setSetting("minimalLayerTime", "5");
    setSetting("minimalFeedrate", "10");
    setSetting("coolHeadLift", "0");
    setSetting("fanSpeedMin", "100");
    setSetting("fanSpeedMax", "100");

    setSetting("spiralizeMode", "0");
    setSetting("simpleMode", "0");
    setSetting("gcodeFlavor", "GCODE_FLAVOR_REPRAP");

    for(int n=0; n<MAX_EXTRUDERS; n++)
    {
        std::ostringstream stream;
        stream << "extruderOffset" << n;
        setSetting(stream.str() + ".X", "0");
        setSetting(stream.str() + ".Y", "0");
    }

    setSetting("startCode",
        "M109 S210     ;Heatup to 210C\n"
        "G21           ;metric values\n"
        "G90           ;absolute positioning\n"
        "G28           ;Home\n"
        "G1 Z15.0 F300 ;move the platform down 15mm\n"
        "G92 E0        ;zero the extruded length\n"
        "G1 F200 E5    ;extrude 5mm of feed stock\n"
        "G92 E0        ;zero the extruded length again\n");
    setSetting("endCode",
        "M104 S0                     ;extruder heater off\n"
        "M140 S0                     ;heated bed heater off (if you have it)\n"
        "G91                            ;relative positioning\n"
        "G1 E-1 F300                    ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n"
        "G1 Z+0.5 E-5 X-20 Y-20 F9000   ;move Z up a bit and retract filament even more\n"
        "G28 X0 Y0                      ;move X/Y to min endstops, so the head is out of the way\n"
        "M84                         ;steppers off\n"
        "G90                         ;absolute positioning\n");
    setSetting("postSwitchExtruderCode", "");
    setSetting("preSwitchExtruderCode", "");
    */
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <cstring>
#include <string>
#include <vector>
#include <iomanip>
#include <cmath>
#include <list>
#include <bitset>

using namespace std;

#define ll long long
#define lson l,mid,id<<1
#define rson mid+1,r,id<<1|1

typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
typedef pair<double, double>pdd;

const double eps = 1e-6;
const ll  LINF = 0x3f3f3f3f3f3f3f3fLL;
const int INF = 0x3f3f3f3f;
const double FINF = 1e18;

#define x first
#define y second

#define REP(i,j,k) for(int i =(j);i<=(k);i++)
#define REPD(i,j,k) for(int i =(j);i>=(k);i--)
#define print(x) cout<<(x)<<endl;
#define IOS ios::sync_with_stdio(0);cin.tie(0);

char a[300005],b[100005];

void Init(){
	cin>>b;

	return ;
}

void Solve(){
	int lena;
	lena =strlen(a);

	REP(i,0,lena-1){
		a[lena+i]=a[i];
	}
	a[lena*2]=0;

	cout<<search(a,a+2*lena,b,b+strlen(b))<<endl;

	return ;
}

int main(){
#ifdef LOCAL
	freopen("hdu2203.in","r",stdin);
#endif

	while(cin>>a)
	Init(),Solve();
	return 0;
}<commit_msg>update hdu2203<commit_after>#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <stack>
#include <cstring>
#include <string>
#include <vector>
#include <iomanip>
#include <cmath>
#include <list>
#include <bitset>

using namespace std;

#define ll long long
#define lson l,mid,id<<1
#define rson mid+1,r,id<<1|1

typedef pair<int, int>pii;
typedef pair<ll, ll>pll;
typedef pair<double, double>pdd;

const double eps = 1e-6;
const ll  LINF = 0x3f3f3f3f3f3f3f3fLL;
const int INF = 0x3f3f3f3f;
const double FINF = 1e18;

#define x first
#define y second

#define REP(i,j,k) for(int i =(j);i<=(k);i++)
#define REPD(i,j,k) for(int i =(j);i>=(k);i--)
#define print(x) cout<<(x)<<endl;
#define IOS ios::sync_with_stdio(0);cin.tie(0);

char a[300005],b[100005];

void Init(){
	cin>>b;

	return ;
}

void Solve(){
	int lena;
	lena =strlen(a);

	REP(i,0,lena-1){
		a[lena+i]=a[i];
	}
	a[lena*2]=0;

	cout<<search(a,a+2*lena,b,b+strlen(b))-a<<endl;

	return ;
}

int main(){
#ifdef LOCAL
	freopen("hdu2203.in","r",stdin);
#endif

	while(cin>>a)
	Init(),Solve();
	return 0;
}<|endoftext|>


<commit_before>/**
 * @cond ___LICENSE___
 *
 * Copyright (c) 2016 Koen Visscher, Paul Visscher and individual contributors.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @endcond
 */

#include "common/environment.h"
#include "common/directory.h"
#include "common/path.h"

#include "preproc/env.h"

#include "api/console.h"

#include "config.h"

#if OS_IS_WINDOWS
#   include <windows.h>
#elif OS_IS_LINUX
#   include <unistd.h>
#elif OS_IS_MACOS
#   include <mach-o/dyld.h>
#endif

namespace Path
{
    std::string Get( const std::string &path, Type type /*= Type::Game */ ) noexcept
    {
        std::string from;
        bool resolve = true;

        switch ( type )
        {
        case Path::Type::Program:
            from = Path::GetProgramDirectory();
            break;

        case Path::Type::Data:
            from = Path::GetProgramDataDirectory();
            break;

        case Path::Type::SharedData:
            from = Path::GetProgramSharedDataDirectory();
            break;

        case Path::Type::Temp:
            from = Path::GetProgramTempDirectory();
            break;

        case Path::Type::Editor:
            from = Path::GetProgramDirectory();
            break;

        case Path::Type::None:
            resolve = false;
            break;
        }

        return resolve ? Path::ResolveRelative( from, path ) : path;
    }

    std::string ResolveRelative( const std::string &cfrom, const std::string &cto, bool sameRoot /*= true */ ) noexcept
    {
        std::string from = cfrom;
        std::string to = cto;
#if !(OS_IS_WINDOWS)
        from = String::Replace( cfrom, "\\", "/" );
        to = String::Replace( cto, "\\", "/" );
#endif

        if ( sameRoot )
        {
            // Just add the relative path to the from path an normalise :)
            return Canonical( FixStyle( boost::filesystem::path( from ).parent_path().generic_string() ) + to );
        }
        else
        {
            // Cheers - http://stackoverflow.com/questions/10167382/boostfilesystem-get-relative-path

            boost::filesystem::path fsFrom, fsTo, result;

            fsFrom  = boost::filesystem::absolute( from ).parent_path();
            fsTo    = boost::filesystem::absolute( to );

            boost::filesystem::path::const_iterator itrFrom( fsFrom.begin() ), itrTo( fsTo.begin() );

            // Find common base
            /// @todo itrTo != toEnd always true
            for ( boost::filesystem::path::const_iterator toEnd( fsTo.end() ), fromEnd( fsFrom.end() ) ;
                    itrTo != toEnd && itrFrom != fromEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo );

            // Navigate backwards in directory to reach previously found base
            for ( boost::filesystem::path::const_iterator fromEnd( fsFrom.end() ); itrFrom != fromEnd; ++itrFrom )
            {
                if ( ( *itrFrom ) != "." )
                {
                    result /= "..";
                }
            }

            // Now navigate down the directory branch
            for ( ; itrTo != fsTo.end() ; ++itrTo )
            {
                result /= *itrTo;
            }

            return Canonical( result.generic_string() );
        }
    }

    std::string FixStyle( const std::string &filePath ) noexcept
    {
        const boost::filesystem::path path( filePath );
        std::string newPath = boost::filesystem::absolute(path).generic_string();

        if ( !path.has_extension() )
        {
            if ( path.empty() || newPath.back() != '/' )
            {
                newPath += '/';
            }
        }

#if !(OS_IS_WINDOWS)
        newPath = String::Replace( newPath, "\\", "/" );
        newPath = String::Replace( newPath, "//", "/" );
#endif
        return newPath;
    }

    std::string Canonical( const std::string &opath, bool absolute /*= false */ ) noexcept
    {
        std::string path = opath;
#if !(OS_IS_WINDOWS)
        path = String::Replace( path, "\\", "/" );
#endif

        if ( ( path == "." || path == "./" ) && !absolute )
        {
            return path;
        }

        // Again Cheers - http://stackoverflow.com/questions/1746136/how-do-i-normalize-a-pathname-using-boostfilesystem
        boost::filesystem::path fsPath( path );

        if ( absolute )
        {
            fsPath = boost::filesystem::absolute( fsPath );
        }

        boost::filesystem::path result;

        for ( auto it = fsPath.begin(), end = fsPath.end(); it != end; ++it )
        {
            const std::string part = it->generic_string();

            if ( part == ".." )
            {
                if ( result.filename() == ".." )
                {
                    result /= *it;
                }
                else
                {
                    if ( result != "" )
                    {
                        result = result.parent_path();
                    }
                    else
                    {
                        result /= "..";
                    }
                }
            }
            else if ( part == "." )
            {
                // Ignore
            }
            else
            {
                // Just cat other path entries
                result /= *it;
            }
        }

        return FixStyle( result.generic_string() );
    }

    bool IsParent( const std::string &from, const std::string &to ) noexcept
    {
        const std::string canFrom = Canonical( from, true );
        const std::string canTo = Canonical( to, true );
        const std::string relative = Canonical( canFrom + ResolveRelative( canFrom, canTo, false ), true );

        return relative.find( canFrom ) == 0;
    }

    std::string GetFileName( const std::string &path, const bool stripExtension /*= false */ ) noexcept
    {
        const boost::filesystem::path fsPath( FixStyle( path ) );
        std::string filename;

        if ( !stripExtension )
        {
            filename = fsPath.filename().generic_string();
        }
        else
        {
            filename = fsPath.stem().generic_string();
        }

        return filename;
    }

    std::string GetDirectory( const std::string &path ) noexcept
    {
        return FixStyle( boost::filesystem::path( path ).parent_path().generic_string() );
    }

    std::string GetExtension( const std::string &filepath, const bool addDot /*= false */ ) noexcept
    {
        const std::string fullExtension = boost::filesystem::path( filepath ).extension().generic_string();

        return addDot || fullExtension == "" ? fullExtension : fullExtension.substr( 1 );
    }

    bool HasExtension( const std::string &filepath ) noexcept
    {
        return boost::filesystem::path( filepath ).has_extension();
    }

    std::string GetUniqueFileName( const std::string &extension /*= ".tmp" */ ) noexcept
    {
        return FixStyle( boost::filesystem::unique_path( "%%%%-%%%%-%%%%-%%%%" + extension ).generic_string() );
    }

    std::string GetUniqueDirectory() noexcept
    {
        return FixStyle( boost::filesystem::unique_path( "%%%%-%%%%-%%%%" ).generic_string() );
    }

    std::string GetTempDirectory() noexcept
    {
        return FixStyle( boost::filesystem::temp_directory_path().generic_string() );
    }

    std::string GetExeDirectory() noexcept
    {
        return FixStyle( boost::filesystem::path( GetExeFile() ).parent_path().generic_string() );
    }

    std::string GetExeFile() noexcept
    {
#if OS_IS_WINDOWS
        char result[ MAX_PATH ];
        return Canonical( std::string( result, GetModuleFileNameA( nullptr, result, MAX_PATH ) ) );
#elif OS_IS_LINUX
        char result[ PATH_MAX ];
        size_t count = readlink( "/proc/self/exe", result, PATH_MAX );
        return std::string( result, ( count > 0 ) ? count : 0 );
#elif OS_IS_MACOS
        char result[ PATH_MAX ];
        unsigned int count = 0;
        unsigned int buffl = PATH_MAX;
        // fetch the required buffer size
        _NSGetExecutablePath( result, &count );
        _NSGetExecutablePath( result, &buffl );

        return std::string( result, ( count <= PATH_MAX ) ? count : 0 );
#endif
    }

    std::string GetDataDirectory() noexcept
    {
#if OS_IS_WINDOWS
        return FixStyle( Environment::Get( "APPDATA" ) );
#elif OS_IS_LINUX
        const boost::filesystem::path path( Environment::Get("HOME") );

        return FixStyle( String::Format( "%s/local/share/", path.generic_string() ) );
#elif OS_IS_MACOS
        const boost::filesystem::path path( Environment::Get("HOME") );

        return FixStyle( String::Format( "%s/Library/Application Support/", path.generic_string() ) );
#endif
    }

    std::string GetSharedDataDirectory() noexcept
    {
#if OS_IS_WINDOWS
        return FixStyle( Environment::Get( "ALLUSERSPROFILE" ) );
#elif OS_IS_LINUX
        return "/usr/local/";
#elif OS_IS_MACOS
        return "/usr/local/";
#endif
    }

    std::string GetProgramDirectory() noexcept
    {
        return GetExeDirectory();
    }

    std::string GetProgramTempDirectory() noexcept
    {
        return String::Format( "%s%s/%s/", GetTempDirectory(), std::string( PROGRAM_COMPANY ), std::string( PROGRAM_NAME ) );
    }

    std::string GetProgramDataDirectory() noexcept
    {
        return String::Format( "%s%s/%s/", GetDataDirectory(), std::string( PROGRAM_COMPANY ), std::string( PROGRAM_NAME ) );
    }

    std::string GetProgramSharedDataDirectory() noexcept
    {
        return String::Format( "%s%s/%s/", GetSharedDataDirectory(),
                               std::string( PROGRAM_COMPANY ),
                               std::string( PROGRAM_NAME ) );
    }

    std::vector< boost::filesystem::path > List( const std::string &directory, bool recursive /*= false */ ) noexcept
    {
        std::vector< boost::filesystem::path > contents;

        if ( !Directory::Exists( directory ) )
        {
            return contents;
        }

        if ( recursive )
        {
            boost::filesystem::recursive_directory_iterator it( directory ), end;

            for ( ; it != end; ++it )
            {
                contents.push_back( *it );
            }
        }
        else
        {
            boost::filesystem::directory_iterator it( directory ), end;

            for ( ; it != end; ++it )
            {
                contents.push_back( *it );
            }
        }

        return contents;
    }

    std::vector< std::string > ListContent( const std::string &directory, bool recursive /*= false */ ) noexcept
    {
        const std::vector< boost::filesystem::path > contents = List( directory, recursive );
        std::vector< std::string > result;
        result.reserve( contents.size() );

        for ( auto it = contents.begin(), end = contents.end(); it != end; ++it )
        {
            result.push_back( FixStyle( it->generic_string() ) );
        }

        return result;
    }

    std::string GetWorkingDirectory() noexcept
    {
        return Path::FixStyle( boost::filesystem::current_path().generic_string() );
    }

    bool SetWorkingDirectory( const std::string &workingDirectory ) noexcept
    {
        bool success = true;

        try
        {
            boost::filesystem::current_path( workingDirectory );
        }
        catch ( boost::filesystem::filesystem_error & )
        {
            success = false;
        }

        return success;
    }

    void DeleteAll( const std::string &path ) noexcept
    {
        boost::filesystem::remove_all( path );
    }

}<commit_msg>Cannonical fix<commit_after>/**
 * @cond ___LICENSE___
 *
 * Copyright (c) 2016 Koen Visscher, Paul Visscher and individual contributors.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @endcond
 */

#include "common/environment.h"
#include "common/directory.h"
#include "common/path.h"

#include "preproc/env.h"

#include "api/console.h"

#include "config.h"

#if OS_IS_WINDOWS
#   include <windows.h>
#elif OS_IS_LINUX
#   include <unistd.h>
#elif OS_IS_MACOS
#   include <mach-o/dyld.h>
#endif

namespace Path
{
    std::string Get( const std::string &path, Type type /*= Type::Game */ ) noexcept
    {
        std::string from;
        bool resolve = true;

        switch ( type )
        {
        case Path::Type::Program:
            from = Path::GetProgramDirectory();
            break;

        case Path::Type::Data:
            from = Path::GetProgramDataDirectory();
            break;

        case Path::Type::SharedData:
            from = Path::GetProgramSharedDataDirectory();
            break;

        case Path::Type::Temp:
            from = Path::GetProgramTempDirectory();
            break;

        case Path::Type::Editor:
            from = Path::GetProgramDirectory();
            break;

        case Path::Type::None:
            resolve = false;
            break;
        }

        return resolve ? Path::ResolveRelative( from, path ) : path;
    }

    std::string ResolveRelative( const std::string &cfrom, const std::string &cto, bool sameRoot /*= true */ ) noexcept
    {
        std::string from = cfrom;
        std::string to = cto;
#if !(OS_IS_WINDOWS)
        from = String::Replace( cfrom, "\\", "/" );
        to = String::Replace( cto, "\\", "/" );
#endif

        if ( sameRoot )
        {
            // Just add the relative path to the from path an normalise :)
            return Canonical( FixStyle( boost::filesystem::path( from ).parent_path().generic_string() ) + to );
        }
        else
        {
            // Cheers - http://stackoverflow.com/questions/10167382/boostfilesystem-get-relative-path

            boost::filesystem::path fsFrom, fsTo, result;

            fsFrom  = boost::filesystem::absolute( from ).parent_path();
            fsTo    = boost::filesystem::absolute( to );

            boost::filesystem::path::const_iterator itrFrom( fsFrom.begin() ), itrTo( fsTo.begin() );

            // Find common base
            /// @todo itrTo != toEnd always true
            for ( boost::filesystem::path::const_iterator toEnd( fsTo.end() ), fromEnd( fsFrom.end() ) ;
                    itrTo != toEnd && itrFrom != fromEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo );

            // Navigate backwards in directory to reach previously found base
            for ( boost::filesystem::path::const_iterator fromEnd( fsFrom.end() ); itrFrom != fromEnd; ++itrFrom )
            {
                if ( ( *itrFrom ) != "." )
                {
                    result /= "..";
                }
            }

            // Now navigate down the directory branch
            for ( ; itrTo != fsTo.end() ; ++itrTo )
            {
                result /= *itrTo;
            }

            return Canonical( result.generic_string() );
        }
    }

    std::string FixStyle( const std::string &filePath ) noexcept
    {
        const boost::filesystem::path path( filePath );
        std::string newPath = path.generic_string();

        if ( !path.has_extension() )
        {
            if ( path.empty() || newPath.back() != '/' )
            {
                newPath += '/';
            }
        }

#if !(OS_IS_WINDOWS)
        newPath = String::Replace( newPath, "\\", "/" );
        newPath = String::Replace( newPath, "//", "/" );
#endif
        return newPath;
    }

    std::string Canonical( const std::string &opath, bool absolute /*= false */ ) noexcept
    {
        std::string path = opath;
#if !(OS_IS_WINDOWS)
        path = String::Replace( path, "\\", "/" );
#endif

        if ( ( path == "." || path == "./" ) && !absolute )
        {
            return path;
        }

        // Again Cheers - http://stackoverflow.com/questions/1746136/how-do-i-normalize-a-pathname-using-boostfilesystem
        boost::filesystem::path fsPath( path );

        if ( absolute )
        {
            fsPath = boost::filesystem::absolute( fsPath );
        }

        boost::filesystem::path result;

        for ( auto it = fsPath.begin(), end = fsPath.end(); it != end; ++it )
        {
            const std::string part = it->generic_string();

            if ( part == ".." )
            {
                if ( result.filename() == ".." )
                {
                    result /= *it;
                }
                else
                {
                    if ( result != "" )
                    {
                        result = result.parent_path();
                    }
                    else
                    {
                        result /= "..";
                    }
                }
            }
            else if ( part == "." )
            {
                // Ignore
            }
            else
            {
                // Just cat other path entries
                result /= *it;
            }
        }

        return FixStyle( result.generic_string() );
    }

    bool IsParent( const std::string &from, const std::string &to ) noexcept
    {
        const std::string canFrom = Canonical( from, true );
        const std::string canTo = Canonical( to, true );
        const std::string relative = Canonical( canFrom + ResolveRelative( canFrom, canTo, false ), true );

        return relative.find( canFrom ) == 0;
    }

    std::string GetFileName( const std::string &path, const bool stripExtension /*= false */ ) noexcept
    {
        const boost::filesystem::path fsPath( FixStyle( path ) );
        std::string filename;

        if ( !stripExtension )
        {
            filename = fsPath.filename().generic_string();
        }
        else
        {
            filename = fsPath.stem().generic_string();
        }

        return filename;
    }

    std::string GetDirectory( const std::string &path ) noexcept
    {
        return FixStyle( boost::filesystem::path( path ).parent_path().generic_string() );
    }

    std::string GetExtension( const std::string &filepath, const bool addDot /*= false */ ) noexcept
    {
        const std::string fullExtension = boost::filesystem::path( filepath ).extension().generic_string();

        return addDot || fullExtension == "" ? fullExtension : fullExtension.substr( 1 );
    }

    bool HasExtension( const std::string &filepath ) noexcept
    {
        return boost::filesystem::path( filepath ).has_extension();
    }

    std::string GetUniqueFileName( const std::string &extension /*= ".tmp" */ ) noexcept
    {
        return FixStyle( boost::filesystem::unique_path( "%%%%-%%%%-%%%%-%%%%" + extension ).generic_string() );
    }

    std::string GetUniqueDirectory() noexcept
    {
        return FixStyle( boost::filesystem::unique_path( "%%%%-%%%%-%%%%" ).generic_string() );
    }

    std::string GetTempDirectory() noexcept
    {
        return FixStyle( boost::filesystem::temp_directory_path().generic_string() );
    }

    std::string GetExeDirectory() noexcept
    {
        return FixStyle( boost::filesystem::path( GetExeFile() ).parent_path().generic_string() );
    }

    std::string GetExeFile() noexcept
    {
#if OS_IS_WINDOWS
        char result[ MAX_PATH ];
        return Canonical( std::string( result, GetModuleFileNameA( nullptr, result, MAX_PATH ) ) );
#elif OS_IS_LINUX
        char result[ PATH_MAX ];
        size_t count = readlink( "/proc/self/exe", result, PATH_MAX );
        return std::string( result, ( count > 0 ) ? count : 0 );
#elif OS_IS_MACOS
        char result[ PATH_MAX ];
        unsigned int count = 0;
        unsigned int buffl = PATH_MAX;
        // fetch the required buffer size
        _NSGetExecutablePath( result, &count );
        _NSGetExecutablePath( result, &buffl );

        return std::string( result, ( count <= PATH_MAX ) ? count : 0 );
#endif
    }

    std::string GetDataDirectory() noexcept
    {
#if OS_IS_WINDOWS
        return Canonical( Environment::Get( "APPDATA" ) );
#elif OS_IS_LINUX
        const boost::filesystem::path path( Environment::Get( "HOME" ) );

        return FixStyle( String::Format( "%s/local/share/", path.generic_string() ) );
#elif OS_IS_MACOS
        const boost::filesystem::path path( Environment::Get( "HOME" ) );

        return FixStyle( String::Format( "%s/Library/Application Support/", path.generic_string() ) );
#endif
    }

    std::string GetSharedDataDirectory() noexcept
    {
#if OS_IS_WINDOWS
        return Canonical( Environment::Get( "ALLUSERSPROFILE" ) );
#elif OS_IS_LINUX
        return "/usr/local/";
#elif OS_IS_MACOS
        return "/usr/local/";
#endif
    }

    std::string GetProgramDirectory() noexcept
    {
        return GetExeDirectory();
    }

    std::string GetProgramTempDirectory() noexcept
    {
        return String::Format( "%s%s/%s/", GetTempDirectory(), std::string( PROGRAM_COMPANY ), std::string( PROGRAM_NAME ) );
    }

    std::string GetProgramDataDirectory() noexcept
    {
        return String::Format( "%s%s/%s/", GetDataDirectory(), std::string( PROGRAM_COMPANY ), std::string( PROGRAM_NAME ) );
    }

    std::string GetProgramSharedDataDirectory() noexcept
    {
        return String::Format( "%s%s/%s/", GetSharedDataDirectory(),
                               std::string( PROGRAM_COMPANY ),
                               std::string( PROGRAM_NAME ) );
    }

    std::vector< boost::filesystem::path > List( const std::string &directory, bool recursive /*= false */ ) noexcept
    {
        std::vector< boost::filesystem::path > contents;

        if ( !Directory::Exists( directory ) )
        {
            return contents;
        }

        if ( recursive )
        {
            boost::filesystem::recursive_directory_iterator it( directory ), end;

            for ( ; it != end; ++it )
            {
                contents.push_back( *it );
            }
        }
        else
        {
            boost::filesystem::directory_iterator it( directory ), end;

            for ( ; it != end; ++it )
            {
                contents.push_back( *it );
            }
        }

        return contents;
    }

    std::vector< std::string > ListContent( const std::string &directory, bool recursive /*= false */ ) noexcept
    {
        const std::vector< boost::filesystem::path > contents = List( directory, recursive );
        std::vector< std::string > result;
        result.reserve( contents.size() );

        for ( auto it = contents.begin(), end = contents.end(); it != end; ++it )
        {
            result.push_back( FixStyle( it->generic_string() ) );
        }

        return result;
    }

    std::string GetWorkingDirectory() noexcept
    {
        return Path::FixStyle( boost::filesystem::current_path().generic_string() );
    }

    bool SetWorkingDirectory( const std::string &workingDirectory ) noexcept
    {
        bool success = true;

        try
        {
            boost::filesystem::current_path( workingDirectory );
        }
        catch ( boost::filesystem::filesystem_error & )
        {
            success = false;
        }

        return success;
    }

    void DeleteAll( const std::string &path ) noexcept
    {
        boost::filesystem::remove_all( path );
    }

}<|endoftext|>


<commit_before>#include "all_defines.hpp"
#include "history.hpp"
#include "processes.hpp"
#include "bytecodes.hpp"
#include "reader.hpp"
#include "types.hpp"

void History::entry(void) {
	if(known_type<Closure>(stack[0])->kontinuation) {
		/*called a continuation: remove tail calls using this continuation*/
		known_type<Closure>(stack[0])->kontinuation->clear();
	} else {
		/*called an ordinary function: add to tail calls on current continuation*/
		if(stack.size() < 2) return;

		Closure* pkclos = maybe_type<Closure>(stack[1]);
		if(!pkclos) return;

		Closure& kclos = *pkclos;
		if(!kclos.kontinuation) return;

		InnerRing& inner_ring = *kclos.kontinuation;
		inner_ring.push_front(Item());
		// ?? for some reason, after insertion capacity must be set again
		inner_ring.repeat_set_capacity();

		Item& it = inner_ring.front();
		it.resize(stack.size() - 1);
		it[0] = stack[0];
		/*skip stack[1] in the debug dump*/
		for(size_t i = 1; i < stack.size(); ++i) {
			it[i] = stack[i + 1];
		}
	}
}

// returned list is of type
// ((functon arg1 ... argn) ...)
void History::to_list(Process & proc) {
	ProcessStack & s = proc.stack;
	size_t count = 0; // number of elements in the history
	Closure* pkclos;
	pkclos = maybe_type<Closure>(stack[1]);
	if(pkclos && pkclos->kontinuation) goto outer_loop;
	pkclos = maybe_type<Closure>(stack[0]);
	if(pkclos && pkclos->kontinuation) goto outer_loop;
	goto end_outer_loop;
outer_loop:
	/*go through the kontinuation*/
	{ InnerRing& ring = *pkclos->kontinuation;
		for(InnerRing::iterator it = ring.begin();
				it != ring.end();
				++it) {
			Item& item = *it;
			{ size_t count = 0;
				for(Item::iterator it = item.begin();
						it != item.end();
						++it) {
					proc.stack.push(*it);
					++count;
				}
				proc.stack.push(Object::nil());
				for(; count; --count) {
					bytecode_cons(proc, stack);
				}
			}
			++count;
		}
	}
	/*search for a parent continuation*/
	for(size_t i = 0; i < pkclos->size(); ++i) {
		Closure* npkclos = maybe_type<Closure>((*pkclos)[i]);
		if(npkclos) {
			if(npkclos->kontinuation) {
				pkclos = npkclos;
				goto outer_loop;
			}
		}
	}
end_outer_loop:
	proc.stack.push(Object::nil());
	// build the list
	for (; count; --count) {
		bytecode_cons(proc, proc.stack);
	}
}

void History::InnerRing::traverse_references(GenericTraverser* gt) {
	for(iterator it = begin(); it != end(); ++it) {
		for(Item::iterator vit = it->begin(); vit != it->end(); ++vit) {
			gt->traverse(*vit);
		}
	}
}

<commit_msg>src/history.cpp: corrected creation of history entry<commit_after>#include "all_defines.hpp"
#include "history.hpp"
#include "processes.hpp"
#include "bytecodes.hpp"
#include "reader.hpp"
#include "types.hpp"

void History::entry(void) {
	if(known_type<Closure>(stack[0])->kontinuation) {
		/*called a continuation: remove tail calls using this continuation*/
		known_type<Closure>(stack[0])->kontinuation->clear();
	} else {
		/*called an ordinary function: add to tail calls on current continuation*/
		if(stack.size() < 2) return;

		Closure* pkclos = maybe_type<Closure>(stack[1]);
		if(!pkclos) return;

		Closure& kclos = *pkclos;
		if(!kclos.kontinuation) return;

		InnerRing& inner_ring = *kclos.kontinuation;
		inner_ring.push_front(Item());
		// ?? for some reason, after insertion capacity must be set again
		inner_ring.repeat_set_capacity();

		Item& it = inner_ring.front();
		it.resize(stack.size() - 1, Object::nil());
		it[0] = stack[0];
		/*skip stack[1] in the debug dump*/
		for(size_t i = 1; i < (stack.size() - 1); ++i) {
			it[i] = stack[i + 1];
		}
	}
}

// returned list is of type
// ((functon arg1 ... argn) ...)
void History::to_list(Process & proc) {
	ProcessStack & s = proc.stack;
	size_t count = 0; // number of elements in the history
	Closure* pkclos;
	pkclos = maybe_type<Closure>(stack[1]);
	if(pkclos && pkclos->kontinuation) goto outer_loop;
	pkclos = maybe_type<Closure>(stack[0]);
	if(pkclos && pkclos->kontinuation) goto outer_loop;
	goto end_outer_loop;
outer_loop:
	/*go through the kontinuation*/
	{ InnerRing& ring = *pkclos->kontinuation;
		for(InnerRing::iterator it = ring.begin();
				it != ring.end();
				++it) {
			Item& item = *it;
			{ size_t count = 0;
				for(Item::iterator it = item.begin();
						it != item.end();
						++it) {
					proc.stack.push(*it);
					++count;
				}
				proc.stack.push(Object::nil());
				for(; count; --count) {
					bytecode_cons(proc, stack);
				}
			}
			++count;
		}
	}
	/*search for a parent continuation*/
	for(size_t i = 0; i < pkclos->size(); ++i) {
		Closure* npkclos = maybe_type<Closure>((*pkclos)[i]);
		if(npkclos) {
			if(npkclos->kontinuation) {
				pkclos = npkclos;
				goto outer_loop;
			}
		}
	}
end_outer_loop:
	proc.stack.push(Object::nil());
	// build the list
	for (; count; --count) {
		bytecode_cons(proc, proc.stack);
	}
}

void History::InnerRing::traverse_references(GenericTraverser* gt) {
	for(iterator it = begin(); it != end(); ++it) {
		for(Item::iterator vit = it->begin(); vit != it->end(); ++vit) {
			gt->traverse(*vit);
		}
	}
}

<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/hwaccelrated/iaccelrated.h>
#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/stllike/hash_map.h>
#include <iostream>
#include <vector>

using namespace vespalib;
using vespalib::hwaccelrated::IAccelrated;

class Benchmark {
public:
    virtual ~Benchmark() { }
    virtual void compute(size_t docId) const = 0;
};

void
runBenchmark(size_t count, size_t docs, const Benchmark & benchmark)
{
    for (size_t i(0); i < count; i++) {
        for (size_t docId(0); docId < docs; docId++) {
            benchmark.compute(docId);
        }
    }
}

template <typename T>
class FullBenchmark : public Benchmark
{
public:
    FullBenchmark(size_t numDocs, size_t numValue);
    ~FullBenchmark();
    void compute(size_t docId) const override {
        _dp->dotProduct(&_query[0], &_values[docId * _query.size()], _query.size());
    }
private:
    std::vector<T> _values;
    std::vector<T> _query;
    IAccelrated::UP _dp;
};

template <typename T>
FullBenchmark<T>::FullBenchmark(size_t numDocs, size_t numValues)
    : _values(numDocs*numValues),
      _query(numValues),
      _dp(IAccelrated::getAccelrator())
{
    for (size_t i(0); i < numDocs; i++) {
        for (size_t j(0); j < numValues; j++) {
            _values[i*numValues + j] = j;
        }
    }
    for (size_t j(0); j < numValues; j++) {
        _query[j] = j;
    }
}

template <typename T>
FullBenchmark<T>::~FullBenchmark() { }

class SparseBenchmark : public Benchmark
{
public:
    SparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues);
    ~SparseBenchmark();
protected:
    struct P {
        P(uint32_t key=0, int32_t value=0) :
            _key(key),
            _value(value)
        { }
        uint32_t _key;
        int32_t  _value;
    };
    size_t _numValues;
    std::vector<P> _values;
};

SparseBenchmark::SparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues)
    : _numValues(numValues),
      _values(numDocs*numValues)
{
    for (size_t i(0); i < numDocs; i++) {
        for (size_t j(0); j < numValues; j++) {
            size_t k(numValues < numQueryValues ?  (j*numQueryValues)/numValues : j);
            _values[i*numValues + j] = P(k, k);
        }
    }
}
SparseBenchmark::~SparseBenchmark() { }

class UnorderedSparseBenchmark : public SparseBenchmark
{
private:
    typedef hash_map<uint32_t, int32_t> map;
public:
    UnorderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues);
    ~UnorderedSparseBenchmark();
private:
    void compute(size_t docId) const override {
        int64_t sum(0);
        size_t offset(docId*_numValues);
        const auto e(_query.end());
        for (size_t i(0); i < _numValues; i++) {
            auto it = _query.find(_values[offset + i]._key);
            if (it != e) {
                sum += static_cast<int64_t>(_values[offset + i]._value) * it->second;
            }
        }
    }
    map _query;
};

UnorderedSparseBenchmark::UnorderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues)
    : SparseBenchmark(numDocs, numValues, numQueryValues)
{
    for (size_t j(0); j < numQueryValues; j++) {
        _query[j] = j;
    }
}
UnorderedSparseBenchmark::~UnorderedSparseBenchmark() {}

class OrderedSparseBenchmark : public SparseBenchmark
{
private:
public:
    OrderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues);
    ~OrderedSparseBenchmark();
private:
    void compute(size_t docId) const override {
        int64_t sum(0);
        size_t offset(docId*_numValues);

        for (size_t a(0), b(0); a < _query.size() && b < _numValues; b++) {
            for (; a < _query.size() && (_query[a]._key <= _values[offset + b]._key); a++);
            if (_query[a]._key == _values[offset + b]._key) {
                sum += static_cast<int64_t>(_values[offset + b]._value) * _query[a]._value;
            }
        }
    }
    std::vector<P> _query;
};

OrderedSparseBenchmark::OrderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues)
    : SparseBenchmark(numDocs, numValues, numQueryValues),
      _query(numQueryValues)
{
    for (size_t j(0); j < numQueryValues; j++) {
        size_t k(numValues > numQueryValues ?  j*numValues/numQueryValues : j);
        _query[j] = P(k, k);
    }
}
OrderedSparseBenchmark::~OrderedSparseBenchmark() { }

int main(int argc, char *argv[])
{
    size_t numDocs(1);
    size_t numValues(1000);
    size_t numQueryValues(1000);
    size_t numQueries(1000000);
    string type("full");
    if ( argc > 1) {
        type = argv[1];
    }
    if ( argc > 2) {
        numQueries = strtoul(argv[2], NULL, 0);
    }
    if ( argc > 3) {
        numDocs = strtoul(argv[3], NULL, 0);
    }
    if ( argc > 4) {
        numValues = strtoul(argv[4], NULL, 0);
    }
    if ( argc > 5) {
        numQueryValues = strtoul(argv[5], NULL, 0);
    }

    std::cout << "type = " << type << std::endl;
    std::cout << "numQueries = " << numQueries << std::endl;
    std::cout << "numDocs = " << numDocs << std::endl;
    std::cout << "numValues = " << numValues << std::endl;
    std::cout << "numQueryValues = " << numQueryValues << std::endl;
    if (type == "full") {
        FullBenchmark<int32_t> bm(numDocs, numValues);
        runBenchmark(numQueries, numDocs, bm);
    } else if (type == "sparse-ordered") {
        OrderedSparseBenchmark bm(numDocs, numValues, numQueryValues);
        runBenchmark(numQueries, numDocs, bm);
    } else if (type == "sparse-unordered") {
        UnorderedSparseBenchmark bm(numDocs, numValues, numQueryValues);
        runBenchmark(numQueries, numDocs, bm);
    } else {
        std::cerr << "type '" << type << "' is unknown." << std::endl;
    }

    return 0;
}

<commit_msg>Add support for stride and number of threads.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/vespalib/hwaccelrated/iaccelrated.h>
#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/stllike/hash_map.h>
#include <iostream>
#include <vector>
#include <thread>

using namespace vespalib;
using vespalib::hwaccelrated::IAccelrated;

class Benchmark {
public:
    virtual ~Benchmark() { }
    virtual void compute(size_t docId) const = 0;
};

void
runThread(size_t count, size_t docs, const Benchmark & benchmark, size_t stride)
{
    for (size_t i(0); i < count; i++) {
        for (size_t docId(0); docId < docs; docId++) {
            benchmark.compute((docId*stride)%docs);
        }
    }
}

void
runBenchmark(size_t numThreads, size_t count, size_t docs, const Benchmark & benchmark, size_t stride) {
    std::vector<std::thread> threads;
    threads.reserve(numThreads);
    for (size_t i(0); i < numThreads; i++) {
        threads.emplace_back(runThread, count, docs, benchmark, stride);
    }
    for (auto & thread : threads) {
        thread.join();
    }
}

template <typename T>
class FullBenchmark : public Benchmark
{
public:
    FullBenchmark(size_t numDocs, size_t numValue);
    ~FullBenchmark();
    void compute(size_t docId) const override {
        _dp->dotProduct(&_query[0], &_values[docId * _query.size()], _query.size());
    }
private:
    std::vector<T> _values;
    std::vector<T> _query;
    IAccelrated::UP _dp;
};

template <typename T>
FullBenchmark<T>::FullBenchmark(size_t numDocs, size_t numValues)
    : _values(numDocs*numValues),
      _query(numValues),
      _dp(IAccelrated::getAccelrator())
{
    for (size_t i(0); i < numDocs; i++) {
        for (size_t j(0); j < numValues; j++) {
            _values[i*numValues + j] = j;
        }
    }
    for (size_t j(0); j < numValues; j++) {
        _query[j] = j;
    }
}

template <typename T>
FullBenchmark<T>::~FullBenchmark() = default;

class SparseBenchmark : public Benchmark
{
public:
    SparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues);
    ~SparseBenchmark();
protected:
    struct P {
        P(uint32_t key=0, int32_t value=0) :
            _key(key),
            _value(value)
        { }
        uint32_t _key;
        int32_t  _value;
    };
    size_t _numValues;
    std::vector<P> _values;
};

SparseBenchmark::SparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues)
    : _numValues(numValues),
      _values(numDocs*numValues)
{
    for (size_t i(0); i < numDocs; i++) {
        for (size_t j(0); j < numValues; j++) {
            size_t k(numValues < numQueryValues ?  (j*numQueryValues)/numValues : j);
            _values[i*numValues + j] = P(k, k);
        }
    }
}
SparseBenchmark::~SparseBenchmark() = default;

class UnorderedSparseBenchmark : public SparseBenchmark
{
private:
    typedef hash_map<uint32_t, int32_t> map;
public:
    UnorderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues);
    ~UnorderedSparseBenchmark();
private:
    void compute(size_t docId) const override {
        int64_t sum(0);
        size_t offset(docId*_numValues);
        const auto e(_query.end());
        for (size_t i(0); i < _numValues; i++) {
            auto it = _query.find(_values[offset + i]._key);
            if (it != e) {
                sum += static_cast<int64_t>(_values[offset + i]._value) * it->second;
            }
        }
    }
    map _query;
};

UnorderedSparseBenchmark::UnorderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues)
    : SparseBenchmark(numDocs, numValues, numQueryValues)
{
    for (size_t j(0); j < numQueryValues; j++) {
        _query[j] = j;
    }
}
UnorderedSparseBenchmark::~UnorderedSparseBenchmark() = default;

class OrderedSparseBenchmark : public SparseBenchmark
{
private:
public:
    OrderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues);
    ~OrderedSparseBenchmark();
private:
    void compute(size_t docId) const override {
        int64_t sum(0);
        size_t offset(docId*_numValues);

        for (size_t a(0), b(0); a < _query.size() && b < _numValues; b++) {
            for (; a < _query.size() && (_query[a]._key <= _values[offset + b]._key); a++);
            if (_query[a]._key == _values[offset + b]._key) {
                sum += static_cast<int64_t>(_values[offset + b]._value) * _query[a]._value;
            }
        }
    }
    std::vector<P> _query;
};

OrderedSparseBenchmark::OrderedSparseBenchmark(size_t numDocs, size_t numValues, size_t numQueryValues)
    : SparseBenchmark(numDocs, numValues, numQueryValues),
      _query(numQueryValues)
{
    for (size_t j(0); j < numQueryValues; j++) {
        size_t k(numValues > numQueryValues ?  j*numValues/numQueryValues : j);
        _query[j] = P(k, k);
    }
}
OrderedSparseBenchmark::~OrderedSparseBenchmark() = default;

int main(int argc, char *argv[])
{
    size_t numDocs(1);
    size_t numValues(1000);
    size_t numQueries(1000000);
    size_t stride(1);
    string type("full");
    if ( argc > 1) {
        type = argv[1];
    }
    if ( argc > 2) {
        numQueries = strtoul(argv[2], nullptr, 0);
    }
    if ( argc > 3) {
        numDocs = strtoul(argv[3], nullptr, 0);
    }
    if ( argc > 4) {
        numValues = strtoul(argv[4], nullptr, 0);
    }
    if (argc > 5) {
        stride = strtoul(argv[5], nullptr, 0);
    }
    size_t numQueryValues = ( argc > 6) : numQueryValues = strtoul(argv[6], nullptr, 0) : numValues;
    std::cout << "type = " << type << std::endl;
    std::cout << "numQueries = " << numQueries << std::endl;
    std::cout << "numDocs = " << numDocs << std::endl;
    std::cout << "numValues = " << numValues << std::endl;
    std::cout << "numQueryValues = " << numQueryValues << std::endl;
    std::cout << "stride =" << stride << std::endl;
    if (type == "full") {
        FullBenchmark<int32_t> bm(numDocs, numValues);
        runBenchmark(numQueries, numDocs, bm, stride);
    } else if (type == "sparse-ordered") {
        OrderedSparseBenchmark bm(numDocs, numValues, numQueryValues);
        runBenchmark(numQueries, numDocs, bm, stride);
    } else if (type == "sparse-unordered") {
        UnorderedSparseBenchmark bm(numDocs, numValues, numQueryValues);
        runBenchmark(numQueries, numDocs, bm, stride);
    } else {
        std::cerr << "type '" << type << "' is unknown." << std::endl;
    }

    return 0;
}

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/system_wrappers/interface/atomic32.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"
#include "webrtc/voice_engine/test/auto_test/voe_standard_test.h"

class TestRtpObserver : public webrtc::VoERTPObserver {
 public:
  TestRtpObserver()
      : crit_(voetest::CriticalSectionWrapper::CreateCriticalSection()),
        changed_ssrc_event_(voetest::EventWrapper::Create()) {}
  virtual ~TestRtpObserver() {}
  virtual void OnIncomingCSRCChanged(int channel,
                                     unsigned int CSRC,
                                     bool added) {}
  virtual void OnIncomingSSRCChanged(int channel,
                                     unsigned int SSRC);
  void WaitForChangedSsrc() {
    // 10 seconds should be enough.
    EXPECT_EQ(voetest::kEventSignaled, changed_ssrc_event_->Wait(10*1000));
    changed_ssrc_event_->Reset();
  }
  void SetIncomingSsrc(unsigned int ssrc) {
    voetest::CriticalSectionScoped lock(crit_.get());
    incoming_ssrc_ = ssrc;
  }
 public:
  voetest::scoped_ptr<voetest::CriticalSectionWrapper> crit_;
  unsigned int incoming_ssrc_;
  voetest::scoped_ptr<voetest::EventWrapper> changed_ssrc_event_;
};

void TestRtpObserver::OnIncomingSSRCChanged(int channel,
                                            unsigned int SSRC) {
  char msg[128];
  sprintf(msg, "\n=> OnIncomingSSRCChanged(channel=%d, SSRC=%u)\n", channel,
          SSRC);
  TEST_LOG("%s", msg);

  {
    voetest::CriticalSectionScoped lock(crit_.get());
    if (incoming_ssrc_ == SSRC)
      changed_ssrc_event_->Set();
  }
}

class RtcpAppHandler : public webrtc::VoERTCPObserver {
 public:
  RtcpAppHandler() : length_in_bytes_(0), sub_type_(0), name_(0) {}
  void OnApplicationDataReceived(int channel,
                                 unsigned char sub_type,
                                 unsigned int name,
                                 const unsigned char* data,
                                 unsigned short length_in_bytes);
  void Reset();
  ~RtcpAppHandler() {}
  unsigned short length_in_bytes_;
  unsigned char data_[256];
  unsigned char sub_type_;
  unsigned int name_;
};

static const char* const RTCP_CNAME = "Whatever";

class RtpRtcpTest : public AfterStreamingFixture {
 protected:
  void SetUp() {
    // We need a second channel for this test, so set it up.
    second_channel_ = voe_base_->CreateChannel();
    EXPECT_GE(second_channel_, 0);

    transport_ = new LoopBackTransport(voe_network_);
    EXPECT_EQ(0, voe_network_->RegisterExternalTransport(second_channel_,
                                                         *transport_));

    EXPECT_EQ(0, voe_base_->StartReceive(second_channel_));
    EXPECT_EQ(0, voe_base_->StartPlayout(second_channel_));
    EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(second_channel_, 5678));
    EXPECT_EQ(0, voe_base_->StartSend(second_channel_));

    // We'll set up the RTCP CNAME and SSRC to something arbitrary here.
    voe_rtp_rtcp_->SetRTCP_CNAME(channel_, RTCP_CNAME);
  }

  void TearDown() {
    EXPECT_EQ(0, voe_network_->DeRegisterExternalTransport(second_channel_));
    voe_base_->DeleteChannel(second_channel_);
    delete transport_;
  }

  int second_channel_;
  LoopBackTransport* transport_;
};

void RtcpAppHandler::OnApplicationDataReceived(
    const int /*channel*/, unsigned char sub_type,
    unsigned int name, const unsigned char* data,
    unsigned short length_in_bytes) {
  length_in_bytes_ = length_in_bytes;
  memcpy(data_, &data[0], length_in_bytes);
  sub_type_ = sub_type;
  name_ = name;
}

void RtcpAppHandler::Reset() {
  length_in_bytes_ = 0;
  memset(data_, 0, sizeof(data_));
  sub_type_ = 0;
  name_ = 0;
}

TEST_F(RtpRtcpTest, RemoteRtcpCnameHasPropagatedToRemoteSide) {
  if (!FLAGS_include_timing_dependent_tests) {
    TEST_LOG("Skipping test - running in slow execution environment...\n");
    return;
  }

  // We need to sleep a bit here for the name to propagate. For instance,
  // 200 milliseconds is not enough, so we'll go with one second here.
  Sleep(1000);

  char char_buffer[256];
  voe_rtp_rtcp_->GetRemoteRTCP_CNAME(channel_, char_buffer);
  EXPECT_STREQ(RTCP_CNAME, char_buffer);
}

// Flakily hangs on Linux. code.google.com/p/webrtc/issues/detail?id=2178.
TEST_F(RtpRtcpTest, DISABLED_ON_LINUX(SSRCPropagatesCorrectly)) {
  unsigned int local_ssrc = 1234;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, local_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  Sleep(1000);

  unsigned int ssrc;
  EXPECT_EQ(0, voe_rtp_rtcp_->GetLocalSSRC(channel_, ssrc));
  EXPECT_EQ(local_ssrc, ssrc);

  EXPECT_EQ(0, voe_rtp_rtcp_->GetRemoteSSRC(channel_, ssrc));
  EXPECT_EQ(local_ssrc, ssrc);
}

TEST_F(RtpRtcpTest, RtcpApplicationDefinedPacketsCanBeSentAndReceived) {
  RtcpAppHandler rtcp_app_handler;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTCPObserver(
      channel_, rtcp_app_handler));

  // Send data aligned to 32 bytes.
  const char* data = "application-dependent data------";
  unsigned short data_length = strlen(data);
  unsigned int data_name = 0x41424344;  // 'ABCD' in ascii
  unsigned char data_subtype = 1;

  EXPECT_EQ(0, voe_rtp_rtcp_->SendApplicationDefinedRTCPPacket(
      channel_, data_subtype, data_name, data, data_length));

  // Ensure the RTP-RTCP process gets scheduled.
  Sleep(1000);

  // Ensure we received the data in the callback.
  ASSERT_EQ(data_length, rtcp_app_handler.length_in_bytes_);
  EXPECT_EQ(0, memcmp(data, rtcp_app_handler.data_, data_length));
  EXPECT_EQ(data_name, rtcp_app_handler.name_);
  EXPECT_EQ(data_subtype, rtcp_app_handler.sub_type_);

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTCPObserver(channel_));
}

TEST_F(RtpRtcpTest, DisabledRtcpObserverDoesNotReceiveData) {
  RtcpAppHandler rtcp_app_handler;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTCPObserver(
      channel_, rtcp_app_handler));

  // Put observer in a known state before de-registering.
  rtcp_app_handler.Reset();

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTCPObserver(channel_));

  const char* data = "whatever";
  EXPECT_EQ(0, voe_rtp_rtcp_->SendApplicationDefinedRTCPPacket(
      channel_, 1, 0x41424344, data, strlen(data)));

  // Ensure the RTP-RTCP process gets scheduled.
  Sleep(1000);

  // Ensure we received no data.
  EXPECT_EQ(0u, rtcp_app_handler.name_);
  EXPECT_EQ(0u, rtcp_app_handler.sub_type_);
}

TEST_F(RtpRtcpTest, InsertExtraRTPPacketDealsWithInvalidArguments) {
  const char payload_data[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };

  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      -1, 0, false, payload_data, 8)) <<
          "Should reject: invalid channel.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      channel_, -1, false, payload_data, 8)) <<
          "Should reject: invalid payload type.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      channel_, 128, false, payload_data, 8)) <<
          "Should reject: invalid payload type.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, 99, false, NULL, 8)) <<
            "Should reject: bad pointer.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, 99, false, payload_data, 1500 - 28 + 1)) <<
            "Should reject: invalid size.";
}

TEST_F(RtpRtcpTest, DISABLED_ON_WIN(CanTransmitExtraRtpPacketsWithoutError)) {
  const char payload_data[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };

  for (int i = 0; i < 128; ++i) {
    // Try both with and without the marker bit set
    EXPECT_EQ(0, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, i, false, payload_data, 8));
    EXPECT_EQ(0, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, i, true, payload_data, 8));
  }
}

// TODO(xians, phoglund): Re-enable when issue 372 is resolved.
TEST_F(RtpRtcpTest, DISABLED_CanCreateRtpDumpFilesWithoutError) {
  // Create two RTP dump files (3 seconds long). You can verify these after
  // the test using rtpplay or NetEqRTPplay if you like.
  std::string output_path = webrtc::test::OutputPath();
  std::string incoming_filename = output_path + "dump_in_3sec.rtp";
  std::string outgoing_filename = output_path + "dump_out_3sec.rtp";

  EXPECT_EQ(0, voe_rtp_rtcp_->StartRTPDump(
      channel_, incoming_filename.c_str(), webrtc::kRtpIncoming));
  EXPECT_EQ(0, voe_rtp_rtcp_->StartRTPDump(
      channel_, outgoing_filename.c_str(), webrtc::kRtpOutgoing));

  Sleep(3000);

  EXPECT_EQ(0, voe_rtp_rtcp_->StopRTPDump(channel_, webrtc::kRtpIncoming));
  EXPECT_EQ(0, voe_rtp_rtcp_->StopRTPDump(channel_, webrtc::kRtpOutgoing));
}

TEST_F(RtpRtcpTest, ObserverGetsNotifiedOnSsrcChange) {
  TestRtpObserver rtcp_observer;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTPObserver(
      channel_, rtcp_observer));

  unsigned int new_ssrc = 7777;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  rtcp_observer.SetIncomingSsrc(new_ssrc);
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, new_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  rtcp_observer.WaitForChangedSsrc();

  // Now try another SSRC.
  unsigned int newer_ssrc = 1717;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  rtcp_observer.SetIncomingSsrc(newer_ssrc);
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, newer_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  rtcp_observer.WaitForChangedSsrc();

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTPObserver(channel_));
}
<commit_msg>Disables RtpRtcpTest.CanTransmitExtraRtpPacketsWithoutError as it flakily breaks the waterfall. See http://chromegw.corp.google.com/i/client.webrtc/builders/Linux64%20Release%20%5Blarge%20tests%5D/builds/99/steps/voe_auto_test/logs/stdio the cl triggering it was a no-change (disabled some other broken tests).<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/system_wrappers/interface/atomic32.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/voice_engine/test/auto_test/fixtures/after_streaming_fixture.h"
#include "webrtc/voice_engine/test/auto_test/voe_standard_test.h"

class TestRtpObserver : public webrtc::VoERTPObserver {
 public:
  TestRtpObserver()
      : crit_(voetest::CriticalSectionWrapper::CreateCriticalSection()),
        changed_ssrc_event_(voetest::EventWrapper::Create()) {}
  virtual ~TestRtpObserver() {}
  virtual void OnIncomingCSRCChanged(int channel,
                                     unsigned int CSRC,
                                     bool added) {}
  virtual void OnIncomingSSRCChanged(int channel,
                                     unsigned int SSRC);
  void WaitForChangedSsrc() {
    // 10 seconds should be enough.
    EXPECT_EQ(voetest::kEventSignaled, changed_ssrc_event_->Wait(10*1000));
    changed_ssrc_event_->Reset();
  }
  void SetIncomingSsrc(unsigned int ssrc) {
    voetest::CriticalSectionScoped lock(crit_.get());
    incoming_ssrc_ = ssrc;
  }
 public:
  voetest::scoped_ptr<voetest::CriticalSectionWrapper> crit_;
  unsigned int incoming_ssrc_;
  voetest::scoped_ptr<voetest::EventWrapper> changed_ssrc_event_;
};

void TestRtpObserver::OnIncomingSSRCChanged(int channel,
                                            unsigned int SSRC) {
  char msg[128];
  sprintf(msg, "\n=> OnIncomingSSRCChanged(channel=%d, SSRC=%u)\n", channel,
          SSRC);
  TEST_LOG("%s", msg);

  {
    voetest::CriticalSectionScoped lock(crit_.get());
    if (incoming_ssrc_ == SSRC)
      changed_ssrc_event_->Set();
  }
}

class RtcpAppHandler : public webrtc::VoERTCPObserver {
 public:
  RtcpAppHandler() : length_in_bytes_(0), sub_type_(0), name_(0) {}
  void OnApplicationDataReceived(int channel,
                                 unsigned char sub_type,
                                 unsigned int name,
                                 const unsigned char* data,
                                 unsigned short length_in_bytes);
  void Reset();
  ~RtcpAppHandler() {}
  unsigned short length_in_bytes_;
  unsigned char data_[256];
  unsigned char sub_type_;
  unsigned int name_;
};

static const char* const RTCP_CNAME = "Whatever";

class RtpRtcpTest : public AfterStreamingFixture {
 protected:
  void SetUp() {
    // We need a second channel for this test, so set it up.
    second_channel_ = voe_base_->CreateChannel();
    EXPECT_GE(second_channel_, 0);

    transport_ = new LoopBackTransport(voe_network_);
    EXPECT_EQ(0, voe_network_->RegisterExternalTransport(second_channel_,
                                                         *transport_));

    EXPECT_EQ(0, voe_base_->StartReceive(second_channel_));
    EXPECT_EQ(0, voe_base_->StartPlayout(second_channel_));
    EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(second_channel_, 5678));
    EXPECT_EQ(0, voe_base_->StartSend(second_channel_));

    // We'll set up the RTCP CNAME and SSRC to something arbitrary here.
    voe_rtp_rtcp_->SetRTCP_CNAME(channel_, RTCP_CNAME);
  }

  void TearDown() {
    EXPECT_EQ(0, voe_network_->DeRegisterExternalTransport(second_channel_));
    voe_base_->DeleteChannel(second_channel_);
    delete transport_;
  }

  int second_channel_;
  LoopBackTransport* transport_;
};

void RtcpAppHandler::OnApplicationDataReceived(
    const int /*channel*/, unsigned char sub_type,
    unsigned int name, const unsigned char* data,
    unsigned short length_in_bytes) {
  length_in_bytes_ = length_in_bytes;
  memcpy(data_, &data[0], length_in_bytes);
  sub_type_ = sub_type;
  name_ = name;
}

void RtcpAppHandler::Reset() {
  length_in_bytes_ = 0;
  memset(data_, 0, sizeof(data_));
  sub_type_ = 0;
  name_ = 0;
}

TEST_F(RtpRtcpTest, RemoteRtcpCnameHasPropagatedToRemoteSide) {
  if (!FLAGS_include_timing_dependent_tests) {
    TEST_LOG("Skipping test - running in slow execution environment...\n");
    return;
  }

  // We need to sleep a bit here for the name to propagate. For instance,
  // 200 milliseconds is not enough, so we'll go with one second here.
  Sleep(1000);

  char char_buffer[256];
  voe_rtp_rtcp_->GetRemoteRTCP_CNAME(channel_, char_buffer);
  EXPECT_STREQ(RTCP_CNAME, char_buffer);
}

// Flakily hangs on Linux. code.google.com/p/webrtc/issues/detail?id=2178.
TEST_F(RtpRtcpTest, DISABLED_ON_LINUX(SSRCPropagatesCorrectly)) {
  unsigned int local_ssrc = 1234;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, local_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  Sleep(1000);

  unsigned int ssrc;
  EXPECT_EQ(0, voe_rtp_rtcp_->GetLocalSSRC(channel_, ssrc));
  EXPECT_EQ(local_ssrc, ssrc);

  EXPECT_EQ(0, voe_rtp_rtcp_->GetRemoteSSRC(channel_, ssrc));
  EXPECT_EQ(local_ssrc, ssrc);
}

TEST_F(RtpRtcpTest, RtcpApplicationDefinedPacketsCanBeSentAndReceived) {
  RtcpAppHandler rtcp_app_handler;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTCPObserver(
      channel_, rtcp_app_handler));

  // Send data aligned to 32 bytes.
  const char* data = "application-dependent data------";
  unsigned short data_length = strlen(data);
  unsigned int data_name = 0x41424344;  // 'ABCD' in ascii
  unsigned char data_subtype = 1;

  EXPECT_EQ(0, voe_rtp_rtcp_->SendApplicationDefinedRTCPPacket(
      channel_, data_subtype, data_name, data, data_length));

  // Ensure the RTP-RTCP process gets scheduled.
  Sleep(1000);

  // Ensure we received the data in the callback.
  ASSERT_EQ(data_length, rtcp_app_handler.length_in_bytes_);
  EXPECT_EQ(0, memcmp(data, rtcp_app_handler.data_, data_length));
  EXPECT_EQ(data_name, rtcp_app_handler.name_);
  EXPECT_EQ(data_subtype, rtcp_app_handler.sub_type_);

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTCPObserver(channel_));
}

TEST_F(RtpRtcpTest, DisabledRtcpObserverDoesNotReceiveData) {
  RtcpAppHandler rtcp_app_handler;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTCPObserver(
      channel_, rtcp_app_handler));

  // Put observer in a known state before de-registering.
  rtcp_app_handler.Reset();

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTCPObserver(channel_));

  const char* data = "whatever";
  EXPECT_EQ(0, voe_rtp_rtcp_->SendApplicationDefinedRTCPPacket(
      channel_, 1, 0x41424344, data, strlen(data)));

  // Ensure the RTP-RTCP process gets scheduled.
  Sleep(1000);

  // Ensure we received no data.
  EXPECT_EQ(0u, rtcp_app_handler.name_);
  EXPECT_EQ(0u, rtcp_app_handler.sub_type_);
}

TEST_F(RtpRtcpTest, InsertExtraRTPPacketDealsWithInvalidArguments) {
  const char payload_data[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };

  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      -1, 0, false, payload_data, 8)) <<
          "Should reject: invalid channel.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      channel_, -1, false, payload_data, 8)) <<
          "Should reject: invalid payload type.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
      channel_, 128, false, payload_data, 8)) <<
          "Should reject: invalid payload type.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, 99, false, NULL, 8)) <<
            "Should reject: bad pointer.";
  EXPECT_EQ(-1, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, 99, false, payload_data, 1500 - 28 + 1)) <<
            "Should reject: invalid size.";
}

TEST_F(RtpRtcpTest, DISABLED_CanTransmitExtraRtpPacketsWithoutError) {
  const char payload_data[8] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' };

  for (int i = 0; i < 128; ++i) {
    // Try both with and without the marker bit set
    EXPECT_EQ(0, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, i, false, payload_data, 8));
    EXPECT_EQ(0, voe_rtp_rtcp_->InsertExtraRTPPacket(
        channel_, i, true, payload_data, 8));
  }
}

// TODO(xians, phoglund): Re-enable when issue 372 is resolved.
TEST_F(RtpRtcpTest, DISABLED_CanCreateRtpDumpFilesWithoutError) {
  // Create two RTP dump files (3 seconds long). You can verify these after
  // the test using rtpplay or NetEqRTPplay if you like.
  std::string output_path = webrtc::test::OutputPath();
  std::string incoming_filename = output_path + "dump_in_3sec.rtp";
  std::string outgoing_filename = output_path + "dump_out_3sec.rtp";

  EXPECT_EQ(0, voe_rtp_rtcp_->StartRTPDump(
      channel_, incoming_filename.c_str(), webrtc::kRtpIncoming));
  EXPECT_EQ(0, voe_rtp_rtcp_->StartRTPDump(
      channel_, outgoing_filename.c_str(), webrtc::kRtpOutgoing));

  Sleep(3000);

  EXPECT_EQ(0, voe_rtp_rtcp_->StopRTPDump(channel_, webrtc::kRtpIncoming));
  EXPECT_EQ(0, voe_rtp_rtcp_->StopRTPDump(channel_, webrtc::kRtpOutgoing));
}

TEST_F(RtpRtcpTest, ObserverGetsNotifiedOnSsrcChange) {
  TestRtpObserver rtcp_observer;
  EXPECT_EQ(0, voe_rtp_rtcp_->RegisterRTPObserver(
      channel_, rtcp_observer));

  unsigned int new_ssrc = 7777;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  rtcp_observer.SetIncomingSsrc(new_ssrc);
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, new_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  rtcp_observer.WaitForChangedSsrc();

  // Now try another SSRC.
  unsigned int newer_ssrc = 1717;
  EXPECT_EQ(0, voe_base_->StopSend(channel_));
  rtcp_observer.SetIncomingSsrc(newer_ssrc);
  EXPECT_EQ(0, voe_rtp_rtcp_->SetLocalSSRC(channel_, newer_ssrc));
  EXPECT_EQ(0, voe_base_->StartSend(channel_));

  rtcp_observer.WaitForChangedSsrc();

  EXPECT_EQ(0, voe_rtp_rtcp_->DeRegisterRTPObserver(channel_));
}
<|endoftext|>


<commit_before>#ifndef GNR_DISPATCH_HPP
# define GNR_DISPATCH_HPP
# pragma once

#include <type_traits>

#include <utility>

namespace gnr
{

namespace detail
{

template <typename A, typename ...B>
struct front
{
  using type = A;
};

template <typename ...A>
using front_t = typename front<A...>::type;

}

constexpr decltype(auto) dispatch(auto const i, auto&& ...f)
  noexcept(noexcept((f(), ...)))
  requires(
    std::is_enum_v<std::remove_const_t<decltype(i)>> &&
    std::conjunction_v<
      std::is_same<
        std::decay_t<
          decltype(std::declval<detail::front_t<decltype(f)...>>()())
        >,
        std::decay_t<decltype(std::declval<decltype(f)>()())>
      >...
    >
  )
{
  using int_t = std::underlying_type_t<std::remove_const_t<decltype(i)>>;
  using R = decltype(std::declval<detail::front_t<decltype(f)...>>()());

  return [&]<auto ...I>(std::integer_sequence<int_t, I...>)
    noexcept(noexcept((f(), ...))) -> decltype(auto)
  {
    if constexpr(std::is_void_v<R>)
    {
      ((I == int_t(i) ? (f(), 0) : 0), ...);
    }
    else if constexpr(std::is_array_v<std::remove_reference_t<R>>)
    {
      std::remove_extent_t<std::remove_reference_t<R>>(*r)[];

      (
        (
          I == int_t(i) ?
            r = reinterpret_cast<decltype(r)>(&f()) :
            nullptr
        ),
        ...
      );

      return *r;
    }
    else if constexpr(std::is_reference_v<R>)
    {
      std::remove_reference_t<R>* r;

      ((I == int_t(i) ? r = &f() : nullptr), ...);

      return *r;
    }
    else
    {
      R r;

      ((I == int_t(i) ? (r = f(), 0) : 0), ...);

      return r;
    }
  }(std::make_integer_sequence<int_t, sizeof...(f)>());
}

constexpr decltype(auto) select(auto const i, auto&& ...v) noexcept
  requires(
    std::is_integral_v<std::remove_const_t<decltype(i)>> &&
    std::conjunction_v<
      std::is_same<
        std::decay_t<
          decltype(std::declval<detail::front_t<decltype(v)...>>())
        >,
        std::decay_t<decltype(std::declval<decltype(v)>())>
      >...
    >
  )
{
  using R = detail::front_t<decltype(v)...>;

  return [&]<auto ...I>(std::index_sequence<I...>) noexcept -> decltype(auto)
  {
    if constexpr(std::is_array_v<std::remove_reference_t<R>>)
    {
      std::remove_extent_t<std::remove_reference_t<R>>(*r)[];

      ((I == i ? r = reinterpret_cast<decltype(r)>(&v) : nullptr), ...);

      return *r;
    }
    else
    {
      std::remove_reference_t<R>* r;

      ((I == i ? r = &v : nullptr), ...);

      return *r;
    }
  }(std::make_index_sequence<sizeof...(v)>());
}

}

#endif // GNR_DISPATCH_HPP
<commit_msg>some fixes<commit_after>#ifndef GNR_DISPATCH_HPP
# define GNR_DISPATCH_HPP
# pragma once

#include <type_traits>

#include <utility>

#include "invoke.hpp"

namespace gnr
{

namespace detail
{

template <typename A, typename ...B>
struct front
{
  using type = A;
};

template <typename ...A>
using front_t = typename front<A...>::type;

}

constexpr decltype(auto) dispatch(auto const i, auto&& ...f)
  noexcept(noexcept((f(), ...)))
  requires(
    std::is_enum_v<std::remove_const_t<decltype(i)>> &&
    std::conjunction_v<
      std::is_same<
        std::decay_t<
          decltype(std::declval<detail::front_t<decltype(f)...>>()())
        >,
        std::decay_t<decltype(std::declval<decltype(f)>()())>
      >...
    >
  )
{
  using int_t = std::underlying_type_t<std::remove_const_t<decltype(i)>>;
  using R = decltype(std::declval<detail::front_t<decltype(f)...>>()());

  return [&]<auto ...I>(std::integer_sequence<int_t, I...>)
    noexcept(noexcept((f(), ...))) -> decltype(auto)
  {
    if constexpr(std::is_void_v<R>)
    {
      ((I == int_t(i) ? (f(), 0) : 0), ...);
    }
    else if constexpr(std::is_array_v<std::remove_reference_t<R>>)
    {
      std::remove_extent_t<std::remove_reference_t<R>>(*r)[];

      (
        (
          I == int_t(i) ?
            r = reinterpret_cast<decltype(r)>(&f()) :
            nullptr
        ),
        ...
      );

      return *r;
    }
    else if constexpr(std::is_reference_v<R>)
    {
      std::remove_reference_t<R>* r;

      ((I == int_t(i) ? r = &f() : nullptr), ...);

      return *r;
    }
    else
    {
      R r;

      ((I == int_t(i) ? (r = f(), 0) : 0), ...);

      return r;
    }
  }(std::make_integer_sequence<int_t, sizeof...(f)>());
}

constexpr decltype(auto) select(auto const i, auto&& ...v) noexcept
  requires(
    std::is_integral_v<std::remove_const_t<decltype(i)>> &&
    std::conjunction_v<
      std::is_same<
        std::decay_t<
          decltype(std::declval<detail::front_t<decltype(v)...>>())
        >,
        std::decay_t<decltype(std::declval<decltype(v)>())>
      >...
    >
  )
{
  using R = detail::front_t<decltype(v)...>;

  return [&]<auto ...I>(std::index_sequence<I...>) noexcept -> decltype(auto)
  {
    if constexpr(std::is_array_v<std::remove_reference_t<R>>)
    {
      std::remove_extent_t<std::remove_reference_t<R>>(*r)[];

      ((I == i ? r = reinterpret_cast<decltype(r)>(&v) : nullptr), ...);

      return *r;
    }
    else
    {
      std::remove_reference_t<R>* r;

      ((I == i ? r = &v : nullptr), ...);

      return *r;
    }
  }(std::make_index_sequence<sizeof...(v)>());
}

constexpr decltype(auto) dispatch2(auto const i, auto&& ...a)
  noexcept(noexcept(
      gnr::invoke_split<2>(
        [](auto&& e, auto&& f)
        {
          f();
        },
        std::forward<decltype(a)>(a)...
      )
    )
  )
{
  using tuple_t = std::tuple<decltype(a)...>;
  using R = decltype(std::declval<std::tuple_element_t<1, tuple_t>>()());

  if constexpr(std::is_void_v<R>)
  {
    gnr::invoke_split<2>(
      [&](auto&& e, auto&& f)
      noexcept(noexcept(f())) -> decltype(auto)
      {
        if (e == i)
        {
          f();
        }
      },
      std::forward<decltype(a)>(a)...
    );
  }
  else if constexpr(std::is_array_v<std::remove_reference_t<R>>)
  {
    std::remove_extent_t<std::remove_reference_t<R>>(*r)[];

    gnr::invoke_split<2>(
      [&](auto&& e, auto&& f)
      noexcept(noexcept(f())) -> decltype(auto)
      {
        if (e == i)
        {
          r = reinterpret_cast<decltype(r)>(&f());
        }
      },
      std::forward<decltype(a)>(a)...
    );

    return *r;
  }
  else if constexpr(std::is_reference_v<R>)
  {
    std::remove_reference_t<R>* r;

    gnr::invoke_split<2>(
      [&](auto&& e, auto&& f)
      noexcept(noexcept(f())) -> decltype(auto)
      {
        if (e == i)
        {
          r = &f();
        }
      },
      std::forward<decltype(a)>(a)...
    );

    return *r;
  }
  else
  {
    R r;

    gnr::invoke_split<2>(
      [&](auto&& e, auto&& f)
      noexcept(noexcept(f())) -> decltype(auto)
      {
        if (e == i)
        {
          r = f();
        }
      },
      std::forward<decltype(a)>(a)...
    );

    return r;
  }
}

}

#endif // GNR_DISPATCH_HPP
<|endoftext|>