text:
//===-- serialbox/core/frontend/stella/UnittestUtility.cpp --------------------------*- C++ -*-===//
//
//                                    S E R I A L B O X
//
// This file is distributed under terms of BSD license.
// See LICENSE.txt for more information
//
//===------------------------------------------------------------------------------------------===//
//
/// \file
/// This file contains the unittests of the STELLA utitlity functions.
///
//===------------------------------------------------------------------------------------------===//

#include "serialbox/core/frontend/stella/Utility.h"
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <gtest/gtest.h>
#include <memory>

using namespace serialbox;

TEST(STELLAUtility, BoostToStdSharedPointerConversion) {

  std::shared_ptr<int> std_ptr = std::make_shared<int>(5);
  ASSERT_EQ(std_ptr.use_count(), 1);

  boost::shared_ptr<int> boost_ptr = boost::make_shared<int>(5);
  ASSERT_EQ(boost_ptr.use_count(), 1);

  // std -> boost
  {
    {
      // Create new shared user
      boost::shared_ptr<int> ptr = stella::internal::make_shared_ptr(std_ptr);
      EXPECT_EQ(std_ptr.use_count(), 2);
      EXPECT_EQ(*ptr, 5);

      // Release original pointer
      std_ptr.reset();
      EXPECT_EQ(ptr.use_count(), 1);
      EXPECT_EQ(*ptr, 5);
    }
    EXPECT_EQ(std_ptr.use_count(), 0);
  }

  // boost -> std
  {
    {
      // Create new shared user
      std::shared_ptr<int> ptr = stella::internal::make_shared_ptr(boost_ptr);
      EXPECT_EQ(boost_ptr.use_count(), 2);

      // Release original pointer
      boost_ptr.reset();
      EXPECT_EQ(ptr.use_count(), 1);
      EXPECT_EQ(*ptr, 5);
    }
    EXPECT_EQ(boost_ptr.use_count(), 0);
  }
}


text:
#include "mod.h"
#include "stub/tfplayer.h"
#include "stub/tfweaponbase.h"
#include "stub/econ.h"
#include "stub/gamerules.h"
#include "stub/misc.h"
#include "util/iterate.h"
#include "util/misc.h"
#include "mod/pop/common.h"
#include "mod/pop/popmgr_extensions.h"
#include "stub/upgrades.h"
#include "stub/entities.h"
#include "stub/strings.h"
#include "stub/tf_objective_resource.h"
#include <fmt/core.h>
#include <boost/algorithm/string.hpp>
#include <boost/tokenizer.hpp>

namespace Mod::MvM::Extended_Upgrades
{
    int GetLoadoutSlotForItem(CTFItemDefinition *item, int class_index);
    void StartMenuForPlayer(CTFPlayer *player);
    void StartUpgradeListForPlayer(CTFPlayer *player, int slot, int displayitem = 0);
    void StopMenuForPlayer(CTFPlayer *player);

    bool from_buy_upgrade = false;

    class UpgradeCriteria {
    public:
        virtual bool Matches(CEconEntity *ent, CEconItemView *item, CTFPlayer *owner) = 0;
        virtual void ParseKey(KeyValues *kv) = 0;
    };

    class UpgradeCriteriaClassname : public UpgradeCriteria {
    public:
        UpgradeCriteriaClassname(std::string classname) : m_classname(classname) {}

        virtual bool Matches(CEconEntity *ent, CEconItemView *item, CTFPlayer *owner) override {
            return FStrEq(m_classname.c_str(), ent->GetClassname());
        }

        virtual void ParseKey(KeyValues *kv) override {
            if (FStrEq(kv->GetName(), "Classname"))
                m_classname = kv->GetString();
        }

    private:
        std::string m_classname;
    };

    class UpgradeCriteriaName : public UpgradeCriteria {
    public:
        UpgradeCriteriaName(std::string name) : m_name(name) {}

        virtual bool Matches(CEconEntity *ent, CEconItemView *item, CTFPlayer *owner) override {
            return FStrEq(m_name.c_str(), GetItemName(item));
        }

        virtual void ParseKey(KeyValues *kv) override {
            if (FStrEq(kv->GetName(), "Name"))
                m_name = kv->GetString();
        }

    private:
        std::string m_name;
        std::string m_strLogName;
    };

    class UpgradeCriteriaSimilar : public UpgradeCriteria
    {
    public:
        UpgradeCriteriaSimilar(const char *name) : m_strName(name)
        {
            auto itemDef = reinterpret_cast<CTFItemDefinition *>(GetItemSchema()->GetItemDefinitionByName(name));
            if (itemDef != nullptr && Mod::Pop::PopMgr_Extensions::GetCustomWeaponItemDef(name) == nullptr) {
                m_strLogName = itemDef->GetKeyValues()->GetString("item_logname");
                m_strBaseName = itemDef->GetKeyValues()->GetString("base_item_name");
                m_bCanCompareByLogName = !m_strLogName.empty() || !m_strBaseName.empty();
                m_strBaseClassMelee = itemDef->GetLoadoutSlot(TF_CLASS_UNDEFINED) == LOADOUT_POSITION_MELEE && FStrEq(itemDef->GetKeyValues()->GetString("item_quality"), "normal") ? itemDef->GetItemClass() : "";
            }
        }

        virtual bool Matches(CEconEntity *ent, CEconItemView *item_view, CTFPlayer *owner) override
        {
            if (item_view == nullptr) return false;

            bool is_custom = false;
            const char *name =  GetItemName(item_view, is_custom);
            if (FStrEq(this->m_strName.c_str(),name)) return true;

            return !is_custom && AreItemsSimilar(item_view, m_bCanCompareByLogName, m_strBaseName, m_strLogName, m_strBaseClassMelee, ent->GetClassname());
        }

        virtual void ParseKey(KeyValues *kv) override {
        }

    private:

        std::string m_strName;
        bool m_bCanCompareByLogName;
        std::string m_strLogName;
        std::string m_strBaseName;
        std::string m_strBaseClassMelee;
    };

    class UpgradeCriteriaHasDamage : public UpgradeCriteria {
    public:
        UpgradeCriteriaHasDamage() {}

        virtual bool Matches(CEconEntity *ent, CEconItemView *item, CTFPlayer *owner) override {
            auto weapon = rtti_cast<CTFWeaponBase *>(ent);
            if (weapon != nullptr) {
                int weaponid = weapon->GetWeaponID();
                return !(weaponid == TF_WEAPON_NONE ||
							weaponid == TF_WEAPON_LASER_POINTER ||
							weaponid == TF_WEAPON_MEDIGUN ||
							weaponid == TF_WEAPON_BUFF_ITEM ||
							weaponid == TF_WEAPON_BUILDER ||
							weaponid == TF_WEAPON_PDA_ENGINEER_BUILD ||
							weaponid == TF_WEAPON_PDA_ENGINEER_DESTROY ||
							weaponid == TF_WEAPON_PDA_SPY ||
							weaponid == TF_WEAPON_INVIS ||
							weaponid == TF_WEAPON_SPELLBOOK);
            }
            return false;
        }

        virtual void ParseKey(KeyValues *kv) override {

        }
    };

    class UpgradeCriteriaWeaponSlot : public UpgradeCriteria {
    public:
        UpgradeCriteriaWeaponSlot(int slot) : slot(slot) {}

        virtual bool Matches(CEconEntity *ent, CEconItemView *item, CTFPlayer *owner) override {

            return GetLoadoutSlotForItem(item->GetItemDefinition(), owner->GetPlayerClass()->GetClassIndex()) == this->slot;
        }

        virtual void ParseKey(KeyValues *kv) override {

        }
    private:
        int slot;
    };

    struct UpgradeInfo {
        int mvm_upgrade_index;
        CEconItemAttributeDefinition *attributeDefinition = nullptr;
        std::string attribute_name = "";
        int cost = 0;
        float increment = 0.25f;
        float cap = 2.0f;
        std::vector<std::unique_ptr<UpgradeCriteria>> criteria;
        std::vector<std::unique_ptr<UpgradeCriteria>> criteria_negate;
        std::vector<int> player_classes;
        std::string name = "";
        std::string description = "";
        bool playerUpgrade = false;
        bool hidden = false;
        std::string ref_name = "";
        std::vector<std::string> children;
        std::map<std::string, float> secondary_attributes;
        std::vector<int> secondary_attributes_index;
        std::map<std::string, int> required_upgrades;
        std::map<std::string, int> required_upgrades_option;
        std::map<std::string, int> disallowed_upgrades;
        std::vector<std::unique_ptr<UpgradeCriteria>> required_weapons;
        int force_upgrade_slot = -2;
        int allow_wave_min = 0;
        int allow_wave_max = 9999;
        std::string required_weapons_string = "";
        bool show_requirements = true;
        //std::string on_upgrade_output = "";
        std::vector<std::string> on_upgrade_outputs = {};
        std::vector<std::string> on_apply_outputs = {};
        std::vector<std::string> on_downgrade_outputs = {};
        std::vector<std::string> on_restore_outputs = {};
        bool force_enable = false;
        int tier = 0;
        int uigroup = 0;
    };

    std::vector<UpgradeInfo *> upgrades;
    std::map<std::string, UpgradeInfo *> upgrades_ref;
    std::vector<int> max_tier_upgrades;
    std::vector<int> min_tier_upgrades;

    std::map<CHandle<CTFPlayer>, IBaseMenu *> select_type_menus;

    std::set<CHandle<CTFPlayer>> in_upgrade_zone;

    int extended_upgrades_start_index = -1;

    bool BuyUpgrade(UpgradeInfo *upgrade,/* CEconEntity *item*/ int slot, CTFPlayer *player, bool free, bool downgrade);

    int GetLoadoutSlotForItem(CTFItemDefinition *item, int class_index)
    {
        int slot = item->GetLoadoutSlot(class_index);
        if (slot == -1 && class_index != TF_CLASS_UNDEFINED && item->m_iItemDefIndex != 0) {
            slot = item->GetLoadoutSlot(TF_CLASS_UNDEFINED);
        }
        return slot;
    }

    void FireOutputs(std::vector<std::string> &outputs, variant_t &defaultValue, CBaseEntity *activator, CBaseEntity *caller)
    {
        for(const auto &output : outputs){

            boost::tokenizer<boost::char_separator<char>> tokens(output, boost::char_separator<char>(","));
            auto tokens_it = tokens.begin();
            std::string target = tokens_it != tokens.end() ? *tokens_it++ : "";
            std::string action = tokens_it != tokens.end() ? *tokens_it++ : "";
            std::string value = tokens_it != tokens.end() ? *tokens_it++ : "";
            std::string delay = tokens_it != tokens.end() ? *tokens_it++ : "";

            if(target != "" && action != "") {
                // Use provided default parameter
                variant_t actualvalue = defaultValue;
                if (value != "") {
                    string_t stringvalue = AllocPooledString(value.c_str());
                    actualvalue.SetString(stringvalue);
                }
                CEventQueue &que = g_EventQueue;
                que.AddEvent(STRING(AllocPooledString(target.c_str())), STRING(AllocPooledString(action.c_str())), actualvalue, strtof(delay.c_str(), nullptr), activator, caller, -1);
            }
        }
    }

    class SelectUpgradeWeaponHandler : public IMenuHandler
    {
    public:

        SelectUpgradeWeaponHandler(CTFPlayer * pPlayer) : IMenuHandler() {
            this->player = pPlayer;

        }

        void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item) {
            const char *info = menu->GetItemInfo(item, nullptr);
            int slotid = -1;
            if (info == nullptr)
                return;

            if (FStrEq(info, "player")) {
                slotid = -1;
            }
            else if (FStrEq(info, "refund")) {
                auto kv = new KeyValues("MVM_Respec");
                serverGameClients->ClientCommandKeyValues(player->GetNetworkable()->GetEdict(), kv);
                return;
            }
            else if (FStrEq(info, "extra")) {
                Mod::Pop::PopMgr_Extensions::DisplayExtraLoadoutItemsClass(player, player->GetPlayerClass()->GetClassIndex());
                return;
            }
            else {
                slotid = strtol(info, nullptr, 10);
            }
            StartUpgradeListForPlayer(player, slotid, 0);
        }

        void OnMenuDestroy(IBaseMenu *menu) {
            if (select_type_menus[player] == menu)
                select_type_menus.erase(player);
            delete this;
        }

