text:
//
// Created by skonrad on 24/11/18.
//

#define BOOST_TEST_MODULE StarwarsTests2

#include <boost/test/included/unit_test.hpp>
#include <boost/test/execution_monitor.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include "rebelfleet.h"
#include "imperialfleet.h"
#include "battle.h"
#include <cassert>
#include <iostream>

//class OldStrategy : public AttackTimeStrategy {
//public:
//    bool decide(Time currentTime) override {
//
//        for (Time i = 0; i * i <= currentTime; ++i) {
//            if (i * i == currentTime) {
//                return true;
//            }
//        }
//        return false;
//
//    }
//};

struct cout_redirect {
    cout_redirect( std::streambuf * new_buffer )
            : old( std::cout.rdbuf( new_buffer ) )
    { }

    ~cout_redirect( ) {
        std::cout.rdbuf( old );
    }

private:
    std::streambuf * old;
};

struct StarCruiserInfo {
    static constexpr int minSpeed = 99999;
    static constexpr int maxSpeed = 299795;
};

struct ExplorerInfo {
    static constexpr int minSpeed = 299796;
    static constexpr int maxSpeed = 2997960;
};

struct XWingInfo : public ExplorerInfo {
};

template<typename S>
bool testRebelConstruction(ShieldPoints shield, Speed speed) {
    S ship(shield, speed);

    return ship.getShield() == shield
           && ship.getSpeed() == speed;

}

template<typename S>
bool testRebelConstruction(ShieldPoints shield, Speed speed, AttackPower attackPower) {
    S ship(shield, speed, attackPower);

    return ship.getShield() == shield
           && ship.getSpeed() == speed
           && ship.getAttackPower() == attackPower;

}

template<typename S>
bool testEmpireConstruction(ShieldPoints shield, AttackPower attackPower) {
    S ship(shield, attackPower);

    return ship.getShield() == shield
           && ship.getAttackPower() == attackPower;
}

template<typename T>
bool checkDamageTake(T &ship, AttackPower dmg, ShieldPoints result) {
    ship.takeDamage(dmg);
    return ship.getShield() == result;
}

template<typename T>
bool checkDamageTake(T &&ship, AttackPower dmg, ShieldPoints result)  {
    ship.takeDamage(dmg);
    return ship.getShield() == result;
}

BOOST_AUTO_TEST_SUITE(ProvidedTests);

    BOOST_AUTO_TEST_CASE(example) {

        auto xwing = createXWing(100.0f, 300000.0f, 50.0f);
        //auto &xwing = *xwingP;

        auto explorer = createExplorer(150, 400000);
        //auto &explorer = *explorerP;

        auto cruiser = createStarCruiser(1234, 100000, 11);
        //auto &cruiser = *cruiserP;

        auto deathStar = createDeathStar(10000, 75);
        //auto &deathStar = *deathStarP;

        auto fighter = createTIEFighter(50, 9);
        //auto &fighter = *fighterP;

        auto destroyer = createImperialDestroyer(150, 20);
        //auto &destroyer = *destroyerP;

        auto battle = SpaceBattle::Builder()
                .startTime(1)
                .maxTime(23)
                .ship(deathStar)
                .ship(explorer)
                .ship(fighter)
                .ship(xwing)
                .build();

        BOOST_CHECK_EQUAL(battle.countRebelFleet(), 2);
        BOOST_CHECK_EQUAL(battle.countImperialFleet(), 2);

        battle.tick(2);
        BOOST_CHECK_EQUAL(battle.countRebelFleet(), 2);
        BOOST_CHECK_EQUAL(battle.countImperialFleet(), 2);

        battle.tick(1);
        BOOST_CHECK_EQUAL(battle.countRebelFleet(), 2);
        BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);

        battle.tick(4);
        BOOST_CHECK_EQUAL(battle.countRebelFleet(), 0);
        BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);

        {
            boost::test_tools::output_test_stream output;
            cout_redirect redir(output.rdbuf());

            for (int i =0; i < 5; ++i) {
                battle.tick(1);
            }
            BOOST_CHECK( output.is_equal( ("IMPERIUM WON\n"
                                           "IMPERIUM WON\n"
                                           "IMPERIUM WON\n"
                                           "IMPERIUM WON\n"
                                           "IMPERIUM WON\n") ) );
        }

    }

BOOST_AUTO_TEST_SUITE_END();

BOOST_AUTO_TEST_SUITE(Rebels);

    BOOST_AUTO_TEST_CASE(construction) {
        BOOST_CHECK((testRebelConstruction<StarCruiser>(100, StarCruiserInfo::minSpeed, 12)));
        BOOST_CHECK((testRebelConstruction<StarCruiser>(100, StarCruiserInfo::maxSpeed, 12)));

        BOOST_CHECK((testRebelConstruction<Explorer>(77, ExplorerInfo::minSpeed)));
        BOOST_CHECK((testRebelConstruction<Explorer>(24, ExplorerInfo::maxSpeed)));
        BOOST_CHECK((testRebelConstruction<XWing>(77, XWingInfo::minSpeed, 256)));
        BOOST_CHECK((testRebelConstruction<XWing>(24, XWingInfo::maxSpeed, 128)));
    }

    BOOST_AUTO_TEST_CASE(takeDamage) {
        BOOST_CHECK((checkDamageTake(StarCruiser(0, StarCruiserInfo::minSpeed, 12), 100, 0)));
        BOOST_CHECK((checkDamageTake(StarCruiser(1, StarCruiserInfo::minSpeed, 12), 100, 0)));
        BOOST_CHECK((checkDamageTake(StarCruiser(100, StarCruiserInfo::minSpeed, 12), 100, 0)));

        {
            StarCruiser ship(100, StarCruiserInfo::minSpeed, 42);
            BOOST_CHECK((checkDamageTake(ship, 8, 92)));
            BOOST_CHECK((checkDamageTake(ship, 42, 50)));
            BOOST_CHECK((checkDamageTake(ship, 999999, 0)));

        }

        {
            /* przechodzi na long long */
            Explorer ship(12.34, ExplorerInfo::minSpeed);
            BOOST_CHECK((checkDamageTake(ship, 0.12, 12.22)));
            BOOST_CHECK((checkDamageTake(ship, 1.10, 11.12)));
            BOOST_CHECK((checkDamageTake(ship, 999999.999999, 0.0)));
        }

    }

BOOST_AUTO_TEST_SUITE_END();

BOOST_AUTO_TEST_SUITE(Empire);

    BOOST_AUTO_TEST_CASE(construction) {
        BOOST_CHECK((testEmpireConstruction<DeathStar>(100, 12)));
        BOOST_CHECK((testEmpireConstruction<TIEFighter>(100, 12)));
    }

    BOOST_AUTO_TEST_CASE(takeDamage) {

        BOOST_CHECK((checkDamageTake(DeathStar(0, 12), 100, 0)));
        BOOST_CHECK((checkDamageTake(DeathStar(1, 12), 100, 0)));
        BOOST_CHECK((checkDamageTake(DeathStar(100, 12), 9, 91)));

        {
            DeathStar ship(100, 42);
            BOOST_CHECK((checkDamageTake(ship, 8, 92)));
            BOOST_CHECK((checkDamageTake(ship, 42, 50)));
            BOOST_CHECK((checkDamageTake(ship, 999999, 0)));

        }
    }

BOOST_AUTO_TEST_SUITE_END();