        CHandle<CTFPlayer> player;
    };

    class SelectUpgradeListHandler : public IMenuHandler
    {
    public:

        SelectUpgradeListHandler(CTFPlayer * pPlayer, int iSlot) : IMenuHandler() {
            this->player = pPlayer;
            this->slot = iSlot;

        }

        void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item) {
            const char *info = menu->GetItemInfo(item, nullptr);

            if (info == nullptr)
                return;

            int upgrade_id = strtol(info, nullptr, 10);
            if (upgrade_id < 1000)
                BuyUpgrade(upgrades[upgrade_id], this->slot, this->player, false, false);
            else if ((upgrade_id == 1000) && (!Mod::Pop::PopMgr_Extensions::ExtendedUpgradesNoUndo())) {
                DevMsg("Undoing %d %d\n", extended_upgrades_start_index, CMannVsMachineUpgradeManager::Upgrades().Count());
                for (int i = extended_upgrades_start_index; i < CMannVsMachineUpgradeManager::Upgrades().Count(); i++) {
                    CMannVsMachineUpgrades &upgr = CMannVsMachineUpgradeManager::Upgrades()[i];
                    int cur_step;
                    bool over_cap;
                    int max_step = GetUpgradeStepData(this->player, this->slot, i, cur_step, over_cap);
                    DevMsg("Undoing upgrade %d cap %f increment %f steps %d %d\n", i, upgr.m_flCap,  upgr.m_flIncrement, cur_step, max_step);
                    for (int j = 0; j < cur_step; j++) {
                        DevMsg("Undoing upgrade %d %d\n", j, cur_step);
                        from_buy_upgrade = true;
                        g_hUpgradeEntity->PlayerPurchasingUpgrade(this->player, this->slot, i, true, false, false);
                        from_buy_upgrade = false;
                    }
                }
            }

            StartUpgradeListForPlayer(this->player, this->slot, (item / 7) * 7);
        }

        virtual void OnMenuEnd(IBaseMenu *menu, MenuEndReason reason)
		{
            if (reason == MenuEnd_ExitBack) {
                if (select_type_menus[player] == menu)
                    select_type_menus.erase(player);
                StartMenuForPlayer(player);
            }
		}

        void OnMenuDestroy(IBaseMenu *menu) {
            if (select_type_menus[player] == menu)
                select_type_menus.erase(player);
            delete this;
        }

        CHandle<CTFPlayer> player;
        int slot;
    };

    void GetIncrementStringForAttribute(CEconItemAttributeDefinition *attr, float value, std::string &string) {
        if (FStrEq(attr->GetDescriptionFormat(), "value_is_percentage")) {
            string = fmt::format("{:+.2f}% {}", value, attr->GetName());
        }
        else if (FStrEq(attr->GetDescriptionFormat(), "value_is_inverted_percentage")) {
            value *= -1.0f;
            string = fmt::format("{:+.2f}% {}", value, attr->GetName());
        }
        else if (FStrEq(attr->GetDescriptionFormat(), "value_is_additive")) {
            string = fmt::format("{:.2f}% {}", value, attr->GetName());
        }
        else if (FStrEq(attr->GetDescriptionFormat(), "value_is_additive_percentage")) {
            value *= 100.0f;
            string = fmt::format("{:.2f}% {}", value, attr->GetName());
        }
    }

    void Parse_RequiredUpgrades(KeyValues *kv, std::map<std::string, int> &required_upgrades) {
        int level = 1;
        std::string name="";
        FOR_EACH_SUBKEY(kv, subkey) {
            if (FStrEq(subkey->GetName(), "Upgrade"))
                name = subkey->GetString();
            else if (FStrEq(subkey->GetName(), "Level"))
                level = subkey->GetInt();
        }
        if (name != "") {
            required_upgrades[name] = level;
        }
    }

    void Parse_SecondaryAttributes(KeyValues *kv, std::map<std::string, float> &secondary_attributes) {
        FOR_EACH_SUBKEY(kv, subkey) {
            attribute_data_union_t value;
            auto attr_def = GetItemSchema()->GetAttributeDefinitionByName(subkey->GetName());
            std::string value_str = subkey->GetString();
            if (attr_def != nullptr && LoadAttributeDataUnionFromString(attr_def, value, value_str)) {
                secondary_attributes[subkey->GetName()] = value.m_Float;
            }
        }
    }

    void Parse_OnUpgradeOutputs(KeyValues* kv, std::vector<std::string>& outputs){
        FOR_EACH_SUBKEY(kv, subkey) {
            outputs.push_back(subkey->GetString());
        }
    }

    int GetSlotFromString(const char *string) {
        int slot = -1;
        if (V_stricmp(string, "Primary") == 0)
            slot = 0;
        else if (V_stricmp(string, "Secondary") == 0)
            slot = 1;
        else if (V_stricmp(string, "Melee") == 0)
            slot = 2;
        else if (V_stricmp(string, "PDA") == 0)
            slot = 5;
        else if (V_stricmp(string, "Canteen") == 0)
            slot = 9;
        else
            slot = strtol(string, nullptr, 10);
        return slot;
    }

    int GetExtendedUpgradesStartIndex() {
        return extended_upgrades_start_index;
    }

    bool Parse_Criteria(KeyValues *kv, std::vector<std::unique_ptr<UpgradeCriteria>> &criteria) {
        FOR_EACH_SUBKEY(kv, subkey) {
            if (FStrEq(subkey->GetName(), "Classname"))
                criteria.push_back(std::make_unique<UpgradeCriteriaClassname>(subkey->GetString()));
            else if (FStrEq(subkey->GetName(), "ItemName"))
                criteria.push_back(std::make_unique<UpgradeCriteriaName>(subkey->GetString()));
            else if (FStrEq(subkey->GetName(), "SimilarToItem"))
                criteria.push_back(std::make_unique<UpgradeCriteriaSimilar>(subkey->GetString()));
            else if (FStrEq(subkey->GetName(), "DealsDamage"))
                criteria.push_back(std::make_unique<UpgradeCriteriaHasDamage>());
            else if (FStrEq(subkey->GetName(), "Slot")) {
                criteria.push_back(std::make_unique<UpgradeCriteriaWeaponSlot>(GetSlotFromString(subkey->GetString())));
            }
        }
        return false;
    }

    void RemoveUpgradesFromGameList() {
        if (extended_upgrades_start_index != -1) {
            CMannVsMachineUpgradeManager::Upgrades().SetCountNonDestructively(extended_upgrades_start_index);
        }
        extended_upgrades_start_index = -1;
    }

    void AddUpgradesToGameList() {
        extended_upgrades_start_index = -1;
        for (auto upgrade : upgrades) {
            int upgrade_index = CMannVsMachineUpgradeManager::Upgrades().AddToTail();
            if (extended_upgrades_start_index == -1)
                extended_upgrades_start_index = upgrade_index;

            CMannVsMachineUpgrades &upgrade_game = CMannVsMachineUpgradeManager::Upgrades()[upgrade_index];
            upgrade->mvm_upgrade_index = upgrade_index;
            strcpy(upgrade_game.m_szAttribute, upgrade->attribute_name.c_str());
            upgrade_game.m_flCap = upgrade->cap;
            upgrade_game.m_flIncrement = upgrade->increment;
            upgrade_game.m_nCost = upgrade->cost;
            upgrade_game.m_iUIGroup = upgrade->playerUpgrade ? 1 : upgrade->uigroup;
            upgrade_game.m_iQuality = 9500;
            upgrade_game.m_iTier = 0;

            for(auto entry : upgrade->secondary_attributes) {
                upgrade_index = CMannVsMachineUpgradeManager::Upgrades().AddToTail();
                CMannVsMachineUpgrades &upgrade_game_child = CMannVsMachineUpgradeManager::Upgrades()[upgrade_index];
                upgrade->secondary_attributes_index.push_back(upgrade_index);
                strcpy(upgrade_game_child.m_szAttribute, entry.first.c_str());

                // String attributes always have cap set the same as increment
                if (GetItemSchema()->GetAttributeDefinitionByName(entry.first.c_str())->IsType<CSchemaAttributeType_String>()) {
                    upgrade_game_child.m_flCap = entry.second;
                }
                else {
                    upgrade_game_child.m_flCap = entry.second > 0 ? 1.0f + entry.second * 64 : entry.second * 64;
                }

                upgrade_game_child.m_flIncrement = entry.second;
                upgrade_game_child.m_nCost = 0;
                upgrade_game_child.m_iUIGroup = upgrade->playerUpgrade ? 1 : upgrade->uigroup;
                upgrade_game_child.m_iQuality = 9500;
                upgrade_game_child.m_iTier = 0;
            }
        }
    }

    void Parse_ExtendedUpgrades(KeyValues *kv) {
        FOR_EACH_SUBKEY(kv, subkey) {
            if (FStrEq(subkey->GetName(), "MaxUpgradesTier")) {
                FOR_EACH_SUBKEY(subkey, subkey2) {
                    int tier = atoi(subkey2->GetName());
                    int max = subkey2->GetInt();
                    if ((size_t) tier > max_tier_upgrades.size()) {
                        max_tier_upgrades.resize(tier, 1);
                    }
                    max_tier_upgrades[tier - 1] = max;
                }
                continue;
            }
            else if (FStrEq(subkey->GetName(), "MinUpgradesTier")) {
                FOR_EACH_SUBKEY(subkey, subkey2) {
                    int tier = atoi(subkey2->GetName());
                    int max = subkey2->GetInt();
                    if ((size_t) tier > min_tier_upgrades.size()) {
                        min_tier_upgrades.resize(tier, 1);
                    }
                    min_tier_upgrades[tier - 1] = max;
                }
                continue;
            }

            auto upgradeinfo = new UpgradeInfo(); // upgrades.emplace(upgrades.end());
            upgradeinfo->ref_name = subkey->GetName();

            FOR_EACH_SUBKEY(subkey, subkey2) {
                if (FStrEq(subkey2->GetName(), "Attribute")) {
                    upgradeinfo->attribute_name = subkey2->GetString();
                    upgradeinfo->attributeDefinition = GetItemSchema()->GetAttributeDefinitionByName(upgradeinfo->attribute_name.c_str());
                }
                else if (FStrEq(subkey2->GetName(), "Cap")) {
                    upgradeinfo->cap = subkey2->GetFloat();
                }
                else if (FStrEq(subkey2->GetName(), "Increment")) {
                    upgradeinfo->increment = subkey2->GetFloat();
                }
                else if (FStrEq(subkey2->GetName(), "Cost")) {
                    upgradeinfo->cost = subkey2->GetInt();
                }
                else if (FStrEq(subkey2->GetName(), "AllowedWeapons"))
                    Parse_Criteria(subkey2, upgradeinfo->criteria);
                else if (FStrEq(subkey2->GetName(), "DisallowedWeapons"))
                    Parse_Criteria(subkey2, upgradeinfo->criteria_negate);
                else if (FStrEq(subkey2->GetName(), "PlayerUpgrade")) {
                    upgradeinfo->playerUpgrade = subkey2->GetBool();
                }
                else if (FStrEq(subkey2->GetName(), "Name"))
                    upgradeinfo->name = subkey2->GetString();
                else if (FStrEq(subkey2->GetName(), "Description"))
                    upgradeinfo->description = subkey2->GetString();
                else if (FStrEq(subkey2->GetName(), "SecondaryAttributes"))
                    Parse_SecondaryAttributes(subkey2, upgradeinfo->secondary_attributes);
                else if (FStrEq(subkey2->GetName(), "Children"))
                    upgradeinfo->children.push_back(subkey2->GetString());
                else if (FStrEq(subkey2->GetName(), "Hidden"))
                    upgradeinfo->hidden = subkey2->GetString();
                else if (FStrEq(subkey2->GetName(), "AllowedMinWave"))
                    upgradeinfo->allow_wave_min = subkey2->GetInt();
                else if (FStrEq(subkey2->GetName(), "AllowedMaxWave"))
                    upgradeinfo->allow_wave_max = subkey2->GetInt();
                else if (FStrEq(subkey2->GetName(), "RequiredUpgrade"))
                    Parse_RequiredUpgrades(subkey2, upgradeinfo->required_upgrades);
                else if (FStrEq(subkey2->GetName(), "RequiredUpgradeOr"))
                    Parse_RequiredUpgrades(subkey2, upgradeinfo->required_upgrades_option);
                else if (FStrEq(subkey2->GetName(), "DisallowedUpgrade"))
                    Parse_RequiredUpgrades(subkey2, upgradeinfo->disallowed_upgrades);
                else if (FStrEq(subkey2->GetName(), "RequiredWeapons"))
                    Parse_Criteria(subkey2, upgradeinfo->required_weapons);
                else if (FStrEq(subkey2->GetName(), "RequiredWeaponsString"))
                    upgradeinfo->required_weapons_string = subkey2->GetString();
                else if (FStrEq(subkey2->GetName(), "ForceUpgradeSlot"))
                    upgradeinfo->force_upgrade_slot = GetSlotFromString(subkey->GetString());
                else if (FStrEq(subkey2->GetName(), "ShowRequirements"))
                    upgradeinfo->show_requirements = subkey2->GetBool();
                else if (FStrEq(subkey2->GetName(), "AllowPlayerClass")) {
                    for(int i=1; i < 10; i++){
                        if(FStrEq(g_aRawPlayerClassNames[i],subkey2->GetString())){
                            upgradeinfo->player_classes.push_back(i);
                            break;
                        }
                    }
                }
                else if (FStrEq(subkey2->GetName(), "OnUpgrade")) {
                    Parse_OnUpgradeOutputs(subkey2, upgradeinfo->on_upgrade_outputs);
                }
                else if (FStrEq(subkey2->GetName(), "OnApply")) {
                    Parse_OnUpgradeOutputs(subkey2, upgradeinfo->on_apply_outputs);
                }
                else if (FStrEq(subkey2->GetName(), "OnDowngrade")) {
                    Parse_OnUpgradeOutputs(subkey2, upgradeinfo->on_downgrade_outputs);
                }
                else if (FStrEq(subkey2->GetName(), "OnRestore")) {
                    Parse_OnUpgradeOutputs(subkey2, upgradeinfo->on_restore_outputs);
                }
                else if (FStrEq(subkey2->GetName(), "ForceEnable")) {
                    upgradeinfo->force_enable = true;
                }
                else if (FStrEq(subkey2->GetName(), "Tier")) {
                    upgradeinfo->tier = subkey2->GetInt();
                }
                else if (FStrEq(subkey2->GetName(), "UIGroup")) {
                    upgradeinfo->uigroup = subkey2->GetInt();
                }

            }

            if (upgradeinfo->attributeDefinition == nullptr) {
                delete upgradeinfo;// upgrades.erase(upgradeinfo);
            }
            else {
                upgrades.push_back(upgradeinfo);
                upgrades_ref[upgradeinfo->ref_name] = upgradeinfo;

                if (upgradeinfo->name == "")
                    GetIncrementStringForAttribute(upgradeinfo->attributeDefinition, upgradeinfo->increment, upgradeinfo->name); //upgradeinfo->attributeDefinition->GetKVString("description_string", );
            }
		}
        RemoveUpgradesFromGameList();
        AddUpgradesToGameList();
    }

    void ClearUpgrades() {
        max_tier_upgrades.clear();
        min_tier_upgrades.clear();
        std::vector<CHandle<CTFPlayer>> vecmenus;
        for (auto pair : select_type_menus) {
            vecmenus.push_back(pair.first);
        }

        for (auto player : vecmenus) {
            IBaseMenu *menu = select_type_menus[player];
            if (player != nullptr)
                menus->GetDefaultStyle()->CancelClientMenu(ENTINDEX(player));

            menus->CancelMenu(menu);
            menu->Destroy();
        }
        select_type_menus.clear();

        for (auto upgrade : upgrades) {
            delete upgrade;
        }
        upgrades.clear();
        upgrades_ref.clear();

        RemoveUpgradesFromGameList();
        DevMsg("Total updates count: %d %d\n", CMannVsMachineUpgradeManager::Upgrades().Count(), extended_upgrades_start_index);
    }

    bool IsValidUpgradeForWeapon(UpgradeInfo *upgrade, CEconEntity *item, CTFPlayer *player, std::string &reason) {
        if (upgrade->hidden)
            return false;

        //Default: upgrade is valid for every weapon;

        if ((upgrade->playerUpgrade && item != nullptr) || (!upgrade->playerUpgrade && item == nullptr))
            return false;

        int wave = TFObjectiveResource()->m_nMannVsMachineWaveCount;

        int player_class = player->GetPlayerClass()->GetClassIndex();

        if (!upgrade->playerUpgrade) {
            bool valid = upgrade->criteria.empty();

            for (auto &criteria : upgrade->criteria) {
                valid |= criteria->Matches(item, item->GetItem(), player);
                if (valid)
                    break;
            }

            for (auto &criteria : upgrade->criteria_negate) {
                valid &= !criteria->Matches(item, item->GetItem(), player);
                if (!valid)
                    break;
            }
            if (!valid)
                return false;
        }
        if (!upgrade->player_classes.empty()) {
            bool found = false;
            for (int classindex : upgrade->player_classes) {
                if (classindex == player_class) {
                    found = true;
                    break;
                }
            }
            if (!found)
                return false;
        }

        if (wave < upgrade->allow_wave_min) {
            reason = fmt::format("Available from wave {}", upgrade->allow_wave_min);
            return false;
        }
        else if (wave > upgrade->allow_wave_max) {
            reason = fmt::format("Available up to wave {}", upgrade->allow_wave_max);
            return false;
        }

        for (auto entry : upgrade->required_upgrades) {
            UpgradeInfo *child = upgrades_ref[entry.first];
            if (child != nullptr) {
                int cur_step;
                bool over_cap;
                int max_step = GetUpgradeStepData(player, upgrade->playerUpgrade ? -1 : GetLoadoutSlotForItem(item->GetItem()->GetItemDefinition(), player_class), child->mvm_upgrade_index, cur_step, over_cap);
                if (cur_step < entry.second) {
                    reason = fmt::format("Requires {} upgraded to level {}", child->name, entry.second);
                    return false;
                }
            }
        }

        for (auto entry : upgrade->disallowed_upgrades) {
            UpgradeInfo *child = upgrades_ref[entry.first];
            DevMsg("disallowed upgrade %s %d\n",entry.first.c_str(), child != nullptr);
            if (child != nullptr) {
                int cur_step;
                bool over_cap;
                int max_step = GetUpgradeStepData(player, upgrade->playerUpgrade ? -1 : GetLoadoutSlotForItem(item->GetItem()->GetItemDefinition(), player_class), child->mvm_upgrade_index, cur_step, over_cap);
                DevMsg("%d %d\n", cur_step, entry.second);
                if (cur_step >= entry.second) {
                    reason = fmt::format("Incompatible with {} upgrade", child->name);
                    return false;
                }
            }
        }

        if (!upgrade->required_upgrades_option.empty()) {
            bool found = false;
            for (auto &entry : upgrade->required_upgrades_option) {
                UpgradeInfo *child = upgrades_ref[entry.first];
                if (child != nullptr) {
                    int cur_step;
                    bool over_cap;
                    int max_step = GetUpgradeStepData(player, upgrade->playerUpgrade ? -1 : GetLoadoutSlotForItem(item->GetItem()->GetItemDefinition(), player_class), child->mvm_upgrade_index, cur_step, over_cap);
                    if (cur_step >= entry.second) {
                        found = true;
                    }
                    else {
                        reason = fmt::format("Requires {} upgraded to level {}", child->name, entry.second);
                    }
                }
            }
            if (!found) {
                return false;
            }
        }

        if (!upgrade->required_weapons.empty()) {
            bool found = false;
            for (auto &criteria : upgrade->required_weapons) {
                for (loadout_positions_t slot : {
                    LOADOUT_POSITION_PRIMARY,
                    LOADOUT_POSITION_SECONDARY,
                    LOADOUT_POSITION_MELEE,
                    LOADOUT_POSITION_BUILDING,
                    LOADOUT_POSITION_PDA,
                    LOADOUT_POSITION_ACTION,
                }) {
                    CEconEntity *item_require = GetEconEntityAtLoadoutSlot(player, (int)slot);
                    if (item_require != nullptr) {
                        found = criteria->Matches(item_require, item->GetItem(), player);
                    }
                    if (found)
                        break;
                }
                if (found)
                        break;
            }
            if (!found) {
                reason = upgrade->required_weapons_string;
                return false;
            }
        }

        if (upgrade->tier > 0) {
            int numTierUpgrades = 0;
            int numPrevTierUpgrades = 0;
            for (auto &upgrade2 : upgrades) {
                if (upgrade2 != nullptr && upgrade->playerUpgrade == upgrade2->playerUpgrade) {
                    int cur_step;
                    bool over_cap;
                    int max_step = GetUpgradeStepData(player, upgrade->playerUpgrade ? -1 : GetLoadoutSlotForItem(item->GetItem()->GetItemDefinition(), player_class), upgrade2->mvm_upgrade_index, cur_step, over_cap);
                    if (cur_step > 0) {
                        if (upgrade->tier == upgrade2->tier) {
                            numTierUpgrades+=cur_step;
                        }
                        else if (upgrade->tier == upgrade2->tier + 1) {
                            numPrevTierUpgrades+=cur_step;
                        }
                    }
                }
            }
            int maxUpgradesForThisTier = ((int) max_tier_upgrades.size() > upgrade->tier - 1 ? max_tier_upgrades[upgrade->tier - 1] : 1);
            int minUpgradesForPrevTier = (upgrade->tier > 1 && (int) min_tier_upgrades.size() > upgrade->tier - 2 ? min_tier_upgrades[upgrade->tier - 2] : 1);
            if (numTierUpgrades >= maxUpgradesForThisTier) {
                reason = fmt::format("Tier {} is closed", upgrade->tier);
                return false;
            }
            if (upgrade->tier > 1 && numPrevTierUpgrades < minUpgradesForPrevTier) {
                reason = fmt::format("Buy {} more upgrades on tier {} to unlock this tier", minUpgradesForPrevTier - numPrevTierUpgrades, upgrade->tier - 1);
                return false;
            }
        }

        return true;
    }

    bool WeaponHasValidUpgrades(CEconEntity *item, CTFPlayer *player) {
        for (size_t i = 0; i < upgrades.size(); i++) {
            auto upgrade = upgrades[i];
            std::string reason = "";
            if (IsValidUpgradeForWeapon(upgrade, item, player, reason) || (reason != "" && upgrade->show_requirements)) {
                return true;
            }
        }
        return false;
    }

    bool from_buy_upgrade_free = false;
    bool upgrade_success = false;

    bool BuyUpgrade(UpgradeInfo *upgrade,/* CEconEntity *item*/ int slot, CTFPlayer *player, bool free, bool downgrade) {
        if (g_hUpgradeEntity.GetRef() == nullptr) {
            DevMsg("No upgrade entity?\n");
            return false;
        }
        /*int cost = upgrade->cost;

        if (downgrade)
            cost *= -1;

        if (!free && cost > player->GetCurrency())
            return false;*/
        from_buy_upgrade = true;
        upgrade_success = false;
        int override_slot = slot;

        if (upgrade->force_upgrade_slot != -2) {
            override_slot = upgrade->force_upgrade_slot;
        }
        g_hUpgradeEntity->PlayerPurchasingUpgrade(player, override_slot, upgrade->mvm_upgrade_index, downgrade, free, false);

        if (upgrade_success) {
            from_buy_upgrade_free = true;
            for (auto childname : upgrade->children) {
                auto child = upgrades_ref[childname];
                if (child != nullptr) {

                    override_slot = slot;
                    if (child->force_upgrade_slot != -2) {
                        override_slot = child->force_upgrade_slot;
                    }
                    g_hUpgradeEntity->PlayerPurchasingUpgrade(player, override_slot, child->mvm_upgrade_index, downgrade, true, false);
                }
            }
            for (int attr : upgrade->secondary_attributes_index) {
                DevMsg("Buy Secondary upgrade %d\n", attr);
                g_hUpgradeEntity->PlayerPurchasingUpgrade(player, override_slot, attr, downgrade, true, false);
            }
            from_buy_upgrade_free = false;

            int cur_step;
            bool over_cap;
            int max_step = GetUpgradeStepData(player, slot, upgrade->mvm_upgrade_index, cur_step, over_cap);

            variant_t variant;
            variant.SetInt(cur_step);

            auto itemInSlot = GetEconEntityAtLoadoutSlot(player, slot);
            FireOutputs(upgrade->on_upgrade_outputs, variant, player,  itemInSlot == nullptr ? (CBaseEntity *)player : (CBaseEntity *)itemInSlot);
        }
            //if (!free)
            //    player->RemoveCurrency(cost);

            //RememberUpgrade(upgrade, item->GetItem(), player, cost, downgrade);
            //return true;
        //}
        from_buy_upgrade = false;
        return upgrade_success;
    }

    void StartUpgradeListForPlayer(CTFPlayer *player, int slot, int displayitem) {
        menus->GetDefaultStyle()->CancelClientMenu(ENTINDEX(player));

        CEconEntity *item = GetEconEntityAtLoadoutSlot(player, slot);

        DevMsg("Start upgrade list %d %d\n", slot, item != nullptr);

        if (slot != -1 && item == nullptr) return;

        SelectUpgradeListHandler *handler = new SelectUpgradeListHandler(player, slot);
        IBaseMenu *menu = menus->GetDefaultStyle()->CreateMenu(handler);

        if (slot == -1)
            menu->SetDefaultTitle("Player Upgrades");
        else {
            menu->SetDefaultTitle(CFmtStr("Upgrades for %s", GetItemNameForDisplay(item->GetItem())));
        }
        menu->SetMenuOptionFlags(MENUFLAG_BUTTON_EXITBACK);

        for (size_t i = 0; i < upgrades.size(); i++) {
            auto upgrade = upgrades[i];
            std::string disabled_reason;
            bool enabled = IsValidUpgradeForWeapon(upgrade, item, player, disabled_reason);
            if (upgrade->force_enable) enabled = true;

            int cur_step;
            bool over_cap;
            int max_step = GetUpgradeStepData(player, slot, upgrade->mvm_upgrade_index, cur_step, over_cap);

            if (enabled) {

                char text[128];
                if (upgrade->increment != 0 && max_step < 100000 ) {
                    snprintf(text, 128, "%s (%d/%d) $%d", upgrade->name.c_str(), cur_step, max_step, upgrade->cost);
                }
                else { // If increment == 0 or max steps less than 100000, pretend unlimited upgrades
                    snprintf(text, 128, "%s $%d", upgrade->name.c_str(), upgrade->cost);
                }

                ItemDrawInfo info1(text,
                    cur_step >= max_step || player->GetCurrency() < upgrade->cost ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT);

                // Ensure that upgrade and its description will land on the same page
                if (!upgrade->description.empty() && menu->GetItemCount() % 7 == 6) {
                    menu->AppendItem("", ItemDrawInfo("", ITEMDRAW_DISABLED));
                }

                static char buf[4];
                snprintf(buf, sizeof(buf), "%d", (int)i);
                menu->AppendItem(buf, info1);

                if (!upgrade->description.empty()) {
                    ItemDrawInfo infodesc(CFmtStr("^ %s", upgrade->description.c_str()), ITEMDRAW_DISABLED);
                    menu->AppendItem("9999", infodesc);
                }
            }
            else if (upgrade->show_requirements && disabled_reason != "") {

                char text[128];
                if (upgrade->increment != 0 && max_step < 100000) {
                    snprintf(text, 128, "%s: %s (%d/%d) $%d", upgrade->name.c_str(), disabled_reason.c_str(), cur_step, max_step, upgrade->cost);
                }
                else { // If increment == 0 or max steps less than 100000, pretend unlimited upgrades
                    snprintf(text, 128, "%s: %s $%d", upgrade->name.c_str(), disabled_reason.c_str(), upgrade->cost);
                }

                ItemDrawInfo info1(text, ITEMDRAW_DISABLED);

                static char buf[4];
                snprintf(buf, sizeof(buf), "%d", (int)i);
                menu->AppendItem(buf, info1);

                if (!upgrade->description.empty()) {
                    ItemDrawInfo infodesc(CFmtStr("^ %s", upgrade->description.c_str()), ITEMDRAW_DISABLED);
                    menu->AppendItem("9999", infodesc);
                }
            }
        }

        if(!Mod::Pop::PopMgr_Extensions::ExtendedUpgradesNoUndo()){
            ItemDrawInfo info1("Undo upgrades");
            menu->AppendItem("1000", info1);
        }
        /*if (upgrades.size() == 1) {
            ItemDrawInfo info1(" ", ITEMDRAW_NOTEXT);
            menu->AppendItem(" ", info1);
        }*/

        select_type_menus[player] = menu;
        menu->DisplayAtItem(ENTINDEX(player), 0, displayitem);
    }

    // Some items should not be displayed on the upgrade list if there are no upgrades assigned to them
    bool DisplayItemByDefault(CEconEntity *item) {
        auto weapon = rtti_cast<CTFWeaponBase *>(item);
        if (weapon != nullptr) {
            int itemID = weapon->GetWeaponID();
            if (itemID == TF_WEAPON_INVIS)
                return false;
            if (itemID == TF_WEAPON_PDA_ENGINEER_DESTROY)
                return false;
            if (itemID == TF_WEAPON_PDA_SPY)
                return false;
            // Hide engineer builder item
            if (itemID == TF_WEAPON_BUILDER) {
                auto kv = weapon->GetItem()->GetStaticData()->GetKeyValues()->FindKey("used_by_classes");
                return kv != nullptr && kv->FindKey("spy") != nullptr;
            }
        }
        return true;
    }

    void StartMenuForPlayer(CTFPlayer *player) {
        if (select_type_menus.find(player) != select_type_menus.end()) return;

        SelectUpgradeWeaponHandler *handler = new SelectUpgradeWeaponHandler(player);
        IBaseMenu *menu = menus->GetDefaultStyle()->CreateMenu(handler);

        menu->SetDefaultTitle("Extended Upgrades Menu");
        menu->SetMenuOptionFlags(0);

        ItemDrawInfo info1("Player Upgrades", WeaponHasValidUpgrades(nullptr, player) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
        menu->AppendItem("player", info1);

        for (loadout_positions_t slot : {
			LOADOUT_POSITION_PRIMARY,
			LOADOUT_POSITION_SECONDARY,
			LOADOUT_POSITION_MELEE,
			LOADOUT_POSITION_BUILDING,
			LOADOUT_POSITION_PDA,
			LOADOUT_POSITION_PDA2,
			LOADOUT_POSITION_ACTION,
		}) {
            CEconEntity *item = GetEconEntityAtLoadoutSlot(player, (int)slot);
            if (item != nullptr) {
                bool hasValidUpgrades = WeaponHasValidUpgrades(item, player);
                if (!hasValidUpgrades && !DisplayItemByDefault(item))
                    continue;

                ItemDrawInfo info2(GetItemNameForDisplay(item->GetItem()), hasValidUpgrades ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);

                static char buf[4];
                snprintf(buf, sizeof(buf), "%d", (int)slot);
                menu->AppendItem(buf, info2);
            }
        }

        static ConVarRef tf_mvm_respec_enabled("tf_mvm_respec_enabled");
        ItemDrawInfo info2("Refund Upgrades", tf_mvm_respec_enabled.GetBool() ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
        menu->AppendItem("refund", info2);

        if (Mod::Pop::PopMgr_Extensions::HasExtraLoadoutItems(player->GetPlayerClass()->GetClassIndex())) {

            ItemDrawInfo info3("Extra loadout items", ITEMDRAW_DEFAULT);
            menu->AppendItem("extra", info3);
        }

        select_type_menus[player] = menu;

        menu->Display(ENTINDEX(player), 0);
    }

    void StopMenuForPlayer(CTFPlayer *player) {
        if (select_type_menus.find(player) == select_type_menus.end()) return;
        DevMsg("Stopped menu\n");
        IBaseMenu *menu = select_type_menus[player];
        menus->GetDefaultStyle()->CancelClientMenu(ENTINDEX(player));
        menus->CancelMenu(menu);
        menu->Destroy();

        menu = menus->GetDefaultStyle()->CreateMenu(new SelectUpgradeWeaponHandler(player));
        menu->SetDefaultTitle(" ");
        menu->SetMenuOptionFlags(0);
        ItemDrawInfo info1(" ", ITEMDRAW_NOTEXT);
        menu->AppendItem(" ", info1);
        ItemDrawInfo info2(" ", ITEMDRAW_NOTEXT);
        menu->AppendItem(" ", info2);
        menu->Display(ENTINDEX(player), 1);
    }

    DETOUR_DECL_MEMBER(bool, CPopulationManager_Parse)
	{
        ClearUpgrades();
        return DETOUR_MEMBER_CALL(CPopulationManager_Parse)();
    }

    DETOUR_DECL_MEMBER(void, CMannVsMachineUpgradeManager_LoadUpgradesFileFromPath, const char *path)
	{
        DETOUR_MEMBER_CALL(CMannVsMachineUpgradeManager_LoadUpgradesFileFromPath)(path);
        AddUpgradesToGameList();
    }

    bool player_is_downgrading = false;
    DETOUR_DECL_MEMBER(bool, CTFGameRules_CanUpgradeWithAttrib, CTFPlayer *player, int slot, int defindex, CMannVsMachineUpgrades *upgrade)
	{
        if (upgrade != nullptr && upgrade->m_iQuality == 9500) {
            return player_is_downgrading || from_buy_upgrade;
        }

        return DETOUR_MEMBER_CALL(CTFGameRules_CanUpgradeWithAttrib)(player, slot, defindex, upgrade);
    }

    DETOUR_DECL_MEMBER(int, CTFGameRules_GetCostForUpgrade, CMannVsMachineUpgrades* upgrade, int slot, int classindex, CTFPlayer *player)
	{
        if (upgrade != nullptr && upgrade->m_iQuality == 9500)
            return upgrade->m_nCost;

        return DETOUR_MEMBER_CALL(CTFGameRules_GetCostForUpgrade)(upgrade, slot, classindex, player);
    }

    DETOUR_DECL_MEMBER(attrib_definition_index_t, CUpgrades_ApplyUpgradeToItem, CTFPlayer* player, CEconItemView *item, int upgrade, int cost, bool downgrade, bool fresh)
	{
        attrib_definition_index_t result = DETOUR_MEMBER_CALL(CUpgrades_ApplyUpgradeToItem)(player, item, upgrade, cost, downgrade, fresh);
        upgrade_success = result != INVALID_ATTRIB_DEF_INDEX;

        DevMsg("ApplyUpgradeToItem %d %d %d %d\n", upgrade_success, upgrade, cost, downgrade);
        if (upgrade_success && extended_upgrades_start_index != -1 && upgrade >= extended_upgrades_start_index && upgrade < extended_upgrades_start_index + (int)upgrades.size()) {
            int slot = item == nullptr ? -1 : GetLoadoutSlotForItem(item->GetItemDefinition(), player->GetPlayerClass()->GetClassIndex());
            auto upgradeInfo = upgrades[upgrade - extended_upgrades_start_index];
            int cur_step;
            bool over_cap;
            int max_step = GetUpgradeStepData(player, slot, upgrade, cur_step, over_cap);

            DevMsg("^ %d/%d %e %e\n", cur_step, max_step, CMannVsMachineUpgradeManager::Upgrades()[upgrade].m_flCap, CMannVsMachineUpgradeManager::Upgrades()[upgrade].m_flIncrement);

            variant_t variant;
            variant.SetInt(cur_step);

            auto item_entity = GetEconEntityAtLoadoutSlot(player, slot);
            if (!downgrade) {
                FireOutputs(upgradeInfo->on_apply_outputs, variant, player, item_entity == nullptr ? (CBaseEntity *) player : item_entity);
            }
            else {
                FireOutputs(upgradeInfo->on_downgrade_outputs, variant, player, item_entity == nullptr ? (CBaseEntity *) player : item_entity);
            }
        }
        return result;
    }

    RefCount rc_CUpgrades_PlayerPurchasingUpgrade;
    RefCount rc_CTFPlayerSharedUtils_GetEconItemViewByLoadoutSlot;
    DETOUR_DECL_MEMBER(int, CTFItemDefinition_GetLoadoutSlot, int classIndex)
	{
		CTFItemDefinition *item_def = reinterpret_cast<CTFItemDefinition *>(this);
		int slot = DETOUR_MEMBER_CALL(CTFItemDefinition_GetLoadoutSlot)(classIndex);
		if (rc_CTFPlayerSharedUtils_GetEconItemViewByLoadoutSlot && item_def->m_iItemDefIndex != 0 && slot == -1 && classIndex != TF_CLASS_UNDEFINED)
			slot = item_def->GetLoadoutSlot(TF_CLASS_UNDEFINED);
		return slot;
	}

    DETOUR_DECL_MEMBER(void, CUpgrades_PlayerPurchasingUpgrade, CTFPlayer *player, int itemslot, int upgradeslot, bool sell, bool free, bool b3)
	{
        SCOPED_INCREMENT(rc_CUpgrades_PlayerPurchasingUpgrade);
        player_is_downgrading = sell;
        DevMsg("PlayerPurchasing %d %d %d %d\n", itemslot, upgradeslot, sell, free);
		DETOUR_MEMBER_CALL(CUpgrades_PlayerPurchasingUpgrade)(player, itemslot, upgradeslot, sell, free, b3);
	}

	DETOUR_DECL_MEMBER(void, CPopulationManager_RestoreCheckpoint)
	{
		DETOUR_MEMBER_CALL(CPopulationManager_RestoreCheckpoint)();

		ForEachTFPlayer([](CTFPlayer *player) {

            for (auto upgrade : upgrades) {
                int cur_step;
                bool over_cap;
                for (int slot = -1 ; slot <= LOADOUT_POSITION_ACTION; slot++) {
                    int max_step = GetUpgradeStepData(player, slot, upgrade->mvm_upgrade_index, cur_step, over_cap);
                    variant_t variant;
                    variant.SetInt(cur_step);
                    auto item = GetEconEntityAtLoadoutSlot(player, (int)slot);
                    FireOutputs(upgrade->on_restore_outputs, variant, player, item == nullptr ? (CBaseEntity *)player : item);
                }
            }
		});
	}

    DETOUR_DECL_STATIC(int, GetUpgradeStepData, CTFPlayer *player, int slot, int upgrade, int& cur_step, bool& over_cap)
	{
        if (upgrade >= 0 && upgrade <= CMannVsMachineUpgradeManager::Upgrades().Count()) {
            auto &upgradeInfo = CMannVsMachineUpgradeManager::Upgrades()[upgrade];
            auto attribDef = GetItemSchema()->GetAttributeDefinitionByName(upgradeInfo.m_szAttribute);
            //DevMsg("IsString(%d)\n", attribDef != nullptr && attribDef->IsType<CSchemaAttributeType_String>());
            if (attribDef != nullptr && attribDef->IsType<CSchemaAttributeType_String>()) {
                CAttributeList *attribList = nullptr;
                if (slot == -1) {
                    attribList = player->GetAttributeList();
                }
                else {
                    auto item = GetEconEntityAtLoadoutSlot(player, (int)slot);
                    if (item != nullptr) {
                        attribList = &item->GetItem()->GetAttributeList();
                    }
                }
                if (attribList != nullptr) {
                    auto attr = attribList->GetAttributeByID(attribDef->GetIndex());

                    over_cap = false;
                    cur_step = attr != nullptr ? 1 : 0;
                    return 1;
                }
            }
        }
		auto result = DETOUR_STATIC_CALL(GetUpgradeStepData)(player, slot, upgrade, cur_step, over_cap);
		return result;
	}

    #warning __gcc_regcall detours considered harmful!
	DETOUR_DECL_STATIC_CALL_CONVENTION(__gcc_regcall, attrib_definition_index_t, ApplyUpgrade_Default, const CMannVsMachineUpgrades& upgrade, CTFPlayer *pTFPlayer, CEconItemView *pEconItemView, int nCost, bool bDowngrade)
	{
        auto attribDef = GetItemSchema()->GetAttributeDefinitionByName(upgrade.m_szAttribute);
        if (attribDef != nullptr && attribDef->IsType<CSchemaAttributeType_String>()) {
            CAttributeList *attribList = nullptr;
            if (upgrade.m_iUIGroup == 1) {
                attribList = pTFPlayer->GetAttributeList();
            }
            else if (pEconItemView != nullptr) {
                attribList = &pEconItemView->GetAttributeList();
            }
            if (attribList == nullptr) return INVALID_ATTRIB_DEF_INDEX;

            if (bDowngrade) {
                if (attribList->GetAttributeByID(attribDef->GetIndex()) != nullptr) {
                    attribList->RemoveAttribute(attribDef);
                    return (attrib_definition_index_t) attribDef->GetIndex();
                }
                else {
                    return INVALID_ATTRIB_DEF_INDEX;
                }
            }
            else {
                attribList->SetRuntimeAttributeValue(attribDef, upgrade.m_flIncrement);
	            attribList->SetRuntimeAttributeRefundableCurrency(attribDef, nCost);
                return (attrib_definition_index_t) attribDef->GetIndex();
            }
            return INVALID_ATTRIB_DEF_INDEX;
        }
        return DETOUR_STATIC_CALL(ApplyUpgrade_Default)(upgrade, pTFPlayer, pEconItemView, nCost, bDowngrade);
    }

	class CMod : public IMod, public IModCallbackListener, public IFrameUpdatePostEntityThinkListener
	{
	public:
		CMod() : IMod("MvM:Extended_Upgrades")
		{
            MOD_ADD_DETOUR_MEMBER(CPopulationManager_Parse, "CPopulationManager::Parse");
            MOD_ADD_DETOUR_MEMBER(CMannVsMachineUpgradeManager_LoadUpgradesFileFromPath, "CMannVsMachineUpgradeManager::LoadUpgradesFileFromPath");
            MOD_ADD_DETOUR_MEMBER(CTFGameRules_CanUpgradeWithAttrib, "CTFGameRules::CanUpgradeWithAttrib");
            MOD_ADD_DETOUR_MEMBER(CTFGameRules_GetCostForUpgrade, "CTFGameRules::GetCostForUpgrade");
            MOD_ADD_DETOUR_MEMBER(CUpgrades_ApplyUpgradeToItem, "CUpgrades::ApplyUpgradeToItem");
            //MOD_ADD_DETOUR_MEMBER(CTFItemDefinition_GetLoadoutSlot, "CTFItemDefinition::GetLoadoutSlot");
            MOD_ADD_DETOUR_MEMBER(CUpgrades_PlayerPurchasingUpgrade, "CUpgrades::PlayerPurchasingUpgrade");
            MOD_ADD_DETOUR_MEMBER(CPopulationManager_RestoreCheckpoint, "CPopulationManager::RestoreCheckpoint");

            // Properly track string attribute upgrades
            MOD_ADD_DETOUR_STATIC(GetUpgradeStepData, "GetUpgradeStepData");
            MOD_ADD_DETOUR_STATIC(ApplyUpgrade_Default, "ApplyUpgrade_Default");
		}

        virtual bool ShouldReceiveCallbacks() const override { return this->IsEnabled(); }

        virtual void FrameUpdatePostEntityThink() override
		{
			if (!TFGameRules()->IsMannVsMachineMode()) return;

            for (auto it = in_upgrade_zone.begin(); it != in_upgrade_zone.end();) {
                if ((*it).Get() == nullptr || !(*it).Get()->m_Shared->m_bInUpgradeZone) {
                    if ((*it).Get() != nullptr) {

                        auto kv = new KeyValues("MvM_UpgradesDone");
                        serverGameClients->ClientCommandKeyValues((*it).Get()->GetNetworkable()->GetEdict(), kv);
                    }
                    it = in_upgrade_zone.erase(it);
                }
                else {
                    it++;
                }
            }

            ForEachTFPlayer([&](CTFPlayer *player){
                if (player->IsBot()) return;

                if (player->m_Shared->m_bInUpgradeZone && !upgrades.empty() && in_upgrade_zone.count(player) == 0) {
                    in_upgrade_zone.insert(player);
                    auto kv = new KeyValues("MvM_UpgradesBegin");
                    serverGameClients->ClientCommandKeyValues(player->GetNetworkable()->GetEdict(), kv);
                }

                int class_index = player->GetPlayerClass()->GetClassIndex();
                if (player->m_Shared->m_bInUpgradeZone && g_hUpgradeEntity.GetRef() != nullptr && (!upgrades.empty() || Mod::Pop::PopMgr_Extensions::HasExtraLoadoutItems(class_index)) && select_type_menus.find(player) == select_type_menus.end()) {
                    bool found = false;
                    bool found_any = false;
                    bool has_extra = Mod::Pop::PopMgr_Extensions::HasExtraLoadoutItems(class_index);

                    for (loadout_positions_t slot : {
                        LOADOUT_POSITION_PRIMARY,
                        LOADOUT_POSITION_SECONDARY,
                        LOADOUT_POSITION_MELEE,
                        LOADOUT_POSITION_BUILDING,
                        LOADOUT_POSITION_PDA,
                        LOADOUT_POSITION_ACTION,
                    }) {
                        CBaseCombatWeapon *item = player->Weapon_GetSlot((int)slot);

                        bool found_now = WeaponHasValidUpgrades(item, player);
                        found_any |= found_now;
                        if (found_now && item == player->GetActiveWeapon()) {

                            if (!WeaponHasValidUpgrades(nullptr, player) && !has_extra) {
                                found = true;
                                StartUpgradeListForPlayer(player, (int)slot, 0);
                            }
                            break;
                        }
                    }

                    if (!found) {
                        if (!found_any && !has_extra) {
                            if (WeaponHasValidUpgrades(nullptr, player))
                                StartUpgradeListForPlayer(player, -1, 0);
                        }
                        else if (!found_any && has_extra && !WeaponHasValidUpgrades(nullptr, player)) {
                            StartMenuForPlayer(player);
                            Mod::Pop::PopMgr_Extensions::DisplayExtraLoadoutItemsClass(player, class_index);
                        }
                        else {
                            StartMenuForPlayer(player);
                        }
                    }
                }
                else if (!player->m_Shared->m_bInUpgradeZone && select_type_menus.find(player) != select_type_menus.end()) {
                    StopMenuForPlayer(player);
                }
            });

		}

        virtual void OnEnable() override
        {

            LoadItemNames();
        }

        virtual void OnDisable() override
        {
            ForEachTFPlayer([&](CTFPlayer *player){
                if (!player->IsBot())
                    menus->GetDefaultStyle()->CancelClientMenu(ENTINDEX(player));
            });
        }

        virtual void LevelInitPreEntity() override
		{

            ClearUpgrades();
		}

		virtual void LevelShutdownPostEntity() override
		{
			ClearUpgrades();
		}

	};
	CMod s_Mod;

	ConVar cvar_enable("sig_mvm_extended_upgrades", "0", FCVAR_NOTIFY,
		"Mod: enable extended upgrades",
		[](IConVar *pConVar, const char *pOldValue, float flOldValue){
			s_Mod.Toggle(static_cast<ConVar *>(pConVar)->GetBool());

		});
}

ext: cpp


text:
#include "Utils.h"

#include <pthread.h>
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>

#include <boost/fiber/numa/pin_thread.hpp>
#include <boost/fiber/numa/topology.hpp>
#include <experimental/filesystem>
#include <iostream>

void Utils::bindProcess(int core_id) {
  if (core_id >= (int) std::thread::hardware_concurrency()) {
    std::cout << "warning: the core id exceeds the number of cores" << std::endl;
    core_id = core_id % (int) std::thread::hardware_concurrency();
  }
  //core_id = core_id + 1;
  pthread_t pid = pthread_self();
  cpu_set_t cpuset;
  CPU_ZERO(&cpuset);
  CPU_SET(core_id, &cpuset);
  const int set_result = pthread_setaffinity_np(pid, sizeof(cpu_set_t), &cpuset);
  if (set_result != 0)
    print_error_then_terminate(set_result, "sched_setaffinity");
  if (CPU_ISSET(core_id, &cpuset))
    fprintf(stdout, "Successfully set thread %lu to affinity to CPU %d\n", pid, core_id);
  else
    fprintf(stderr, "Failed to set thread %lu to affinity to CPU %d\n", pid, core_id);
}

void Utils::bindProcess(std::thread &thread, int id) {
  if (id >= (int) std::thread::hardware_concurrency()) {
    std::cout << "warning: the core id exceeds the number of cores" << std::endl;
    id = id % (int) std::thread::hardware_concurrency();
  }
  auto pid = thread.native_handle();
  /* Pin worker to thread */
  /*int min = 1; // +1 dispatcher
  int max = SystemConf::getInstance().THREADS;
  int total = max - min + 1;

  int core_id = ((id - (min - 1)) % total) + min;*/
  int core_id = id; // + 1;
  std::cout << "[DBG] bind worker " + std::to_string(id) + " to core " + std::to_string(core_id) << std::endl;

  cpu_set_t cpuset;
  CPU_ZERO(&cpuset);
  CPU_SET(core_id, &cpuset);
  const int set_result = pthread_setaffinity_np(pid, sizeof(cpu_set_t), &cpuset);
  if (set_result != 0)
    print_error_then_terminate(set_result, "sched_setaffinity");
  if (CPU_ISSET(core_id, &cpuset))
    fprintf(stdout, "Successfully set thread %lu to affinity to CPU %d\n", pid, core_id);
  else
    fprintf(stderr, "Failed to set thread %lu to affinity to CPU %d\n", pid, core_id);
}

long Utils::pack(long systemTimestamp, long tupleTimestamp) {
  return (systemTimestamp << 32) | tupleTimestamp;
}

int Utils::getSystemTimestamp(long value) {
  return (int) (value >> 32);
}

int Utils::getTupleTimestamp(long value) {
  return (int) value;
}

int Utils::getPowerOfTwo(int value) {
  bool powerOfTwo = value != 0 && !(value & (value - 1));
  if (!powerOfTwo) {
    int temp = 0;
    auto num = (double) value;
    while (num > 1) {
      num = num / 2;
      temp++;
    }
    value = (int) std::pow(2, temp);
  }
  return value;
}

bool Utils::_is_pointer_aligned(const void *p, int alignment) {
  return ((((uintptr_t) p) & (alignment - 1)) == 0);
}

bool Utils::_is_length_aligned(int length, int alignment) {
  return ((length & (alignment - 1)) == 0);
}

std::string Utils::getCurrentWorkingDir() {
  char buff[FILENAME_MAX];
  GetCurrentDir(buff, FILENAME_MAX);
  std::string current_working_dir(buff);
  return current_working_dir;
}

std::string Utils::getHomeDir() {
  struct passwd *pw = getpwuid(getuid());
  const char *homedir = pw->pw_dir;
  return std::string(homedir);
}

void Utils::process_mem_usage(double &vm_usage, double &resident_set) {
  using std::ios_base;
  using std::ifstream;
  using std::string;

  vm_usage = 0.0;
  resident_set = 0.0;

  // 'file' stat seems to give the most reliable results
  ifstream stat_stream("/proc/self/stat", ios_base::in);

  // dummy vars for leading entries in stat that we don't care about
  string pid, comm, state, ppid, pgrp, session, tty_nr;
  string tpgid, flags, minflt, cminflt, majflt, cmajflt;
  string utime, stime, cutime, cstime, priority, nice;
  string O, itrealvalue, starttime;

  // the two fields we want
  unsigned long vsize;
  long rss;

  stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
              >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
              >> utime >> stime >> cutime >> cstime >> priority >> nice
              >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest

  stat_stream.close();

  long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
  vm_usage = vsize / 1024.0;
  resident_set = rss * page_size_kb;
}

std::string Utils::getStdoutFromCommand(std::string cmd) {
  std::string data;
  FILE *stream;
  const int max_buffer = 1024;
  char buffer[max_buffer];
  cmd.append(" 2>&1");

  stream = popen(cmd.c_str(), "r");
  if (stream) {
    while (!feof(stream))
      if (fgets(buffer, max_buffer, stream) != nullptr) data.append(buffer);
    pclose(stream);
  }
  return data;
}

int Utils::getNumberOfSockets () {
    auto topo = boost::fibers::numa::topology();
    auto sockets = topo.size();
    return sockets;
}

int Utils::getNumberOfCoresPerSocket () {
    auto topo = boost::fibers::numa::topology();
    int coresPerSocket = topo.front().logical_cpus.size();
    return coresPerSocket;
}

void Utils::getOrderedCores (std::vector<int> &orderedCores) {
  auto topo = boost::fibers::numa::topology();
  for (auto &n: topo) {
    for (auto &cpu_id: n.logical_cpus) {
      orderedCores.push_back(cpu_id);
    }
  }
}

int Utils::getFirstCoreFromSocket(size_t socket) {
  auto topo = boost::fibers::numa::topology();
  if (socket > topo.size()) {
    throw std::runtime_error("error: wrong socket number");
  }
  auto &soc = topo[socket];
  for (auto &cpu_id: soc.logical_cpus) {
    return (int) cpu_id;
  }
  return -1;
}

int Utils::fileExists(char const *file) {
  return access(file, F_OK);
}

void Utils::readDirectory(const std::string &name, std::vector<std::string> &v) {
  DIR* dirp = opendir(name.c_str());
  struct dirent * dp;
  while ((dp = readdir(dirp)) != nullptr) {
    v.emplace_back(dp->d_name);
  }
  closedir(dirp);
}

void Utils::tryCreateDirectory(std::string dir) {
  std::experimental::filesystem::path path{dir};
  if (!std::experimental::filesystem::exists(
      std::experimental::filesystem::status(path))) {
    std::experimental::filesystem::create_directories(path);
  }
}

template <typename T>
void wrapArrayInVector(
    T *sourceArray, size_t arraySize,
    std::vector<T, boost::alignment::aligned_allocator<T, 64> > &targetVector) {
  typename std::_Vector_base<
      T, boost::alignment::aligned_allocator<T, 64> >::_Vector_impl *vectorPtr =
      (typename std::_Vector_base<
          T, boost::alignment::aligned_allocator<T, 64> >::_Vector_impl
           *)((void *)&targetVector);
  vectorPtr->_M_start = sourceArray;
  vectorPtr->_M_finish = vectorPtr->_M_end_of_storage =
      vectorPtr->_M_start + arraySize;
}
template void wrapArrayInVector(
    char *sourceArray, size_t arraySize,
    std::vector<char, boost::alignment::aligned_allocator<char, 64> >
        &targetVector);

template <typename T>
void releaseVectorWrapper(
    std::vector<T, boost::alignment::aligned_allocator<T, 64> > &targetVector) {
  typename std::_Vector_base<
      T, boost::alignment::aligned_allocator<T, 64> >::_Vector_impl *vectorPtr =
      (typename std::_Vector_base<
          T, boost::alignment::aligned_allocator<T, 64> >::_Vector_impl
           *)((void *)&targetVector);
  vectorPtr->_M_start = vectorPtr->_M_finish = vectorPtr->_M_end_of_storage =
      nullptr;
}
template void releaseVectorWrapper(
    std::vector<char, boost::alignment::aligned_allocator<char, 64> >
        &targetVector);

template<typename T>
std::vector<T> computePercentiles(std::vector<T> &input, std::vector<double> &percentiles) {
  std::sort(input.begin(), input.end());
  std::vector<T> res;
  for (auto perc : percentiles) {
    int pos;
    if (perc < 0)
      pos = 0;
    else if (perc > 1.0)
      pos = (int) input.size() - 1;
    else
      pos = (int) std::round(perc * input.size());
    res.push_back(input[pos]);
  }
  return res;
}
template std::vector<double> computePercentiles<double>(std::vector<double> &input, std::vector<double> &percentiles);


text:
#ifndef BADATA_HPP
#define BADATA_HPP

#include <boost/shared_ptr.hpp>

#include "BA.hpp"
#include "BAVector.hpp"
#include "stochasticInput.hpp"
#include "BALPSolverInterface.hpp"
#include "CoinPackedVector.hpp"

// stores actual problem data
// collect data into standard format for solver (introducing slacks),
// and perform linear algebra (PRICE) here

class BAData {
public:
	BAData(stochasticInput &input, BAContext &ctx);
	BAData(const BAData&);
	~BAData();

	void getCol(sparseBAVector &v, BAIndex i) const;
	void addColToVec(sparseBAVector &v, BAIndex i, double mult) const;

	// pick out nonbasic elements from "in" and multiply them with nonbasic columns
	// effectively same as multiplying with whole matrix assuming basic "in" are zero
	// a bit strange for dense input and sparse output, but this is the most convenient presently
	void multiply(const denseBAVector &in, sparseBAVector &out, const BAFlagVector<variableState>&) const;

	// multiply entire constraint matrix transpose by "in"
	// taking linear combinations of the rows
	void multiplyT(const sparseBAVector &in, sparseBAVector &out) const;

	void addSecondStageRow(const CoinPackedVectorBase& elts1, const CoinPackedVectorBase &elts2, int scen, double lb = -COIN_DBL_MAX, double ub = COIN_DBL_MAX);

	void addFirstStageRows(const std::vector<CoinPackedVector*> &v1, std::vector<double> &lb, std::vector<double> &ub, int nRows);

	void addSecondStageConsecutiveRows(const std::vector<CoinPackedVector*> &elts1, const std::vector<CoinPackedVector*> &elts2, int scenario, std::vector<double> &lb, std::vector<double> &ub, int nRows);

	int addFirstStageColumn(double lb, double ub, double c);

	void addFirstStageRow(const CoinPackedVectorBase& elts1, double lb, double ub);

	int addSecondStageColumn(int scen,double lb, double ub, double cobj);

	void deleteLastFirstStageRows(int nRows);

	void deleteLastFirstStageColumns(int nCols);

	void deleteLastSecondStageConsecutiveRows(int scenario, int nRows);

	void deleteLastSecondStageConsecutiveColumns(int scenario, int nCols);

	const CoinShallowPackedVector retrieveARow(int index) const;

	const CoinShallowPackedVector retrieveWRow(int index,int scen) const;

	const CoinShallowPackedVector retrieveTRow(int index,int scen) const;

	const CoinShallowPackedVector retrieveACol(int index) const;

	const CoinShallowPackedVector retrieveWCol(int index,int scen) const;

	const CoinShallowPackedVector retrieveTCol (int index,int scen) const;

	// make members easily accessable for use in solver
	BADimensionsSlacks dims;
	denseBAVector l,u,c;
	BAFlagVector<constraintType> vartype;
	BAFlagVector<std::string> names;
	boost::shared_ptr<CoinPackedMatrix> Acol;
	boost::shared_ptr<CoinPackedMatrix> Arow;
	std::vector<boost::shared_ptr<CoinPackedMatrix> > Tcol;
	std::vector<boost::shared_ptr<CoinPackedMatrix> > Trow;
	std::vector<boost::shared_ptr<CoinPackedMatrix> > Wcol;
	std::vector<boost::shared_ptr<CoinPackedMatrix> > Wrow;
	BAContext &ctx;

protected:
	bool onlyBoundsVary;
	mutable CoinIndexedVector out1Send; // buffer for multiplyT
	//BAFlagVector<variableState> stateCol, stateRow;

};

#endif

ext: hpp

max_stars_repo_name: jalving/PIPS

max_issues_repo_name: jalving/PIPS

max_forks_repo_name: jalving/PIPS


text:
/**
 * @brief Child Process Manager header unit tests
 * @version 1.0.0
 * @author Wolfram Rösler
 * @date 2016-10-20
 * @copyright MIT license
 */

#include <filesystem>
#include <fstream>
#include <future>
#include <unordered_set>

#define BOOST_TEST_MODULE childprocess
#include <boost/test/unit_test.hpp>

#include "childprocess.hpp"

BOOST_AUTO_TEST_SUITE(childprocess)

// Fixture class
class Fx {
public:
    const std::string tmpfile = "./childprocess-" + std::to_string(rand());

    ~Fx() {
        std::filesystem::remove(tmpfile);
    }
};

/*
 * Test running a child process
 */
BOOST_FIXTURE_TEST_CASE(exec,Fx) {
    // Our test value
    const auto data = rand();

    // Write the test value to a file using a child process
    auto chld = ChildProcess(
        "/bin/sh", {
            "-c",
            "echo " + std::to_string(data) + " >" + tmpfile + " 2>&1"
        }
    );

    // Wait until the process terminates, and check the exit code
    BOOST_TEST(chld.join()==0);

    // Waiting again returns -1 since we got the exit code already
    BOOST_TEST(chld.join()==-1);

    // Open the output file
    BOOST_TEST(std::filesystem::exists(tmpfile));
    auto ifs = std::ifstream(tmpfile);
    BOOST_TEST(!!ifs);

    // Read what's in it
    int value = -1;
    ifs >> value;

    // Make sure it's what we expect
    BOOST_TEST(value==data);
}

/*
 * Test piping stuff into/out of a process
 */
BOOST_FIXTURE_TEST_CASE(pipe,Fx) {
    // This is our test value:
    const auto data = rand();

    // Make a process we can write to and read from
    auto chld = ChildProcess(
        "/bin/grep",
        { "^" + std::to_string(data) + "$" },
        ChildProcess::IN | ChildProcess::OUT | ChildProcess::ERR
    );

    // Write to the process' standard input
    auto in = chld.make_stdin([&data](std::ostream& os) {
        // First send some random lines
        for(auto _=rand()%10;_>0;--_) {
            os << rand() << "\n";
        }

        // Then send the value we want to extract
        os << data << "\n";

        // Finish with some more random lines
        for(auto _=rand()%10;_>0;--_) {
            os << rand() << "\n";
        }
    });

    // Capture the process' standard output
    int recv = -1;
    auto out = chld.get_stdout([&recv](std::istream& is) {
        is >> recv;
    });

    // Also capture its standard error output
    std::string fromerr;
    auto err = chld.get_stderr([&fromerr](std::istream& is) {
        fromerr.assign(std::istreambuf_iterator<char>(is),std::istreambuf_iterator<char>());
    });

    // Wait until everything is finished
    in.get();
    out.get();
    err.get();
    const auto status = chld.join();

    BOOST_TEST(status==0);
    BOOST_TEST(recv==data);
    BOOST_TEST(fromerr.empty());
}

/*
 * Test parallel piping
 */
BOOST_FIXTURE_TEST_CASE(parallel,Fx) {

    // Use this many parallel processes:
    const int nprocs = 1000;

    // So do it:
    std::vector<std::future<int>> tasks;
    for(auto i=0;i<nprocs;++i) {
        tasks.push_back(std::async(std::launch::async,
            [&](int idx) {

                // Create a child process that reflects its standard input
                ChildProcess chld("/bin/cat",{},ChildProcess::IN | ChildProcess::OUT);

                // Write our thread index (0..count) into it
                auto in = chld.make_stdin([&idx](std::ostream& os) { os << idx << "\n"; });

                // Read out the result - must be identical to the input
                int recv = -1;
                auto out = chld.get_stdout([&recv](std::istream& is) { is >> recv; });

                // Wait for everybody to finish
                in.get();
                out.get();
                chld.join();

                // Return the result, leave validation to the caller
                return recv;
            },
            i)
        );
    }

    // Now count how many different results we got
    std::unordered_set<int> values;
    for(auto& t : tasks) {
        values.insert(t.get());
    }

    // Test if we got the right number of results (one per process)
    BOOST_TEST(values.size()==nprocs);
}

/*
 * Test calling an initialization function in the child process
 */
BOOST_FIXTURE_TEST_CASE(initok,Fx) {

    // Make a random string
    const auto input = std::to_string(rand());

    // Use the init function to put the test string into the environment
    // of our child process, and run a program that outputs it.
    auto chld = ChildProcess(
        "/bin/sh",
        { "-c", "echo $TESTSTRING" },
        ChildProcess::OUT,
        [&input](){ putenv(strdup(("TESTSTRING="+input).c_str())); }
    );

    // Read the child process' output
    std::string output;
    chld.get_stdout([&output](std::istream& is){ std::getline(is,output); }).get();
    chld.join();

    // Compare it
    BOOST_TEST(output==input);
}

/*
 * Test throwing an exception in the initialization function.
 */
BOOST_FIXTURE_TEST_CASE(initfail,Fx) {

    // Make a random string
    const auto input = std::to_string(rand());

    // Run a child process, but with an init function that fails and throws
    // the test string. The ChildProcess ctor will write the exception message
    // to the new process' stderr.
    ChildProcess chld("/bin/sh",
        { "-c", "echo If you can see this, the test has failed >&2" },
        ChildProcess::ERR,
        [&input](){ throw std::runtime_error(input); }
    );

    // Catch the child's stderr: If all goes well, it contains our test string
    std::string output;
    chld.get_stderr([&output](std::istream& is){ std::getline(is,output); }).get();
    chld.join();

    // Compare it
    BOOST_TEST(output.find(input)!=std::string::npos);
}

/*
 * Test throwing exceptions from the in/out/err functions.
 */
BOOST_FIXTURE_TEST_CASE(except,Fx) {

    // Run a process that simply copies stdin to stdout. The process doesn't
    // terminate before we close stdin, which we're testing implicitly.
    // Connect to all three I/O pipes.
    auto chld = ChildProcess("/bin/cat",{},ChildProcess::IN | ChildProcess::OUT | ChildProcess::ERR);

    // The identification numbers we throw around
    const auto exI = rand();
    const auto exO = rand();
    const auto exE = rand();

    // Attach to pipes and throw immediately
    auto in  = chld.make_stdin([&exI](std::ostream&){ throw exI; });
    auto out = chld.get_stdout([&exO](std::istream&){ throw exO; });
    auto err = chld.get_stderr([&exE](std::istream&){ throw exE; });

    // Wait for the threads to terminate and catch their exceptions.
    int gotI=0,gotO=0,gotE=0;
    try { in .get(); } catch(int e) { gotI = e; }
    try { out.get(); } catch(int e) { gotO = e; }
    try { err.get(); } catch(int e) { gotE = e; }

    // Wait for the process to terminate
    chld.join();

    // Compare what we got to what we're expecting
    BOOST_TEST(gotI==exI);
    BOOST_TEST(gotO==exO);
    BOOST_TEST(gotE==exE);
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: wolframroesler/childprocess

max_issues_repo_name: wolframroesler/childprocess

max_forks_repo_name: wolframroesler/childprocess


text:
/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include "base/logging.h"

#include <sys/types.h>
#include <unistd.h>
#include <log4cplus/helpers/pointer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/fileappender.h>
#include <log4cplus/syslogappender.h>

#include <boost/format.hpp>
#include <boost/algorithm/string/predicate.hpp>

using namespace log4cplus;

static bool disabled_;
static bool use_syslog_;
static const char *loggingPattern = "%D{%Y-%m-%d %a %H:%M:%S:%Q %Z} "
                                    " %h [Thread %t, Pid %i]: %m%n";

bool LoggingDisabled() {
    return disabled_;
}

void SetLoggingDisabled(bool flag) {
    disabled_ = flag;
}

bool LoggingUseSyslog() {
    return use_syslog_;
}

void CheckEnvironmentAndUpdate() {
    if (getenv("LOG_DISABLE") != NULL) {
        SetLoggingDisabled(true);
    }
}

void SetLoggingLevel(LogLevel logLevel) {
    Logger logger = Logger::getRoot();
    logger.setLogLevel(logLevel);
}

void LoggingInit() {
    BasicConfigurator config;
    config.configure();
    Logger logger = Logger::getRoot();
    std::auto_ptr<Layout> layout_ptr(new PatternLayout(loggingPattern));
    logger.getAllAppenders().at(0)->setLayout(layout_ptr);
    CheckEnvironmentAndUpdate();
}

void LoggingInit(const std::string &filename, long maxFileSize, int maxBackupIndex,
                 bool useSyslog, const std::string &syslogFacility,
                 const std::string &ident, LogLevel logLevel) {
    Logger logger = Logger::getRoot();
    logger.setLogLevel(logLevel);

    if (useSyslog) {
        helpers::Properties props;
        std::string syslogident = boost::str(
            boost::format("%1%[%2%]") % ident % getpid());
        props.setProperty(LOG4CPLUS_TEXT("facility"),
                          boost::starts_with(syslogFacility, "LOG_")
                        ? syslogFacility.substr(4)
                        : syslogFacility);
        props.setProperty(LOG4CPLUS_TEXT("ident"), syslogident);
        SharedAppenderPtr syslogappender(new SysLogAppender(props));
        std::auto_ptr<Layout> syslog_layout_ptr(new PatternLayout(
                                                    loggingPattern));
        syslogappender->setLayout(syslog_layout_ptr);
        logger.addAppender(syslogappender);
        use_syslog_ = useSyslog;
    } else {
        if (filename == "<stdout>" || filename.length() == 0) {
            BasicConfigurator config;
            config.configure();
        } else {
            SharedAppenderPtr fileappender(new RollingFileAppender(filename,
                                           maxFileSize, maxBackupIndex));
            logger.addAppender(fileappender);
        }

        std::auto_ptr<Layout> layout_ptr(new PatternLayout(loggingPattern));
        logger.getAllAppenders().at(0)->setLayout(layout_ptr);
    }
    CheckEnvironmentAndUpdate();
}

void LoggingInit(const std::string &propertyFile) {
    PropertyConfigurator::doConfigure(propertyFile);
    CheckEnvironmentAndUpdate();
}

ext: cc

max_stars_repo_name: sagarc-contrail/contrail-controller

max_issues_repo_name: sagarc-contrail/contrail-controller

max_forks_repo_name: sagarc-contrail/contrail-controller


text:
#pragma once
#include <hive/chain/hive_object_types.hpp>

#include <boost/multi_index/composite_key.hpp>

#include <fc/crypto/restartable_sha256.hpp>

namespace hive { namespace plugins { namespace block_log_info {

using namespace std;
using namespace hive::chain;

#ifndef HIVE_BLOCK_LOG_INFO_SPACE_ID
#define HIVE_BLOCK_LOG_INFO_SPACE_ID 14
#endif

enum block_log_info_object_types
{
  block_log_hash_state_object_type      = ( HIVE_BLOCK_LOG_INFO_SPACE_ID << 8 )    ,
  block_log_pending_message_object_type = ( HIVE_BLOCK_LOG_INFO_SPACE_ID << 8 ) + 1,
};

class block_log_hash_state_object : public object< block_log_hash_state_object_type, block_log_hash_state_object >
{
  CHAINBASE_OBJECT( block_log_hash_state_object );
  public:
    CHAINBASE_DEFAULT_CONSTRUCTOR( block_log_hash_state_object )

    uint64_t                 total_size = 0;
    fc::restartable_sha256   rsha256;
    uint64_t                 last_interval = 0;
};

struct block_log_message_data
{
  uint32_t block_num = 0;
  uint64_t total_size = 0;
  uint64_t current_interval = 0;
  fc::restartable_sha256 rsha256;
};

class block_log_pending_message_object : public object< block_log_pending_message_object_type, block_log_pending_message_object >
{
  CHAINBASE_OBJECT( block_log_pending_message_object );
  public:
    CHAINBASE_DEFAULT_CONSTRUCTOR( block_log_pending_message_object )

    block_log_message_data   data;
};

typedef oid_ref< block_log_hash_state_object > block_log_hash_state_id_type;
typedef oid_ref< block_log_pending_message_object > block_log_pending_message_id_type;

typedef multi_index_container<
  block_log_hash_state_object,
  indexed_by<
    ordered_unique< tag< by_id >,
      const_mem_fun< block_log_hash_state_object, block_log_hash_state_object::id_type, &block_log_hash_state_object::get_id > >
  >,
  allocator< block_log_hash_state_object >
> block_log_hash_state_index;

typedef multi_index_container<
  block_log_pending_message_object,
  indexed_by<
    ordered_unique< tag< by_id >,
      const_mem_fun< block_log_pending_message_object, block_log_pending_message_object::id_type, &block_log_pending_message_object::get_id > >
  >,
  allocator< block_log_pending_message_object >
> block_log_pending_message_index;

} } } // hive::plugins::block_log_info

FC_REFLECT( hive::plugins::block_log_info::block_log_hash_state_object, (id)(total_size)(rsha256)(last_interval) )
CHAINBASE_SET_INDEX_TYPE( hive::plugins::block_log_info::block_log_hash_state_object, hive::plugins::block_log_info::block_log_hash_state_index )

FC_REFLECT( hive::plugins::block_log_info::block_log_message_data, (block_num)(total_size)(current_interval)(rsha256) )

FC_REFLECT( hive::plugins::block_log_info::block_log_pending_message_object, (id)(data) )
CHAINBASE_SET_INDEX_TYPE( hive::plugins::block_log_info::block_log_pending_message_object, hive::plugins::block_log_info::block_log_pending_message_index )


text:
// Copyright (c) 2017-2018 The Merit Foundation developers
#include "crypto/finite_field.h"
#include "crypto/legendre.h"
#include "crypto/shamir.h"
#include "key.h"
#include "random.h"
#include <algorithm>
#include <vector>
#include <boost/multiprecision/cpp_int.hpp>

namespace shamir
{
    namespace ff = finite_field;
    namespace bm = boost::multiprecision;

    // TODO: figure out good values or make it configurable
    namespace
    {
        const int K = 5;
        const int N = 10;
        const int KEY_SIZE = 32;
    } // namespace

    ff::BigInt KeyToBigInt(const CPrivKey& key)
    {
        ff::BigInt val;
        for(const auto& ch : key) {
            val <<= 8;
            val += ch;
        }
        return val;
    }

    ff::Element RandomElement()
    {
        CPrivKey buffer(ff::POWER_BYTES);
        GetStrongRandBytes(buffer.data(), ff::POWER_BYTES);
        return KeyToBigInt(buffer);
    }

    CPrivKey BigIntToKey(ff::BigInt val)
    {
        CPrivKey key(KEY_SIZE);
        for(auto it = key.rbegin(); it != key.rend(); ++it) {
            bm::cpp_int bits = val & 0xff; // intermediate cast
            *it = static_cast<unsigned char>(bits);
            val >>= 8;
        }
        return key;
    }

    std::vector<legendre::FieldPoint> ShardKey(const CPrivKey& key)
    {
        ff::Element secret = KeyToBigInt(key);

        // get k-1 random finite_field::Elements to use as coefficients
        std::vector<ff::Element> coefs(K);
        coefs[0] = secret;
        std::generate_n(coefs.begin() + 1, K - 1, RandomElement);

        // get n random finite_field::Elements to use as inputs for shards
        std::vector<ff::Element> inputs(N);
        std::generate_n(inputs.begin(), N, RandomElement);

        std::vector<legendre::FieldPoint> points(N);
        std::transform(inputs.begin(), inputs.end(), points.begin(),
            [&coefs](const ff::Element input)
            {
                return legendre::FieldPoint{input, ff::EvalPolynomial(input, coefs)};
            });
        return points;
    }

} // namespace shamir


text:
// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.

// This file was modified by Oracle on 2013.
// Modifications copyright (c) 2013, Oracle and/or its affiliates.

// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.

// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_GEOMETRY_MULTI_HPP
#define BOOST_GEOMETRY_MULTI_HPP

#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/geometry_id.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/is_areal.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/topological_dimension.hpp>

#include <boost/geometry/algorithms/append.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/centroid.hpp>
#include <boost/geometry/algorithms/clear.hpp>
#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/correct.hpp>
#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/for_each.hpp>
#include <boost/geometry/algorithms/intersection.hpp>
#include <boost/geometry/algorithms/length.hpp>
#include <boost/geometry/algorithms/num_geometries.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/perimeter.hpp>
#include <boost/geometry/algorithms/remove_spikes.hpp>
#include <boost/geometry/algorithms/reverse.hpp>
#include <boost/geometry/algorithms/simplify.hpp>
#include <boost/geometry/algorithms/transform.hpp>
#include <boost/geometry/algorithms/unique.hpp>
#include <boost/geometry/algorithms/within.hpp>

#include <boost/geometry/algorithms/detail/point_on_border.hpp>

#include <boost/geometry/algorithms/detail/for_each_range.hpp>
#include <boost/geometry/algorithms/detail/multi_modify_with_predicate.hpp>
#include <boost/geometry/algorithms/detail/multi_sum.hpp>

#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>

#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>

#include <boost/geometry/geometries/concepts/check.hpp>

#include <boost/geometry/views/detail/range_type.hpp>
#include <boost/geometry/strategies/cartesian/centroid_average.hpp>

#include <boost/geometry/io/dsv/write.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>

#endif // BOOST_GEOMETRY_MULTI_HPP


text:
////////////////////////////////////////////////////////////////////////////////
//  Copyright (c) 2015 Bryce Adelstein Lelbach aka wash
//
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
////////////////////////////////////////////////////////////////////////////////

#include <mdspan>

#include <boost/core/lightweight_test.hpp>

using std::experimental::detail::is_integral_pack;

int main()
{
    BOOST_TEST_EQ((is_integral_pack<>::value), true);

    BOOST_TEST_EQ((is_integral_pack<int  >::value), true);
    BOOST_TEST_EQ((is_integral_pack<float>::value), false);

    BOOST_TEST_EQ((is_integral_pack<int  , int  , int  >::value), true);
    BOOST_TEST_EQ((is_integral_pack<float, int  , int  >::value), false);
    BOOST_TEST_EQ((is_integral_pack<int  , float, int  >::value), false);
    BOOST_TEST_EQ((is_integral_pack<int  , int  , float>::value), false);
    BOOST_TEST_EQ((is_integral_pack<float, float, float>::value), false);

    return boost::report_errors();
}


text:
//==============================================================================
//         Copyright 2003 - 2012   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2012   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#include <boost/simd/preprocessor/stack_buffer.hpp>
#include <boost/simd/memory/is_aligned.hpp>

#include <nt2/sdk/unit/module.hpp>
#include <nt2/sdk/unit/tests/basic.hpp>
#include <nt2/sdk/unit/tests/relation.hpp>

NT2_TEST_CASE_TPL(stack_buffer, BOOST_SIMD_TYPES)
{
  using boost::simd::is_aligned;

  BOOST_SIMD_STACK_BUFFER( array, T, 13 );

  for(std::size_t i=0; i < 13; ++i) array[i] = T(i+1);
  for(std::size_t i=0; i < 13; ++i) NT2_TEST_EQUAL(array[i], T(i+1));
}

NT2_TEST_CASE_TPL(aligned_stack_buffer, BOOST_SIMD_TYPES)
{
  using boost::simd::is_aligned;

  BOOST_SIMD_ALIGNED_STACK_BUFFER( array, T, 13 );

  NT2_TEST( is_aligned(&array[ 0 ]) );
  for(std::size_t i=0; i < 13; ++i) array[i] = T(i+1);
  for(std::size_t i=0; i < 13; ++i) NT2_TEST_EQUAL(array[i], T(i+1));
}

NT2_TEST_CASE_TPL(scoped_buffer, BOOST_SIMD_TYPES)
{
  using boost::simd::is_aligned;

  BOOST_SIMD_SCOPED_STACK_BUFFER( array, T, 13 );

  for(std::size_t i=0; i < 13; ++i) array[i] = T(i+1);
  for(std::size_t i=0; i < 13; ++i) NT2_TEST_EQUAL(array[i], T(i+1));
}

NT2_TEST_CASE_TPL(aligned_scoped_buffer, BOOST_SIMD_TYPES)
{
  using boost::simd::is_aligned;

  BOOST_SIMD_ALIGNED_SCOPED_STACK_BUFFER( array, T, 13 );

  NT2_TEST( is_aligned(&array[ 0 ]) );
  for(std::size_t i=0; i < 13; ++i) array[i] = T(i+1);
  for(std::size_t i=0; i < 13; ++i) NT2_TEST_EQUAL(array[i], T(i+1));
}


text:
#include "image.hh"

#include <stdint.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"

#include <iomanip>
#include <sstream>
#include <string>

#include <boost/sort/spreadsort/spreadsort.hpp>

#include <cmath>

Image::Image(std::filesystem::path img_path)
{
  // TODO(ja-he): verify file existence, permissions, ... neatly

  uint8_t* rgb_image = stbi_load(
    img_path.c_str(), &this->width, &this->height, &this->n_channels, 3);
  if (n_channels != 3) {
    std::cerr << "WARNING (reading in image): number of channels in image is "
                 "not 3 but "
              << n_channels << std::endl;
  }

  Pixel* tmp = (Pixel*)rgb_image;
  this->img  = std::vector<Pixel>(tmp, tmp + this->width * this->height);

  stbi_image_free(rgb_image);
}

std::vector<Pixel>::const_iterator
Image::begin() const
{
  return this->img.cbegin();
};
std::vector<Pixel>::const_iterator
Image::end() const
{
  return this->img.cend();
};

const Pixel&
Image::at(size_t line, size_t pixel) const
{
  return this->img[(line * this->width) + (pixel)];
}

int
Image::get_width(void) const
{
  return this->width;
}
int
Image::get_height(void) const
{
  return this->height;
}
int
Image::get_n_channels(void) const
{
  return this->n_channels;
}

Point3D
Pixel::to_p3d(void) const
{
  return {
    (float)this->r,
    (float)this->g,
    (float)this->b,
  };
}

uint32_t
Pixel::to_uint(void) const
{
  return ((r << 16) | (g << 8) | b);
}

std::string
Pixel::to_hex(void) const
{
  std::stringstream ss;
  ss << '#';
  ss << std::hex;
  ss << std::setw(2) << std::setfill('0') << (uint32_t)(this->r);
  ss << std::setw(2) << std::setfill('0') << (uint32_t)(this->g);
  ss << std::setw(2) << std::setfill('0') << (uint32_t)(this->b);

  return ss.str();
}

float
pixel_distance(const Pixel& p1, const Pixel& p2)
{
  return std::sqrt(((p1.r - p2.r) * (p1.r - p2.r)) +
                   ((p1.g - p2.g) * (p1.g - p2.g)) +
                   ((p1.b - p2.b) * (p1.b - p2.b)));
}

std::set<Pixel>
Image::get_colors_set(void) const
{
  std::set<Pixel> colors;
  for (auto& color : img) {
    colors.insert(color);
  }
  return colors;
}

Pixel::operator uint32_t() const { return this->to_uint(); }

std::vector<Pixel>
Image::get_colors_vec(void) const
{
  std::vector<Pixel> colors{ img };

  // TODO(ja-he):
  //  - there is a possible performance gain here from eliding repetitive casts
  //  - the sort function only works because the type conversion to uint32_t is
  //    defined
  //  - if we type pun here (requires Pixel to be 4 bytes wide) we see decent
  //    performance gains (on small, unrepresentative sample data)
  //  => a custom implementation of radix sort for Pixel _should_ deliver
  //     performance gains.
  boost::sort::spreadsort::integer_sort(colors.begin(), colors.end());

  colors.erase(std::unique(colors.begin(), colors.end()), colors.end());

  return colors;
}

bool
operator<(const Pixel& a, const Pixel& b)
{
  uint32_t an = (a.r << 16) | (a.g << 8) | (a.b);
  uint32_t bn = (b.r << 16) | (b.g << 8) | (b.b);
  return an < bn;
}

bool
operator==(const Pixel& a, const Pixel& b)
{
  return (a.r == b.r && a.g == b.g && a.b == b.b);
}

max_stars_repo_name: ja-he/palette-grabber

max_issues_repo_name: ja-he/palette-grabber

max_forks_repo_name: ja-he/palette-grabber


text:
// Andrew Naplavkov

#ifndef BRIG_DATABASE_COMMAND_ALLOCATOR_HPP
#define BRIG_DATABASE_COMMAND_ALLOCATOR_HPP

#include <boost/utility.hpp>
#include <brig/database/command.hpp>

namespace brig { namespace database {

struct command_allocator : ::boost::noncopyable {
  virtual ~command_allocator()  {}
  /**
  @return operator new
  */
  virtual command* allocate() = 0;
}; // command_allocator

} } // brig::database

#endif // BRIG_DATABASE_COMMAND_ALLOCATOR_HPP

max_stars_repo_name: isadchenko/brig

max_issues_repo_name: isadchenko/brig

max_forks_repo_name: isadchenko/brig


text:
#pragma once

#include "Logic.hpp"
#include "QF_BV.hpp"
#include "Array.hpp"
#include "Cardinality.hpp"

#include <boost/mpl/joint_view.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/size.hpp>

namespace metaSMT {

  namespace _all_logic_tags {
    typedef boost::mpl::joint_view<
        logic::tag::Predicate_Tags
      , logic::QF_BV::tag::QF_BV_Tags
      >::type all_Tags1;

    typedef boost::mpl::joint_view<
        all_Tags1
      , logic::Array::tag::Array_Tags
      >::type all_Tags2;

    typedef boost::mpl::joint_view<
        all_Tags2
      , logic::cardinality::tag::Cardinality_Tags
      >::type all_Tags3;

    typedef boost::mpl::copy<
       all_Tags3
       , boost::mpl::back_inserter< boost::mpl::vector<> >
      >::type all_Tags;
    //BOOST_MPL_ASSERT_RELATION( boost::mpl::size<allTags>::value, ==, 1 );
  }

#if BOOST_VARIANT_VISITATION_UNROLLING_LIMIT < 58
#warning "BOOST_VARIANT_VISITATION_UNROLLING_LIMIT is too small!"
#warning "Visiting metaSMT::Tag (e.g., via boost::put(.)) may unexpectedly fail."
#warning "Try to include <metaSMT/support/default_visitation_unrolling_limit.hpp>."
#endif // BOOST_VARIANT_VISITATION_UNROLLING_LIMIT

  typedef boost::make_variant_over< _all_logic_tags::all_Tags >::type Tag;

} // namespace metaSMT

//  vim: ft=cpp:ts=2:sw=2:expandtab

max_stars_repo_name: voertler/metaSMT

max_issues_repo_name: voertler/metaSMT

max_forks_repo_name: voertler/metaSMT


text:
// Boost.Bimap
//
// Copyright (c) 2006-2007 Matias Capeletto
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

/// \file tags/support/is_tagged.hpp
/// \brief type_traits extension

#ifndef BOOST_BIMAP_TAGS_SUPPORT_IS_TAGGED_HPP
#define BOOST_BIMAP_TAGS_SUPPORT_IS_TAGGED_HPP

#if defined(_MSC_VER)
#pragma once
#endif

#include <boost/config.hpp>

#include <boost/mpl/bool.hpp>
#include <boost/bimap/tags/tagged.hpp>

/** \struct boost::bimaps::tags::support::is_tagged
\brief Type trait to check if a type is tagged.

\code
template< class Type >
struct is_tagged
{
    typedef {mpl::true_/mpl::false_} type;
};
\endcode

See also tagged.
                                                                                **/

#ifndef BOOST_BIMAP_DOXYGEN_WILL_NOT_PROCESS_THE_FOLLOWING_LINES

namespace boost {
namespace bimaps {
namespace tags {
namespace support {

// is_tagged metafunction

template< class Type >
struct is_tagged :
    ::boost::mpl::false_ {};

template< class Type, class Tag >
struct is_tagged< tagged< Type, Tag > > :
    ::boost::mpl::true_ {};

} // namespace support
} // namespace tags
} // namespace bimaps
} // namespace boost

#endif // BOOST_BIMAP_DOXYGEN_WILL_NOT_PROCESS_THE_FOLLOWING_LINES

#endif // BOOST_BIMAP_TAGS_SUPPORT_IS_TAGGED_HPP

max_stars_repo_name: rudylee/expo

max_issues_repo_name: rudylee/expo

max_forks_repo_name: rudylee/expo


text:
#include <string>
#include <iostream>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <aware/contact.hpp>
#include <aware/avahi/announce_socket.hpp>

void announced(const boost::system::error_code& error)
{
    std::cout << __PRETTY_FUNCTION__ << " error=" << error << std::endl;
}

int main(int argc, char *argv[])
{
    aware::contact::property_map_type properties;
    properties["mac"] = "11:22:33:44:55:66";
    boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 3834);
    aware::contact contact("This is an announcement", "announce", endpoint, properties);
    boost::asio::io_service io;
    aware::avahi::announce_socket announcer(io);
    announcer.async_announce(contact, announced);
    io.run();
    return 0;
}

max_stars_repo_name: xpgdk/aware

max_issues_repo_name: xpgdk/aware

max_forks_repo_name: xpgdk/aware