BOOST_AUTO_TEST_SUITE(Battle);

    BOOST_AUTO_TEST_CASE(time) {
        {
            auto xwing = createXWing(100.0f, 300000.0f, 50.0f);

            auto battle = SpaceBattle::Builder()
                    .startTime(0)
                    .maxTime(127)
                        .ship(xwing)
                        .build();

            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);

            {
                boost::test_tools::output_test_stream output;
                cout_redirect redir(output.rdbuf());

                for (int i =0; i < 5; ++i) {
                    battle.tick(1);
                }
                BOOST_CHECK( (output.is_equal( "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n" )) );

            }

            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);

        }

        {
            auto tie = createTIEFighter(100.0f, 50.0f);
            auto battle = SpaceBattle::Builder()
                    .maxTime(std::numeric_limits<short>::max())
//                    .strategy(AttackTimeStrategyPtr(new OldStrategy()))
                    .ship(tie)
                    .startTime(0)
                    .build();

            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);

            {
                boost::test_tools::output_test_stream output;
                cout_redirect redir(output.rdbuf());

                for (int i =0; i < 5; ++i) {
                    battle.tick(1);
                }
                BOOST_CHECK( (output.is_equal( "IMPERIUM WON\n"
                                               "IMPERIUM WON\n"
                                               "IMPERIUM WON\n"
                                               "IMPERIUM WON\n"
                                               "IMPERIUM WON\n" )) );

            }

            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);

        }

        {
            auto xwing = createXWing(10000000000.0f, 300000.0f, 0.0f);
            auto TIE = createTIEFighter(10000000000.0f, 0.0f);

            auto battle = SpaceBattle::Builder()
                    .ship(xwing)
                    .ship(TIE)
                    .startTime(0)
                    .maxTime(std::numeric_limits<char>::max())
                    .build();
            //std::cerr << std::numeric_limits<int>::max() << std::endl;

            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);

            for (int i = 0; i < 1000; ++i) {
                int jump = rand() % std::numeric_limits<char>::max();
                battle.tick(jump);
            }

            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);

        }

    }

    BOOST_AUTO_TEST_CASE(construction) {
        {
            auto battle = SpaceBattle::Builder()
                    .startTime(0)
                    .maxTime(std::numeric_limits<short>::max())
                    .build();

            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);

            {
                boost::test_tools::output_test_stream output;
                cout_redirect redir(output.rdbuf());

                for (int i =0; i < 5; ++i) {
                    battle.tick(i);
                }
                BOOST_CHECK( (output.is_equal( "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n" )) );

            }

            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);
        }

        {
            auto xwing = createXWing(100.0f, 300000.0f, 50.0f);
            auto explorer = createExplorer(150, 400000);
            auto cruiser = createStarCruiser(1234, 100000, 11);
            auto deathStar = createDeathStar(10000, 75);
            auto fighter = createTIEFighter(50, 9);
            //ImperialDestroyer<int> destroyer(150, 20);

            auto battle = SpaceBattle::Builder()
                    .startTime(1)
                    .ship(deathStar)
                    .ship(explorer)
                    .ship(fighter)
                    .ship(xwing)
                    .maxTime(23)
                    .build();

            {
                BOOST_CHECK_EQUAL(battle.countRebelFleet(), 2);
                BOOST_CHECK_EQUAL(battle.countImperialFleet(), 2);
            }
        }

        {
            auto xwing = createXWing(100.0f, 300000.0f, 50.0f);
            auto xwing2 = createXWing(0.0f, 300000.0f, 50.0f);
            auto explorer = createExplorer(150, 400000);
            auto explorer2 = createExplorer(0.0, 400000.0);
            auto cruiser = createStarCruiser(1234, 100000, 11);

            auto cruiser2 = createStarCruiser(0, 100000, 11);
            auto cruiser3 = createStarCruiser(1234, 100000, 11);
            auto deathStar = createDeathStar(10000, 75);
            auto fighter = createTIEFighter(50, 9);
            auto fighter2 = createTIEFighter(0, 9);
            auto destroyer = createImperialDestroyer(150, 20);
            auto destroyer2 = createImperialDestroyer(0, 20);//todo is this required?

            auto battle = SpaceBattle::Builder()
                    .startTime(20)
                    .ship(cruiser)
                    .ship(cruiser2)
                    .ship(cruiser3)
                    .ship(destroyer)
                    .ship(destroyer2)
                    .ship(deathStar)
                    .ship(explorer)
                    .ship(explorer2)
                    .ship(fighter)
                    .ship(fighter2)
                    .ship(xwing)
                    .ship(xwing2)
                    .maxTime(50)
                    .build();

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 3);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 4);

        }

    }

    void attack(std::shared_ptr<ImperialUnit> a, std::shared_ptr<RebelStarship> b) {
        b->beAttacked(*a);
//        a->attack(*b);
    }

    BOOST_AUTO_TEST_CASE(pair) {
        {
            auto xwing = createXWing(42, XWingInfo::minSpeed, 2);
            auto ds = createDeathStar(42, 3);
            attack(ds, xwing);
            BOOST_CHECK_EQUAL(ds->getShield(), 40);
            BOOST_CHECK_EQUAL(xwing->getShield(), 39);
        }

        {
            auto xwing = createXWing(42, XWingInfo::minSpeed, 2000);
            auto ds = createDeathStar(42, 2000);
            attack(ds, xwing);

            BOOST_CHECK_EQUAL(ds->getShield(), 0);
            BOOST_CHECK_EQUAL(xwing->getShield(), 0);
        }

        {
            auto xw = createXWing(100, XWingInfo::minSpeed, 1);
            auto sc = createStarCruiser(101, StarCruiserInfo::minSpeed, 2);
            auto ex = createExplorer(102, ExplorerInfo::minSpeed);

            auto ds = createDeathStar(103, 3);
            auto id = createImperialDestroyer(104, 4);
            auto tf = createTIEFighter(105, 5);

            attack(ds, xw);
            attack(ds, sc);
            attack(ds, ex);

            attack(id, xw);
            attack(id, sc);
            attack(id, ex);

            attack(tf, xw);
            attack(tf, sc);
            attack(tf, ex);

            auto tf2 = createTIEFighter(105, 5);
            auto tf3 = createTIEFighter(100, 5);

            auto xw2 = createXWing(100, XWingInfo::minSpeed, 1);

            auto squadron = createSquadron({tf2, tf3});

            attack(squadron, xw2);

            BOOST_CHECK_EQUAL(xw2->getShield(), 90);
            BOOST_CHECK_EQUAL(squadron->getShield(), 203);
            BOOST_CHECK_EQUAL(squadron->getAttackPower(), 10);

            auto xw3 = createXWing(100, XWingInfo::minSpeed, 100);

            attack(squadron, xw3);

            BOOST_CHECK_EQUAL(xw3->getShield(), 90);
            BOOST_CHECK_EQUAL(squadron->getShield(), 4);
            BOOST_CHECK_EQUAL(squadron->getAttackPower(), 5);

            BOOST_CHECK_EQUAL(xw->getShield(), 88);
            BOOST_CHECK_EQUAL(sc->getShield(), 89);
            BOOST_CHECK_EQUAL(ex->getShield(), 90);

            BOOST_CHECK_EQUAL(ds->getShield(), 100);
            BOOST_CHECK_EQUAL(id->getShield(), 101);
            BOOST_CHECK_EQUAL(tf->getShield(), 102);
        }

        {
            auto exp = createExplorer(42, ExplorerInfo::minSpeed);
            auto ds = createDeathStar(42, 2000);
            attack(ds, exp);

            BOOST_CHECK_EQUAL(ds->getShield(), 42);
            BOOST_CHECK_EQUAL(exp->getShield(), 0);
        }

    }

    BOOST_AUTO_TEST_CASE(battles) {

        {

            auto xwing = createXWing(100, 300000, 50);
            auto xwing2 = createXWing(0.0f, 300000.0f, 50.0f);
            auto explorer = createExplorer(150, 400000);
            auto explorer2 = createExplorer(0.0, 400000.0);
            auto cruiser = createStarCruiser(123, 100000, 11);

            auto cruiser2 = createStarCruiser(0, 100000, 11);
            auto cruiser3 = createStarCruiser(1234, 100000, 11);
            auto deathStar = createDeathStar(100, 75);
            auto fighter = createTIEFighter(50, 9);
            auto fighter2 = createTIEFighter(0, 9);
            auto destroyer = createImperialDestroyer(150, 20);
            auto destroyer2 = createImperialDestroyer(0, 20);

            auto battle = SpaceBattle::Builder()
                    .startTime(0)
                    .ship(xwing2)
                    .ship(fighter2)
                    .ship(explorer2)
                    .ship(cruiser2)
                    .ship(destroyer2)

                    .ship(xwing)
                    .ship(explorer)
                    .ship(cruiser)
                    .ship(cruiser3)
                    .ship(deathStar)
                    .ship(fighter)
                    .ship(destroyer)
                    .maxTime(0)
                    .build();

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 3);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 4);

            battle.tick(12);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 2);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 3);

            //todo co jak battle.tick(0)
            battle.tick(1);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 2);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

            battle.tick(1);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

            battle.tick(1);
            battle.tick(1);
            battle.tick(1);
            battle.tick(1);
            battle.tick(1);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

            battle.tick(1);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

            {
                boost::test_tools::output_test_stream output;
                cout_redirect redir(output.rdbuf());

                for (int i =0; i < 5; ++i) {
                    battle.tick(1);
                }
                BOOST_CHECK( (output.is_equal( "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n" )) );
            }

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

        }

        {
            auto xwing = createXWing(100, 300000, 50);
            auto xwing2 = createXWing(0.0f, 300000.0f, 50.0f);
            auto explorer = createExplorer(150, 400000);
            auto explorer2 = createExplorer(0.0, 400000.0);
            auto cruiser = createStarCruiser(123, 100000, 11);

            auto cruiser2 = createStarCruiser(0, 100000, 11);
            auto cruiser3 = createStarCruiser(1234, 100000, 11);
            auto deathStar = createDeathStar(100, 75);
            auto fighter = createTIEFighter(50, 9);
            auto fighter2 = createTIEFighter(0, 9);
            auto destroyer = createImperialDestroyer(150, 20);
            auto destroyer2 = createImperialDestroyer(0, 20);

            auto battle = SpaceBattle::Builder()
                    .startTime(0)
                    .ship(xwing2)
                    .ship(fighter2)
                    .ship(explorer2)
                    .ship(cruiser2)
                    .ship(destroyer2)

                    .ship(xwing)
                    .ship(explorer)
                    .ship(cruiser)
                    .ship(cruiser3)
                    .ship(deathStar)
                    .ship(fighter)
                    .ship(destroyer)
                    .maxTime(100)
                    .build();

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 3);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 4);

            battle.tick(0);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 2);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 3);

            //todo co jak battle.tick(0)
            battle.tick(0);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 2);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

            battle.tick(0);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

            battle.tick(0);
            battle.tick(0);
            battle.tick(0);
            battle.tick(0);
            battle.tick(0);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

            battle.tick(0);

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

            {
                boost::test_tools::output_test_stream output;
                cout_redirect redir(output.rdbuf());

                for (int i =0; i < 5; ++i) {
                    battle.tick(12);
                }
                BOOST_CHECK( (output.is_equal( "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n"
                                               "REBELLION WON\n" )) );
            }

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);

        }

        {
            auto xwing = createXWing(100.0f, 300000.0f, 150.0f);
            auto destroyer = createImperialDestroyer(150, 100);

            auto battle = SpaceBattle::Builder()
                    .startTime(0)
                    .ship(xwing)
                    .maxTime(5)
                    .ship(destroyer)
                    .build();

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);
            battle.tick(1);

            {
                boost::test_tools::output_test_stream output;
                cout_redirect redir(output.rdbuf());

                for (int i =0; i < 5; ++i) {
                    battle.tick(1);
                }
                BOOST_CHECK( (output.is_equal( "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n" )) );

            }

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 0);

            BOOST_CHECK_EQUAL(xwing->getShield(), 0.0f);
            BOOST_CHECK_EQUAL(destroyer->getShield(), 0);

        }

        {
            auto xwing = createXWing(300.0f, 300000.0f, 100.0f);
            auto destroyer = createImperialDestroyer(300, 100);

            auto battle = SpaceBattle::Builder()
                    .startTime(0)
                    .ship(xwing)
                    .maxTime(5)
                    .ship(destroyer)
                    .build();

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);
            battle.tick(1);
            battle.tick(4);
            battle.tick(1);
            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 1);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 1);
            battle.tick(1);

            {
                boost::test_tools::output_test_stream output;
                cout_redirect redir(output.rdbuf());

                for (int i =0; i < 5; ++i) {
                    battle.tick(1);
                }
                BOOST_CHECK( (output.is_equal( "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n"
                                               "DRAW\n" )) );

            }

            BOOST_CHECK_EQUAL(battle.countImperialFleet(), 0);
            BOOST_CHECK_EQUAL(battle.countRebelFleet(), 0);

        }
    }
BOOST_AUTO_TEST_SUITE_END();

max_stars_repo_path: Starwars 2/starwars2_unit_tests.cc

max_issues_repo_path: Starwars 2/starwars2_unit_tests.cc

max_forks_repo_path: Starwars 2/starwars2_unit_tests.cc


text:
// io2_test_vc10.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define TEST_IO_NEW

#define BOOST_FILESYSTEM_VERSION 2

#define _CRT_SECURE_NO_WARNINGS 1
#define _SCL_SECURE_NO_WARNINGS 1

#ifdef NDEBUG
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0
#endif

#include <stdio.h>
#include <tchar.h>

#include <string>

#include <iostream>

#include <boost/timer.hpp>
#include <boost/filesystem/convenience.hpp>

unsigned int counter = 0;

#ifdef TEST_IO_NEW

#include <boost/gil/extension/io_new/jpeg_read.hpp>

using namespace std;
using namespace boost;
using namespace gil;

namespace fs = boost::filesystem;

rgb8_image_t img = rgb8_image_t( 136, 98 );

void read_image( const fs::path& dir_path )
{
    if ( fs::is_directory( dir_path ) )
    {
        fs::directory_iterator end_iter;
        for( fs::directory_iterator dir_itr( dir_path )
            ; dir_itr != end_iter
            ; ++dir_itr
            )
        {
            if (    fs::is_regular( dir_itr->status() )
               && ( fs::extension   ( dir_itr->path() ) == ".jpg" )
               )
            {
                string filename = dir_itr->path().string();
                read_image( filename, img, jpeg_tag() );

                ++counter;
            }
            else if( is_directory(dir_itr->status()) )
            {
                read_image( dir_itr->path() );
            }
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    string in( "C:/chhenning/lots_of_jpegs/" );
    //string in( "C:/chhenning/few_jpegs/" );
    fs::path in_path = fs::system_complete( fs::path( in, fs::native ) );

    try
    {
        timer t;

        read_image( in_path );

        cout << "# files : " << counter     << endl;
        cout << "time    : " << t.elapsed() << " sec" << endl;
    }
    catch( std::exception& e )
    {
        cout << e.what() << endl;

        exit( 1 );
    }
}

#else

#include <io2\libjpeg_image.hpp>

using namespace std;
using namespace boost;
using namespace gil;

namespace fs = boost::filesystem;

rgb8_image_t img = rgb8_image_t( 136, 98 );

void read_image( const fs::path& dir_path )
{
    if ( fs::is_directory( dir_path ) )
    {
        fs::directory_iterator end_iter;
        for( fs::directory_iterator dir_itr( dir_path )
            ; dir_itr != end_iter
            ; ++dir_itr
            )
        {
            if (    fs::is_regular( dir_itr->status() )
               && ( fs::extension   ( dir_itr->path() ) == ".jpg" )
               )
            {
                string filename = dir_itr->path().string();
                libjpeg_image::read( filename.c_str(), img );

                ++counter;
            }
            else if( is_directory(dir_itr->status()) )
            {
                read_image( dir_itr->path() );
            }
        }
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    string in( "C:/chhenning/lots_of_jpegs/" );
    //string in( "C:/chhenning/few_jpegs/" );
    fs::path in_path = fs::system_complete( fs::path( in, fs::native ) );

    try
    {
        timer t;

        read_image( in_path );

        cout << "# files : " << counter     << endl;
        cout << "time    : " << t.elapsed() << " sec" << endl;
    }
    catch( std::exception& e )
    {
        cout << e.what() << endl;

        exit( 1 );
    }
}
#endif

ext: cpp

max_stars_repo_name: mloskot/workshop

max_issues_repo_name: mloskot/workshop

max_forks_repo_name: mloskot/workshop


text:
//          Copyright Oliver Kowalke 2009.
// 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)
//
#ifndef CLOCK_H
#define CLOCK_H

#include <algorithm>
#include <cstddef>
#include <numeric>
#include <vector>

#include <boost/assert.hpp>
#include <boost/chrono.hpp>
#include <boost/cstdint.hpp>

typedef boost::chrono::high_resolution_clock    clock_type;
typedef clock_type::duration                    duration_type;
typedef clock_type::time_point                  time_point_type;

struct clock_overhead
{
    boost::uint64_t operator()()
    {
        time_point_type start( clock_type::now() );
        return ( clock_type::now() - start).count();
    }
};

duration_type overhead_clock()
{
    std::size_t iterations( 10);
    std::vector< boost::uint64_t >  overhead( iterations, 0);
    for ( std::size_t i = 0; i < iterations; ++i)
        std::generate(
            overhead.begin(), overhead.end(),
            clock_overhead() );
    BOOST_ASSERT( overhead.begin() != overhead.end() );
    return duration_type( std::accumulate( overhead.begin(), overhead.end(), 0) / iterations);
}

#endif // CLOCK_H

ext: hpp

max_stars_repo_name: cpp-pm/boost

max_issues_repo_name: cpp-pm/boost

max_forks_repo_name: cpp-pm/boost


text:
/*
 * Network packet header
 *
 * This file is part of the "SoftPixel Engine" (Copyright (c) 2008 by Lukas Hermanns)
 * See "SoftPixelEngine.hpp" for license information.
 */

#ifndef __SP_NETWORK_PACKET_H__
#define __SP_NETWORK_PACKET_H__

#include "Base/spStandard.hpp"

#ifdef SP_COMPILE_WITH_NETWORKSYSTEM

#include "Framework/Network/spNetworkCore.hpp"
#include "Framework/Network/spNetworkStream.hpp"

#include <boost/shared_array.hpp>

namespace sp
{
namespace network
{

//! Reserved network packet descriptors for internal network communication. Don't use these values!
enum EReservedDescriptors
{
    DESCRIPTOR_CLIENT_JOIN = 1000,      //!< A client has joined the server. This packet will only be sent to the server.
    DESCRIPTOR_CLIENT_LEFT,             //!< A client has left the server. This packet will sent to each network member.
    DESCRIPTOR_INTRODUCE_CLIENT,        //!< Server introduces a new client who has joined.
    DESCRIPTOR_CONNECTION_ACCEPTED,     //!< Server accepted the connection of the new client who is about to join.
    DESCRIPTOR_SERVER_DISCONNECTED,     //!< Server has been disconnected. This results in a disconnection for each client.

    DESCRIPTOR_SESSION_REQUEST,         //!< Will be sent to 'scan' the network for open game sessions.
    DESCRIPTOR_SESSION_ANSWER,          //!< Answer from a sessions request.
};

/**
NetworkPacket is used as wrapping class around a packet which can be send and/or received over the network.
\ingroup group_network
*/
class SP_EXPORT NetworkPacket
{

    public:

        NetworkPacket(u32 Descriptor = 0);
        NetworkPacket(const NetworkPacket &Other);
        NetworkPacket(const void* Buffer, u32 BufferSize, u32 Descriptor = 0, bool isSetLowLevel = false);
        NetworkPacket(const io::stringc &String, u32 Descriptor = 0);
        //NetworkPacket(NetworkStreamPtr Stream);
        ~NetworkPacket();

        /* === Functions === */

        //! Returns the packet as a string but only if this packet is a null-terminated string.
        io::stringc getString() const;
        //! Returns true if the given string equals the network packet data as string.
        bool compareString(const io::stringc &Str) const;

        //! Sets the descriptor. The descriptor is used to identify the purpose of the packet when received by another network member.
        void setDescriptor(u32 Descriptor);
        //! Returns the descriptor.
        u32 getDescriptor() const;

        //! Sets the receiver IP address. This is only used for a client/server model.
        void setReceiverAddress(u32 IPAddress);
        //! Returns the receiver IP address. This is only used for a client/server model.
        u32 getReceiverAddress() const;

        /* === Inline functions === */

        //! Returns a byte (or rather char) pointer to the packet data.
        inline c8* getBuffer()
        {
            return Buffer_.get() + NetworkPacket::RESERVED_OFFSET;
        }
        inline const c8* getBuffer() const
        {
            return Buffer_.get() + NetworkPacket::RESERVED_OFFSET;
        }

        /**
        Returns a constant pointer to the real buffer. This is used internally
        and should not be used to get the buffer of transmitted network data. use "getBuffer" instead.
        \see getBuffer
        */
        inline const c8* getRealBuffer() const
        {
            return Buffer_.get();
        }
        /**
        Returns the real buffer size. This is the size (in bytes) of the
        actual network packet (including protocol information). This is used internally
        and should not be used to get the buffer size of send network data.
        \see getBufferSize
        */
        inline u32 getRealBufferSize() const
        {
            return LogicalBufferSize_ + NetworkPacket::RESERVED_OFFSET;
        }

        //! Returns the local buffer size. This is the size (in bytes) of the packet data field.
        inline u32 getBufferSize() const
        {
            return LogicalBufferSize_;
        }

    private:

        /* === Macros === */

        static const u32 RESERVED_OFFSET = sizeof(u32);

        /* === Functions === */

        void createBuffer(u32 Size);
        void createBufferNonOffset(u32 Size);

        /* === Members === */

        boost::shared_array<c8> Buffer_;    //!< Network packet buffer.
        u32 LogicalBufferSize_;             //!< Buffer size used for the data field (excluding protocol data fields).

};

} // /namespace network

} // /namespace sp

#endif

#endif

// ================================================================================

max_stars_repo_name: rontrek/softpixel

max_issues_repo_name: rontrek/softpixel

max_forks_repo_name: rontrek/softpixel


text:
// Copyright Maarten L. Hekkelman, Radboud University 2008-2013.
//        Copyright Maarten L. Hekkelman, 2014-2020
// 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 <set>

#include <boost/algorithm/string.hpp>

#include <zeep/xml/document.hpp>
#include <zeep/xml/xpath.hpp>

namespace ba = boost::algorithm;

namespace zeep::xml
{

const std::set<std::string> kEmptyHTMLElements{
	"area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"
};

// --------------------------------------------------------------------

void write_string(std::ostream& os, const std::string& s, bool escape_whitespace, bool escape_quot, bool trim, float version)
{
	bool last_is_space = false;

	auto sp = s.begin();
	auto se = s.end();

	while (sp < se)
	{
		auto sb = sp;

		unicode c;
		std::tie(c, sp) = get_first_char(sp);

		switch (c)
		{
			case '&':	os << "&";			last_is_space = false; break;
			case '<':	os << "<";			last_is_space = false; break;
			case '>':	os << ">";			last_is_space = false; break;
			case '\"':	if (escape_quot)		os << """; else os << static_cast<char>(c); last_is_space = false; break;
			case '\n':	if (escape_whitespace)	os << "
"; else os << static_cast<char>(c); last_is_space = true; break;
			case '\r':	if (escape_whitespace)	os << "
"; else os << static_cast<char>(c); last_is_space = false; break;
			case '\t':	if (escape_whitespace)	os << "	"; else os << static_cast<char>(c); last_is_space = false; break;
			case ' ':	if (not trim or not last_is_space) os << ' '; last_is_space = true; break;
			case 0:		throw exception("Invalid null character in XML content");
			default:	if (c >= 0x0A0 or (version == 1.0 ? is_valid_xml_1_0_char(c) : is_valid_xml_1_1_char(c)))
							for (auto ci = sb; ci < sp; ++ci)
								os << *ci;
						else
							os << "&#" << c << ';';
						last_is_space = false;
						break;
		}

		sb = sp;
	}
}

// --------------------------------------------------------------------

node::~node()
{
	// avoid deep recursion and stack overflows
	while (m_next != nullptr)
	{
		node* n = m_next;
		m_next = n->m_next;
		n->m_next = nullptr;
		delete n;
	}
}

element* node::root()
{
	element* result = nullptr;
	if (m_parent != nullptr)
		result = m_parent->root();
	return result;
}

const element* node::root() const
{
	const element* result = nullptr;
	if (m_parent != nullptr)
		result = m_parent->root();
	return result;
}

bool node::equals(const node* n) const
{
	assert(false);
	return n == this;
}

std::string node::lang() const
{
	std::string result;
	if (m_parent != nullptr)
		result = m_parent->lang();
	return result;
}

void node::insert_sibling(node* n, node* before)
{
	node* p = this;
	while (p->m_next != nullptr and p->m_next != before)
		p = p->m_next;

	if (p->m_next != before and before != nullptr)
		throw zeep::exception("before argument in insert_sibling is not valid");

	p->m_next = n;
	n->m_prev = p;
	n->m_parent = m_parent;
	n->m_next = before;

	if (before != nullptr)
		before->m_prev = n;

// #if DEBUG
// validate();
// n->validate();
// if (before) before->validate();
// #endif
}

void node::remove_sibling(node* n)
{
	assert (this != n);
	if (this == n)
		throw exception("inconsistent node tree");

	node* p = this;
	while (p != nullptr and p->m_next != n)
		p = p->m_next;

	if (p != nullptr and p->m_next == n)
	{
		p->m_next = n->m_next;
		if (p->m_next != nullptr)
			p->m_next->m_prev = p;
		n->m_next = n->m_prev = n->m_parent = nullptr;
	}
	else
		throw exception("remove for a node not found in the list");
}

void node::parent(element* n)
{
	assert(m_parent == nullptr);
	m_parent = n;
}

std::string node::get_qname() const
{
	return "";
}

std::string node::name() const
{
	std::string qn = get_qname();
	std::string::size_type s = qn.find(':');
	if (s != std::string::npos)
		qn.erase(0, s + 1);
	return qn;
}

std::string node::get_prefix() const
{
	std::string qn = get_qname();
	std::string::size_type s = qn.find(':');

	std::string p;

	if (s != std::string::npos)
		p = qn.substr(0, s);

	return p;
}

std::string node::get_ns() const
{
	std::string p = get_prefix();
	return namespace_for_prefix(p);
}

std::string node::namespace_for_prefix(const std::string& prefix) const
{
	std::string result;
	if (m_parent != nullptr)
		result = m_parent->namespace_for_prefix(prefix);
	return result;
}

std::pair<std::string,bool> node::prefix_for_namespace(const std::string& uri) const
{
	std::pair<std::string,bool> result{};
	if (m_parent != nullptr)
		result = m_parent->prefix_for_namespace(uri);
	return result;
}

std::string node::prefix_tag(const std::string& tag, const std::string& uri) const
{
	auto prefix = prefix_for_namespace(uri);
	return prefix.second ? prefix.first + ':' + tag : tag;
}

void node::validate()
{
	if (m_parent and dynamic_cast<element*>(this) != nullptr and
			(std::find_if(m_parent->m_nodes.begin(), m_parent->m_nodes.end(), [this](auto& i) { return &i == this; }) == m_parent->m_nodes.end()))
		throw exception("validation error: parent does not know node");
	if (m_next and m_next->m_prev != this)
		throw exception("validation error: m_next->m_prev != this");
	if (m_prev and m_prev->m_next != this)
		throw exception("validation error: m_prev->m_next != this");

	node* n = this;
	while (n != nullptr and n->m_next != this)
		n = n->m_next;
	if (n == this)
		throw exception("cycle in node list");

	n = this;
	while (n != nullptr and n->m_prev != this)
		n = n->m_prev;
	if (n == this)
		throw exception("cycle in node list");

	if (m_next)
		m_next->validate();
}

// --------------------------------------------------------------------
// comment

bool comment::equals(const node* n) const
{
	return
		dynamic_cast<const comment*>(n) != nullptr and
		m_text == static_cast<const comment*>(n)->m_text;
}

node* comment::clone() const
{
	return new comment(m_text);
}

node* comment::move()
{
	return new comment(std::move(*this));
}

void comment::write(std::ostream& os, format_info fmt) const
{
	// if (fmt.indent_width != 0)
	// 	os << std::endl << std::string(fmt.indent_width, ' ');

	if (not fmt.suppress_comments)
	{
		os << "<!--";

		bool lastWasHyphen = false;
		for (char ch: m_text)
		{
			if (ch == '-' and lastWasHyphen)
				os << ' ';

			os << ch;
			lastWasHyphen = ch == '-';

			// if (ch == '\n')
			// {
			// 	for (size_t i = 0; i < indent; ++i)
			// 		os << ' ';
			// }
		}

		os << "-->";

		if (fmt.indent_width != 0)
			os << std::endl;
	}
}

// --------------------------------------------------------------------
// processing_instruction

bool processing_instruction::equals(const node* n) const
{
	return
		dynamic_cast<const processing_instruction*>(n) != nullptr and
		m_text == static_cast<const processing_instruction*>(n)->m_text;
}

node* processing_instruction::clone() const
{
	return new processing_instruction(m_target, m_target);
}

node* processing_instruction::move()
{
	return new processing_instruction(std::move(*this));
}

void processing_instruction::write(std::ostream& os, format_info fmt) const
{
	if (fmt.indent)
		os << std::endl << std::string(fmt.indent_level * fmt.indent_width, ' ');

	os << "<?" << m_target << ' ' << m_text << "?>";

	if (fmt.indent != 0)
		os << std::endl;
}

// --------------------------------------------------------------------
// text

bool text::equals(const node* n) const
{
	bool result = false;
	auto t = dynamic_cast<const text*>(n);

	if (t != nullptr)
	{
		std::string text = m_text;
		ba::trim(text);

		std::string ttext = t->m_text;
		ba::trim(ttext);

		result = text == ttext;
	}

	return result;
}

bool text::is_space() const
{
	bool result = true;
	for (auto ch: m_text)
	{
		if (not (ch == ' ' or ch == '\t' or ch == '\n' or ch == '\r'))
		{
			result = false;
			break;
		}
	}
	return result;
}

node* text::clone() const
{
	return new text(m_text);
}

node* text::move()
{
	return new text(std::move(*this));
}

void text::write(std::ostream& os, format_info fmt) const
{
	write_string(os, m_text, fmt.escape_white_space, fmt.escape_double_quote, false, fmt.version);
}

// --------------------------------------------------------------------
// cdata

bool cdata::equals(const node* n) const
{
	return
		dynamic_cast<const cdata*>(n) != nullptr and
		m_text == static_cast<const cdata*>(n)->m_text;
}

node* cdata::clone() const
{
	return new cdata(m_text);
}

node* cdata::move()
{
	return new cdata(std::move(*this));
}

void cdata::write(std::ostream& os, format_info fmt) const
{
	if (fmt.indent)
		os << std::endl << std::string(fmt.indent_level * fmt.indent_width, ' ');

	os << "<![CDATA[" << m_text << "]]>";

	if (fmt.indent)
		os << std::endl;
}

// --------------------------------------------------------------------
// attribute

bool attribute::equals(const node* n) const
{
	bool result = false;
	const attribute* a = dynamic_cast<const attribute*>(n);

	if (a != nullptr)
	{
		result = m_qname == a->m_qname and
				 m_value == a->m_value;
	}
	return result;
}

std::string attribute::uri() const
{
	assert(is_namespace());
	if (not is_namespace())
		throw exception("Attribute is not a namespace");
	return m_value;
}

node* attribute::clone() const
{
	return new attribute(m_qname, m_value, m_id);
}

node* attribute::move()
{
	return new attribute(std::move(*this));
}

void attribute::write(std::ostream& os, format_info fmt) const
{
	if (fmt.indent_width != 0)
		os << std::endl << std::string(fmt.indent_width, ' ');
	else
		os << ' ';

	os << m_qname << "=\"";

	write_string(os, m_value, fmt.escape_white_space, true, false, fmt.version);

	os << '"';
}

// // --------------------------------------------------------------------
// // name_space

// bool name_space::equals(const node* n) const
// {
// 	bool result = false;
// 	const name_space* ns = dynamic_cast<const name_space*>(n);

// 	if (ns != nullptr)
// 		result = m_uri == ns->m_uri;

// 	return result;
// }

// node* name_space::clone() const
// {
// 	return new name_space(m_prefix, m_uri);
// }

// node* name_space::move()
// {
// 	return new name_space(std::move(*this));
// }

// void name_space::write(std::ostream& os, format_info fmt) const
// {
// 	if (fmt.indent_width != 0)
// 		os << std::endl << std::string(fmt.indent_width, ' ');
// 	else
// 		os << ' ';

// 	if (m_prefix.empty())
// 		os << "xmlns";
// 	else
// 		os << "xmlns:" << m_prefix;
// 	os << "=\"";

// 	write_string(os, m_uri, fmt.escape_white_space, false, fmt.version);

// 	os << '"';
// }

// --------------------------------------------------------------------
// element

element::element()
	: m_nodes(*this)
	, m_attributes(*this)
{
}

element::element(const std::string& qname)
	: m_qname(qname)
	, m_nodes(*this)
	, m_attributes(*this)
{
}

element::element(const std::string& qname, std::initializer_list<zeep::xml::attribute> attributes)
	: m_qname(qname)
	, m_nodes(*this)
	, m_attributes(*this)
{
	for (auto& a: attributes)
		set_attribute(a.get_qname(), a.value());
}

// copy constructor. Copy data and children, but not parent and sibling
element::element(const element& e)
	: m_qname(e.m_qname)
	, m_nodes(*this, e.m_nodes)
	, m_attributes(*this, e.m_attributes)
{
}

element::element(element&& e)
	: element()
{
	swap(e);
}

element& element::operator=(const element& e)
{
	if (this != &e)
	{
		m_nodes = e.m_nodes;
		m_attributes = e.m_attributes;
	}

	return *this;
}

element& element::operator=(element&& e)
{
	if (this != &e)
	{
		clear();
		swap(e);
	}

	return *this;
}

element::~element()
{
}

void element::swap(element& e) noexcept
{
	std::swap(m_qname, e.m_qname);
	m_nodes.swap(e.m_nodes);
	m_attributes.swap(e.m_attributes);
}

node* element::clone() const
{
	return new element(*this);
}

node* element::move()
{
	return new element(std::move(*this));
}

std::string element::lang() const
{
	std::string result;

	auto i = m_attributes.find("xml:lang");
	if (i != m_attributes.end())
		result = i->value();
	else if (m_parent != nullptr)
		result = m_parent->lang();

	return result;
}

std::string element::id() const
{
	std::string result;

	for (auto& a: m_attributes)
	{
		if (a.is_id())
		{
			result = a.value();
			break;
		}
	}

	return result;
}

std::string element::get_attribute(const std::string& qname) const
{
	std::string result;

	auto a = m_attributes.find(qname);
	if (a != m_attributes.end())
		result = a->value();

	return result;
}

void element::set_attribute(const std::string& qname, const std::string& value)
{
	m_attributes.emplace(qname, value);
}

bool element::equals(const node* n) const
{
	bool result = false;
	const element* e = dynamic_cast<const element*>(n);

	if (e != nullptr)
	{
		result = name() == e->name() and get_ns() == e->get_ns();

		const node* a = m_nodes.m_head;;
		const node* b = e->m_nodes.m_head;

		while (a != nullptr or b != nullptr)
		{
			if (a != nullptr and b != nullptr and a->equals(b))
			{
				a = a->m_next;
				b = b->m_next;
				continue;
			}

			const text* t;

			t = dynamic_cast<const text*>(a);
			if (t != nullptr and t->is_space())
			{
				a = a->m_next;
				continue;
			}

			t = dynamic_cast<const text*>(b);
			if (t != nullptr and t->is_space())
			{
				b = b->m_next;
				continue;
			}

			result = false;
			break;
		}

		result = result and ((a == nullptr) == (b == nullptr));

		if (result)
		{
			result = m_attributes == e->m_attributes;
			if (not result)
			{
				std::set<attribute> a(m_attributes.begin(), m_attributes.end());
				std::set<attribute> b(e->m_attributes.begin(), e->m_attributes.end());

				std::set<std::string> nsa, nsb;

				auto ai = a.begin(), bi = b.begin();
				for (;;)
				{
					if (ai == a.end() and bi == b.end())
						break;

					if (ai != a.end() and ai->is_namespace())
					{
						nsa.insert(ai->value());
						++ai;
						continue;
					}

					if (bi != b.end() and bi->is_namespace())
					{
						nsb.insert(bi->value());
						++bi;
						continue;
					}

					if (ai == a.end() or bi == b.end() or *ai++ != *bi++)
					{
						result = false;
						break;
					}
				}

				result = ai == a.end() and bi == b.end() and nsa == nsb;
			}
		}
	}

	return result;
}

void element::clear()
{
	m_nodes.clear();
	m_attributes.clear();
}

std::string element::get_content() const
{
	std::string result;

	for (auto& n: m_nodes)
	{
		auto t = dynamic_cast<const text*>(&n);
		if (t != nullptr)
			result += t->get_text();
	}

	return result;
}

void element::set_content(const std::string& s)
{
	// remove all existing text nodes (including cdata ones)
	for (auto n = m_nodes.begin(); n != m_nodes.end(); ++n)
	{
		if (dynamic_cast<text*>(&*n) != nullptr)
			n = m_nodes.erase(n);
	}

	// and add a new text node with the content
	m_nodes.insert(m_nodes.end(), text(s));
}

std::string element::str() const
{
	std::string result;

	for (auto& n: m_nodes)
		result += n.str();

	return result;
}

void element::add_text(const std::string& s)
{
	text* textNode = dynamic_cast<text*>(m_nodes.m_tail);

	if (textNode != nullptr and dynamic_cast<cdata*>(textNode) == nullptr)
		textNode->append(s);
	else
		m_nodes.emplace_back(text(s));
}

void element::set_text(const std::string& s)
{
	set_content(s);
}

void element::flatten_text()
{
	auto n = m_nodes.m_head;
	while (n != m_nodes.m_tail)
	{
		auto tn = dynamic_cast<text*>(n);
		if (tn == nullptr)
		{
			n = n->m_next;
			continue;
		}

		if (n->m_next == nullptr)	// should never happen
			break;

		auto ntn = dynamic_cast<text*>(n->m_next);
		if (ntn == nullptr)
		{
			n = n->m_next;
			continue;
		}

		tn->append(ntn->get_text());
		m_nodes.erase(n->m_next);
	}
}

void element::write(std::ostream& os, format_info fmt) const
{
	// if width is set, we wrap and indent the file
	size_t indentation = fmt.indent_level * fmt.indent_width;

	if (fmt.indent)
	{
		if (fmt.indent_level > 0)
			os << std::endl;
		os << std::string(indentation, ' ');
	}

	os << '<' << m_qname;

	// if the left flag is set, wrap and indent attributes as well
	auto attr_fmt = fmt;
	attr_fmt.indent_width = 0;

	for (auto& attr: attributes())
	{
		attr.write(os, attr_fmt);
		if (attr_fmt.indent_width == 0 and fmt.indent_attributes)
			attr_fmt.indent_width = indentation + 1 + m_qname.length() + 1;
	}

	if ((fmt.html and kEmptyHTMLElements.count(m_qname)) or
		(not fmt.html and fmt.collapse_tags and nodes().empty()))
		os << "/>";
	else
	{
		os << '>';
		auto sub_fmt = fmt;
		++sub_fmt.indent_level;

		bool wrote_element = false;
		for (auto& n: nodes())
		{
			n.write(os, sub_fmt);
			wrote_element = dynamic_cast<const element*>(&n) != nullptr;
		}

		if (wrote_element and fmt.indent != 0)
			os << std::endl << std::string(indentation, ' ');

		os << "</" << m_qname << '>';
	}
}

std::ostream& operator<<(std::ostream& os, const element& e)
{
	auto flags = os.flags({});
	auto width = os.width(0);

	format_info fmt;
	fmt.indent = width > 0;
	fmt.indent_width = width;
	fmt.indent_attributes = flags & std::ios_base::left;

	e.write(os, fmt);

	return os;
}

std::string element::namespace_for_prefix(const std::string& prefix) const
{
	std::string result;

	for (auto& a: m_attributes)
	{
		if (not a.is_namespace())
			continue;

		if (a.name() == "xmlns")
		{
			if (prefix.empty())
			{
				result = a.value();
				break;
			}
			continue;
		}

		if (a.name() == prefix)
		{
			result = a.value();
			break;
		}
	}

	if (result.empty() and dynamic_cast<element*>(m_parent) != nullptr)
		result = static_cast<element*>(m_parent)->namespace_for_prefix(prefix);

	return result;
}

std::pair<std::string,bool> element::prefix_for_namespace(const std::string& uri) const
{
	std::string result;
	bool found = false;

	for (auto& a: m_attributes)
	{
		if (not a.is_namespace())
			continue;

		if (a.value() == uri)
		{
			found = true;
			if (a.get_qname().length() > 6)
				result = a.get_qname().substr(6);
			break;
		}
	}

	if (not found and dynamic_cast<element*>(m_parent) != nullptr)
		std::tie(result, found) = static_cast<element*>(m_parent)->prefix_for_namespace(uri);

	return make_pair(result, found);
}

void element::move_to_name_space(const std::string& prefix, const std::string& uri,
	bool recursive, bool including_attributes)
{
	// first some sanity checks
	auto p = prefix_for_namespace(uri);
	if (p.second)
	{
		if (p.first != prefix)
			throw exception("Invalid prefix in move_to_name_space, already known as '" + p.first + "'");
	}
	else
	{
		bool set = false;
		for (auto& a: m_attributes)
		{
			if (not a.is_namespace())
				continue;

			if (a.get_qname().length() > 6 and a.get_qname().substr(6) == prefix)
			{
				set = true;
				a.value(uri);
				break;
			}
		}

		if (not set)
			m_attributes.emplace(prefix.empty() ? "xmlns" : "xmlns:" + prefix, uri);
	}

	set_qname(prefix, name());

	if (including_attributes)
	{
		// first process the namespace attributes...
		for (auto& attr: m_attributes)
		{
			if (not attr.is_namespace())
				continue;

			auto p = prefix_for_namespace(attr.uri());
			if (not p.second)
				attr.set_qname("xmlns", p.first);
		}

		// ... and then the others, makes sure the namespaces are known
		for (auto& attr: m_attributes)
		{
			if (attr.is_namespace())
				continue;

			auto ns = attr.get_ns();

			if (ns.empty())
				attr.set_qname(prefix + ':' + attr.name());
			else
			{
				auto p = prefix_for_namespace(ns);
				if (not p.second)
					throw exception("Cannot move element to new namespace, namespace not found: " + ns);
				attr.set_qname(p.first, attr.name());
			}
		}
	}

	if (recursive)
	{
		for (element& e: *this)
			e.move_to_name_space(prefix, uri, true, including_attributes);
	}
}

element_set element::find(const char *path) const
{
	return xpath(path).evaluate<element>(*this);
}

element* element::find_first(const char *path) const
{
	element_set s = xpath(path).evaluate<element>(*this);

	element *result = nullptr;
	if (not s.empty())
		result = s.front();
	return result;
}

void element::validate()
{
	node::validate();

	for (auto& n: nodes())
		n.validate();

	for (auto& a: attributes())
	{
		if (a.parent() != this)
			throw exception("validation error: attribute has incorrect parent");
	}
}

// --------------------------------------------------------------------

void fix_namespaces(element& e, element& source, element& dest)
{
	std::stack<xml::node*> s;

	s.push(&e);

	std::map<std::string,std::string> mapped;

	while (not s.empty())
	{
		auto e = s.top();
		s.pop();

		auto p = e->get_prefix();
		if (not p.empty())
		{
			if (mapped.count(p))
			{
				if (mapped[p] != p)
					e->set_qname(mapped[p], e->name());
			}
			else
			{
				auto ns = e->namespace_for_prefix(p);
				if (ns.empty())
					ns = source.namespace_for_prefix(p);

				auto dp = dest.prefix_for_namespace(ns);
				if (dp.second)
				{
					mapped[p] = dp.first;
					e->set_qname(dp.first, e->name());
				}
				else
				{
					mapped[p] = p;
					dest.attributes().emplace({ "xmlns:" + p, ns });
				}
			}
		}

		auto el = dynamic_cast<element*>(e);
		if (el == nullptr)
			continue;

		for (auto& c: *el)
			s.push(&c);

		for (auto& a: el->attributes())
			s.push(&a);
	}
}

}

max_stars_repo_name: genisysram/libzeep

max_issues_repo_name: genisysram/libzeep

max_forks_repo_name: genisysram/libzeep


text:
#include <aslam/common/pose-types.h>
#include <Eigen/Core>
#include <gtest/gtest.h>
#include <maplab-common/test/testing-entrypoint.h>
#include <vi-map/test/vi-map-generator.h>

#include "vi-map-helpers/vi-map-vertex-time-queries.h"

namespace vi_map_helpers {

pose_graph::VertexId getGroundTruthVertexIdClosestInTime(
    const int64_t query_timestamp_nanoseconds,
    const pose_graph::VertexIdList& vertex_ids, const vi_map::VIMap::Ptr& map) {
  CHECK(map);
  pose_graph::VertexId closest_vertex_id;
  closest_vertex_id.setInvalid();
  CHECK(!vertex_ids.empty());
  int64_t closest_timestamp_difference = std::numeric_limits<int64_t>::max();
  for (const pose_graph::VertexId& vertex_id : vertex_ids) {
    CHECK(vertex_id.isValid());
    const int64_t timestamp_nanoseconds =
        map->getVertex(vertex_id).getMinTimestampNanoseconds();

    const int64_t timestamp_difference_nanoseconds =
        std::abs(timestamp_nanoseconds - query_timestamp_nanoseconds);
    if (timestamp_difference_nanoseconds < closest_timestamp_difference) {
      closest_timestamp_difference = timestamp_difference_nanoseconds;
      closest_vertex_id = vertex_id;
    }
  }
  CHECK(closest_vertex_id.isValid());
  return closest_vertex_id;
}

pose_graph::VertexId getGroundTruthVertexIdClosestInTime(
    const int64_t query_timestamp_nanoseconds, const vi_map::VIMap::Ptr& map) {
  CHECK(map);
  pose_graph::VertexIdList vertex_ids;
  map->getAllVertexIds(&vertex_ids);
  return getGroundTruthVertexIdClosestInTime(query_timestamp_nanoseconds,
                                             vertex_ids, map);
}

pose_graph::VertexId getGroundTruthVertexIdClosestInTime(
    const int64_t query_timestamp_nanoseconds,
    const vi_map::MissionId& mission_id, const vi_map::VIMap::Ptr& map) {
  CHECK(map);
  CHECK(mission_id.isValid());
  pose_graph::VertexIdList vertex_ids;
  map->getAllVertexIdsInMission(mission_id, &vertex_ids);
  return getGroundTruthVertexIdClosestInTime(query_timestamp_nanoseconds,
                                             vertex_ids, map);
}

TEST(VertexTimeQueriesTest, TestTimeQueriesSingleAndMultiMission) {
  vi_map::VIMap::Ptr map(new vi_map::VIMap);
  const int kSeed = 42;
  vi_map::VIMapGenerator generator(*map, kSeed);

  std::unordered_map<pose_graph::VertexId, int64_t>
      vertex_id_to_timestamp_nanoseconds;

  std::default_random_engine random_number_engine(kSeed);
  std::uniform_int_distribution<int64_t> timestamp_distribution(0, 1e12);

  const vi_map::MissionId mission_id_1 = generator.createMission();
  CHECK(mission_id_1.isValid());

  const vi_map::MissionId mission_id_2 = generator.createMission();
  CHECK(mission_id_2.isValid());

  constexpr size_t kNumVerticesPerMission = 200u;

  for (size_t vertex_idx = 0u; vertex_idx < kNumVerticesPerMission;
       ++vertex_idx) {
    const aslam::Transformation T_M_I(aslam::Quaternion(),
                                      aslam::Position3D::Random());
    generator.createVertex(mission_id_1, T_M_I,
                           timestamp_distribution(random_number_engine));
  }

  for (size_t vertex_idx = 0u; vertex_idx < kNumVerticesPerMission;
       ++vertex_idx) {
    const aslam::Transformation T_M_I(aslam::Quaternion(),
                                      aslam::Position3D::Random());
    generator.createVertex(mission_id_2, T_M_I,
                           timestamp_distribution(random_number_engine));
  }

  generator.generateMap();

  VIMapVertexTimeQueries vertex_time_index(map);

  const size_t kNumQueries = 50u;

  for (size_t query_idx = 0u; query_idx < kNumQueries; ++query_idx) {
    const int64_t query_timestamp_nanoseconds =
        timestamp_distribution(random_number_engine);

    pose_graph::VertexId nn_vertex_id;
    vertex_time_index.getClosestVertexInTime(query_timestamp_nanoseconds,
                                             &nn_vertex_id);
    ASSERT_TRUE(nn_vertex_id.isValid());
    EXPECT_EQ(nn_vertex_id, getGroundTruthVertexIdClosestInTime(
                                query_timestamp_nanoseconds, map));
  }

  VIMapMissionsVertexTimeQueries mission_vertex_time_index(map);

  for (size_t query_idx = 0u; query_idx < kNumQueries; ++query_idx) {
    const int64_t query_timestamp_nanoseconds =
        timestamp_distribution(random_number_engine);

    pose_graph::VertexId nn_vertex_id;
    mission_vertex_time_index.getClosestVertexInTimeForMission(
        query_timestamp_nanoseconds, mission_id_1, &nn_vertex_id);
    ASSERT_TRUE(nn_vertex_id.isValid());
    EXPECT_EQ(nn_vertex_id,
              getGroundTruthVertexIdClosestInTime(query_timestamp_nanoseconds,
                                                  mission_id_1, map));
  }

  for (size_t query_idx = 0u; query_idx < kNumQueries; ++query_idx) {
    const int64_t query_timestamp_nanoseconds =
        timestamp_distribution(random_number_engine);

    pose_graph::VertexId nn_vertex_id;
    mission_vertex_time_index.getClosestVertexInTimeForMission(
        query_timestamp_nanoseconds, mission_id_2, &nn_vertex_id);
    ASSERT_TRUE(nn_vertex_id.isValid());
    EXPECT_EQ(nn_vertex_id,
              getGroundTruthVertexIdClosestInTime(query_timestamp_nanoseconds,
                                                  mission_id_2, map));
  }
}

}  // namespace vi_map_helpers

MAPLAB_UNITTEST_ENTRYPOINT

ext: cc

max_stars_repo_name: AdronTech/maplab

max_issues_repo_name: AdronTech/maplab

max_forks_repo_name: AdronTech/maplab


text:
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation.  William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.

#include <boost/thread/condition.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/limits.hpp>
#include <cassert>
#include "timeconv.inl"

#if defined(BOOST_HAS_WINTHREADS)
#   ifndef NOMINMAX
#      define NOMINMAX
#   endif
#   include <windows.h>
#elif defined(BOOST_HAS_PTHREADS)
#   include <errno.h>
#elif defined(BOOST_HAS_MPTASKS)
#   include <MacErrors.h>
#   include "mac/init.hpp"
#   include "mac/safe.hpp"
#endif

namespace boost {

namespace detail {

#if defined(BOOST_HAS_WINTHREADS)
condition_impl::condition_impl()
    : m_gone(0), m_blocked(0), m_waiting(0)
{
    m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
    m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0,
                                                      std::numeric_limits<long>::max(),
                                                      0));
    m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));

    if (!m_gate || !m_queue || !m_mutex)
        {
            int res = 0;
            if (m_gate)
                {
                    res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
                    assert(res);
                }
            if (m_queue)
                {
                    res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
                    assert(res);
                }
            if (m_mutex)
                {
                    res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
                    assert(res);
                }

            throw thread_resource_error();
        }
}

condition_impl::~condition_impl()
{
    int res = 0;
    res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
    assert(res);
    res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
    assert(res);
    res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
    assert(res);
}

void condition_impl::notify_one()
{
    unsigned signals = 0;

    int res = 0;
    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
    assert(res == WAIT_OBJECT_0);

    if (m_waiting != 0) // the m_gate is already closed
        {
            if (m_blocked == 0)
                {
                    res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
                    assert(res);
                    return;
                }

            ++m_waiting;
            --m_blocked;
            signals = 1;
        }
    else
        {
            res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
            assert(res == WAIT_OBJECT_0);
            if (m_blocked > m_gone)
                {
                    if (m_gone != 0)
                        {
                            m_blocked -= m_gone;
                            m_gone = 0;
                        }
                    signals = m_waiting = 1;
                    --m_blocked;
                }
            else
                {
                    res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
                    assert(res);
                }
        }

    res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
    assert(res);

    if (signals)
        {
            res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
            assert(res);
        }
}

void condition_impl::notify_all()
{
    unsigned signals = 0;

    int res = 0;
    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
    assert(res == WAIT_OBJECT_0);

    if (m_waiting != 0) // the m_gate is already closed
        {
            if (m_blocked == 0)
                {
                    res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
                    assert(res);
                    return;
                }

            m_waiting += (signals = m_blocked);
            m_blocked = 0;
        }
    else
        {
            res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
            assert(res == WAIT_OBJECT_0);
            if (m_blocked > m_gone)
                {
                    if (m_gone != 0)
                        {
                            m_blocked -= m_gone;
                            m_gone = 0;
                        }
                    signals = m_waiting = m_blocked;
                    m_blocked = 0;
                }
            else
                {
                    res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
                    assert(res);
                }
        }

    res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
    assert(res);

    if (signals)
        {
            res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals,
                                   0);
            assert(res);
        }
}

void condition_impl::enter_wait()
{
    int res = 0;
    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
    assert(res == WAIT_OBJECT_0);
    ++m_blocked;
    res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
    assert(res);
}

void condition_impl::do_wait()
{
    int res = 0;
    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
    assert(res == WAIT_OBJECT_0);

    unsigned was_waiting=0;
    unsigned was_gone=0;

    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
    assert(res == WAIT_OBJECT_0);
    was_waiting = m_waiting;
    was_gone = m_gone;
    if (was_waiting != 0)
        {
            if (--m_waiting == 0)
                {
                    if (m_blocked != 0)
                        {
                            res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
                                                   0); // open m_gate
                            assert(res);
                            was_waiting = 0;
                        }
                    else if (m_gone != 0)
                        m_gone = 0;
                }
        }
    else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
        {
            // timeout occured, normalize the m_gone count
            // this may occur if many calls to wait with a timeout are made and
            // no call to notify_* is made
            res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
            assert(res == WAIT_OBJECT_0);
            m_blocked -= m_gone;
            res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
            assert(res);
            m_gone = 0;
        }
    res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
    assert(res);

    if (was_waiting == 1)
        {
            for (/**/ ; was_gone; --was_gone)
                {
                    // better now than spurious later
                    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
                                              INFINITE);
                    assert(res == WAIT_OBJECT_0);
                }
            res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
            assert(res);
        }
}

bool condition_impl::do_timed_wait(const xtime& xt)
{
    bool ret = false;
    unsigned int res = 0;

    for (;;)
        {
            int milliseconds;
            to_duration(xt, milliseconds);

            res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
                                      milliseconds);
            assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
            ret = (res == WAIT_OBJECT_0);

            if (res == WAIT_TIMEOUT)
                {
                    xtime cur;
                    xtime_get(&cur, TIME_UTC);
                    if (xtime_cmp(xt, cur) > 0)
                        continue;
                }

            break;
        }

    unsigned was_waiting=0;
    unsigned was_gone=0;

    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
    assert(res == WAIT_OBJECT_0);
    was_waiting = m_waiting;
    was_gone = m_gone;
    if (was_waiting != 0)
        {
            if (!ret) // timeout
                {
                    if (m_blocked != 0)
                        --m_blocked;
                    else
                        ++m_gone; // count spurious wakeups
                }
            if (--m_waiting == 0)
                {
                    if (m_blocked != 0)
                        {
                            res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
                                                   0); // open m_gate
                            assert(res);
                            was_waiting = 0;
                        }
                    else if (m_gone != 0)
                        m_gone = 0;
                }
        }
    else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
        {
            // timeout occured, normalize the m_gone count
            // this may occur if many calls to wait with a timeout are made and
            // no call to notify_* is made
            res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
            assert(res == WAIT_OBJECT_0);
            m_blocked -= m_gone;
            res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
            assert(res);
            m_gone = 0;
        }
    res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
    assert(res);

    if (was_waiting == 1)
        {
            for (/**/ ; was_gone; --was_gone)
                {
                    // better now than spurious later
                    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
                                              INFINITE);
                    assert(res ==  WAIT_OBJECT_0);
                }
            res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
            assert(res);
        }

    return ret;
}
#elif defined(BOOST_HAS_PTHREADS)
condition_impl::condition_impl()
{
    int res = 0;
    res = pthread_cond_init(&m_condition, 0);
    if (res != 0)
        throw thread_resource_error();
}

condition_impl::~condition_impl()
{
    int res = 0;
    res = pthread_cond_destroy(&m_condition);
    assert(res == 0);
}

void condition_impl::notify_one()
{
    int res = 0;
    res = pthread_cond_signal(&m_condition);
    assert(res == 0);
}

void condition_impl::notify_all()
{
    int res = 0;
    res = pthread_cond_broadcast(&m_condition);
    assert(res == 0);
}

void condition_impl::do_wait(pthread_mutex_t* pmutex)
{
    int res = 0;
    res = pthread_cond_wait(&m_condition, pmutex);
    assert(res == 0);
}

bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
{
    timespec ts;
    to_timespec(xt, ts);

    int res = 0;
    res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
    assert(res == 0 || res == ETIMEDOUT);

    return res != ETIMEDOUT;
}
#elif defined(BOOST_HAS_MPTASKS)

using threads::mac::detail::safe_enter_critical_region;
using threads::mac::detail::safe_wait_on_semaphore;

condition_impl::condition_impl()
    : m_gone(0), m_blocked(0), m_waiting(0)
{
    threads::mac::detail::thread_init();

    OSStatus lStatus = noErr;

    lStatus = MPCreateSemaphore(1, 1, &m_gate);
    if(lStatus == noErr)
        lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);

    if(lStatus != noErr || !m_gate || !m_queue)
        {
            if (m_gate)
                {
                    lStatus = MPDeleteSemaphore(m_gate);
                    assert(lStatus == noErr);
                }
            if (m_queue)
                {
                    lStatus = MPDeleteSemaphore(m_queue);
                    assert(lStatus == noErr);
                }

            throw thread_resource_error();
        }
}

condition_impl::~condition_impl()
{
    OSStatus lStatus = noErr;
    lStatus = MPDeleteSemaphore(m_gate);
    assert(lStatus == noErr);
    lStatus = MPDeleteSemaphore(m_queue);
    assert(lStatus == noErr);
}

void condition_impl::notify_one()
{
    unsigned signals = 0;

    OSStatus lStatus = noErr;
    lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
                                         m_mutex_mutex);
    assert(lStatus == noErr);

    if (m_waiting != 0) // the m_gate is already closed
        {
            if (m_blocked == 0)
                {
                    lStatus = MPExitCriticalRegion(m_mutex);
                    assert(lStatus == noErr);
                    return;
                }

            ++m_waiting;
            --m_blocked;
        }
    else
        {
            lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
            assert(lStatus == noErr);
            if (m_blocked > m_gone)
                {
                    if (m_gone != 0)
                        {
                            m_blocked -= m_gone;
                            m_gone = 0;
                        }
                    signals = m_waiting = 1;
                    --m_blocked;
                }
            else
                {
                    lStatus = MPSignalSemaphore(m_gate);
                    assert(lStatus == noErr);
                }

            lStatus = MPExitCriticalRegion(m_mutex);
            assert(lStatus == noErr);

            while (signals)
                {
                    lStatus = MPSignalSemaphore(m_queue);
                    assert(lStatus == noErr);
                    --signals;
                }
        }
}

void condition_impl::notify_all()
{
    unsigned signals = 0;

    OSStatus lStatus = noErr;
    lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
                                         m_mutex_mutex);
    assert(lStatus == noErr);

    if (m_waiting != 0) // the m_gate is already closed
        {
            if (m_blocked == 0)
                {
                    lStatus = MPExitCriticalRegion(m_mutex);
                    assert(lStatus == noErr);
                    return;
                }

            m_waiting += (signals = m_blocked);
            m_blocked = 0;
        }
    else
        {
            lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
            assert(lStatus == noErr);
            if (m_blocked > m_gone)
                {
                    if (m_gone != 0)
                        {
                            m_blocked -= m_gone;
                            m_gone = 0;
                        }
                    signals = m_waiting = m_blocked;
                    m_blocked = 0;
                }
            else
                {
                    lStatus = MPSignalSemaphore(m_gate);
                    assert(lStatus == noErr);
                }

            lStatus = MPExitCriticalRegion(m_mutex);
            assert(lStatus == noErr);

            while (signals)
                {
                    lStatus = MPSignalSemaphore(m_queue);
                    assert(lStatus == noErr);
                    --signals;
                }
        }
}

void condition_impl::enter_wait()
{
    OSStatus lStatus = noErr;
    lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
    assert(lStatus == noErr);
    ++m_blocked;
    lStatus = MPSignalSemaphore(m_gate);
    assert(lStatus == noErr);
}

void condition_impl::do_wait()
{
    OSStatus lStatus = noErr;
    lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
    assert(lStatus == noErr);

    unsigned was_waiting=0;
    unsigned was_gone=0;

    lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
                                         m_mutex_mutex);
    assert(lStatus == noErr);
    was_waiting = m_waiting;
    was_gone = m_gone;
    if (was_waiting != 0)
        {
            if (--m_waiting == 0)
                {
                    if (m_blocked != 0)
                        {
                            lStatus = MPSignalSemaphore(m_gate); // open m_gate
                            assert(lStatus == noErr);
                            was_waiting = 0;
                        }
                    else if (m_gone != 0)
                        m_gone = 0;
                }
        }
    else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
        {
            // timeout occured, normalize the m_gone count
            // this may occur if many calls to wait with a timeout are made and
            // no call to notify_* is made
            lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
            assert(lStatus == noErr);
            m_blocked -= m_gone;
            lStatus = MPSignalSemaphore(m_gate);
            assert(lStatus == noErr);
            m_gone = 0;
        }
    lStatus = MPExitCriticalRegion(m_mutex);
    assert(lStatus == noErr);

    if (was_waiting == 1)
        {
            for (/**/ ; was_gone; --was_gone)
                {
                    // better now than spurious later
                    lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
                    assert(lStatus == noErr);
                }
            lStatus = MPSignalSemaphore(m_gate);
            assert(lStatus == noErr);
        }
}

bool condition_impl::do_timed_wait(const xtime& xt)
{
    int milliseconds;
    to_duration(xt, milliseconds);

    OSStatus lStatus = noErr;
    lStatus = safe_wait_on_semaphore(m_queue, milliseconds);
    assert(lStatus == noErr || lStatus == kMPTimeoutErr);

    bool ret = (lStatus == noErr);

    unsigned was_waiting=0;
    unsigned was_gone=0;

    lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
                                         m_mutex_mutex);
    assert(lStatus == noErr);
    was_waiting = m_waiting;
    was_gone = m_gone;
    if (was_waiting != 0)
        {
            if (!ret) // timeout
                {
                    if (m_blocked != 0)
                        --m_blocked;
                    else
                        ++m_gone; // count spurious wakeups
                }
            if (--m_waiting == 0)
                {
                    if (m_blocked != 0)
                        {
                            lStatus = MPSignalSemaphore(m_gate); // open m_gate
                            assert(lStatus == noErr);
                            was_waiting = 0;
                        }
                    else if (m_gone != 0)
                        m_gone = 0;
                }
        }
    else if (++m_gone == (std::numeric_limits<unsigned>::max() / 2))
        {
            // timeout occured, normalize the m_gone count
            // this may occur if many calls to wait with a timeout are made and
            // no call to notify_* is made
            lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
            assert(lStatus == noErr);
            m_blocked -= m_gone;
            lStatus = MPSignalSemaphore(m_gate);
            assert(lStatus == noErr);
            m_gone = 0;
        }
    lStatus = MPExitCriticalRegion(m_mutex);
    assert(lStatus == noErr);

    if (was_waiting == 1)
        {
            for (/**/ ; was_gone; --was_gone)
                {
                    // better now than spurious later
                    lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
                    assert(lStatus == noErr);
                }
            lStatus = MPSignalSemaphore(m_gate);
            assert(lStatus == noErr);
        }

    return ret;
}
#endif

} // namespace detail

} // namespace boost

// Change Log:
//    8 Feb 01  WEKEMPF Initial version.
//   22 May 01  WEKEMPF Modified to use xtime for time outs.
//    3 Jan 03  WEKEMPF Modified for DLL implementation.