<commit_before>#include <string>

#include <nds.h>
#include <nds/debug.h>

#include "./math.h"
#include "./sprite.h"
#include "./debug.h"

namespace FMAW {

//------------------------------------------------------------------------------
// Common sprite helpers.
//------------------------------------------------------------------------------

void clearAllSprites() {
    for ( sprite_id id = 0; id < TOTAL_SPRITES; id++ ) {
        Sprite sprite (id);
        sprite.clear();
    }
}

//------------------------------------------------------------------------------
// Sprite class.
//------------------------------------------------------------------------------

uint8 Sprite::nextEmptySprite = 0;

//----------//------------------------------------------------------------------
//----------// Position.
//----------//------------------------------------------------------------------

bool Sprite::setXPosition( int x ) {
    bool isNegative = x < 0;
    if ( isNegative ) x = -x;

    uint16 xCapped = x & 0x00FF;
    printf("X Original: %d New: %u", x, xCapped);
    if ( x != xCapped ) return false;

    // If x was negative we have to apply 2's complement.
    if ( isNegative ) x = twosComplement9B(x);

    // We have to set the upper part of the half-word to 1 so AND doesn't
    // break anything.
    x |= 0xFE00;
    // We have to set position's bits to 1 so we can then make an AND.
    sprites[this->id].attr1 |= 0x01FF;
    // Now we can set position with a simple AND.
    sprites[this->id].attr1 &= x;

    return true;
}

bool Sprite::setYPosition( int y ) {
    bool isNegative = y < 0;
    if ( isNegative ) y = -y;

    uint16 yCapped = y & 0x007F;
    printf("Y Original: %d New: %u", y, yCapped);
    if ( y != yCapped ) return false;

    // If x was negative we have to apply 2's complement.
    if ( isNegative ) y = twosComplement8B(y);

    // We have to set the upper part of the half-word to 1 so AND doesn't
    // break anything.
    y |= 0xFF00;
    // We have to set position's bits to 1 so we can then make an AND.
    sprites[this->id].attr0 |= 0x00FF;
    // Now we can set position with a simple AND.
    sprites[this->id].attr0 &= y;

    return true;
}

bool Sprite::setPosition( int x, int y ) {
    Point previousPosition = this->getPosition();
    if ( this->setXPosition( x ) && this->setYPosition( y ) ) return true;
    else {
        this->setXPosition( previousPosition.x );
        this->setYPosition( previousPosition.y );
        return false;
    }
    return true;
}

bool Sprite::setPosition( Point point ) {
    return this->setPosition( point.x, point.y );
}

int Sprite::getXPosition() {
    uint8 x = sprites[this->id].attr1 & 0x01FF;
    // If x-position was a negative number...
    if ( (x & 0x0100) != 0 ) return -twosComplement9B(x);
    return x;
}

int Sprite::getYPosition() {
    uint8 y = sprites[this->id].attr0 & 0x00FF;
    // If y-position was a negative number...
    if ( (y & 0x0080) != 0 ) return -twosComplement8B(y);
    return y;
}

Point Sprite::getPosition() {
    Point p {};
    p.x = this->getXPosition();
    p.y = this->getYPosition();
    return p;
}

//----------//------------------------------------------------------------------
//----------// Tile & palette settings.
//----------//------------------------------------------------------------------

bool Sprite::setTile( uint16 tileIndex ) {
    uint16 tileIndexCapped = tileIndex & 0x01FF;
    if ( tileIndex != tileIndexCapped ) return false;
    // We first set tile bits to 1 so we can apply an AND later.
    sprites[this->id].attr2 |= 0x01FF;
    // We apply and AND to set the bits properly.
    sprites[this->id].attr2 &= tileIndexCapped;
    return true;
}

uint16 Sprite::getTile() {
    return sprites[this->id].attr2 & 0x01FF;
}

bool Sprite::setPalette( uint8 paletteIndex ) {
    uint8 paletteIndexCapped = paletteIndex & 0x000F;
    if ( paletteIndex != paletteIndexCapped ) return false;
    // We first set tile bits to 1 so we can apply an AND later.
    sprites[this->id].attr2 |= 0xF000;
    // We apply and AND to set the bits properly.
    sprites[this->id].attr2 &= paletteIndexCapped << 12;
    return true;
}

uint8 Sprite::getPalette() {
    return (sprites[this->id].attr2 & 0xF000) >> 12;
}

//----------//------------------------------------------------------------------
//----------// Rotation & scale settings.
//----------//------------------------------------------------------------------

void Sprite::enableRotationAndScale() {
    sprites[this->id].attr0 |= 0x0100;
}

void Sprite::disableRotationAndScale() {
    sprites[this->id].attr0 &= 0xFEFF;
}

bool Sprite::rotationAndScaleAreEnabled() {
    return (sprites[this->id].attr0 & 0x0100) != 0 ;
}

bool Sprite::rotationAndScaleAreDisabled() {
    return !this->rotationAndScaleAreEnabled();
}

void Sprite::enableDoubleSize() {
    sprites[this->id].attr0 |= 0x0200;
}

void Sprite::disableDoubleSize() {
    sprites[this->id].attr0 &= 0xFDFF;
}

bool Sprite::doubleSizeEnabled() {
    return (sprites[this->id].attr0 = 0x0200) != 0;
}

bool Sprite::doubleSizeDisabled() {
    return !this->doubleSizeEnabled();
}

//----------//------------------------------------------------------------------
//----------// Object mode settings.
//----------//------------------------------------------------------------------

void Sprite::setObjectMode( SpriteObjectMode newMode ) {
    sprites[this->id].attr0 |= 0x0C00;
    sprites[this->id].attr0 &= newMode;
}

SpriteObjectMode Sprite::getObjectMode() {
    uint16 half_word = sprites[this->id].attr0 | 0xF3FF;

    switch (half_word) {
        case normal:
            return normal;
        case alpha_first_target:
            return normal;
        case add_to_window:
            return add_to_window;
        case bitmap:
            return bitmap;
        default:
            // This won't ever happen.
            return normal;
    }
}

//----------//------------------------------------------------------------------
//----------// Mosaic & color settings.
//----------//------------------------------------------------------------------

void Sprite::enableMosaic() {
    sprites[this->id].attr0 |= 0x1000;
}

void Sprite::disableMosaic() {
    sprites[this->id].attr0 &= 0xEFFF;
}

bool Sprite::mosaicIsEnabled() {
    return (sprites[this->id].attr0 & 0x1000) != 0;
}

bool Sprite::mosaicIsDisabled() {
    return !this->mosaicIsEnabled();
}

void Sprite::use16BitColors() {
    sprites[this->id].attr0 &= 0xDFFF;
}

void Sprite::use256BitColors() {
    sprites[this->id].attr0 |= 0x2000;
}

bool Sprite::isUsing16BitColors() {
    return (sprites[this->id].attr0 & 0x2000) != 0;
}

bool Sprite::isUsing256BitColors() {
    return !this->isUsing16BitColors();
}

//----------//------------------------------------------------------------------
//----------// Shape & size settings.
//----------//------------------------------------------------------------------

bool Sprite::setSizeMode( SpriteSizeMode newMode ) {
    uint16 attr0mask;
    uint16 attr1mask;

    switch ( newMode ) {
        case square8x8:
        case square16x16:
        case square32x32:
        case square64x64:
            attr0mask = 0x3FFF;
            break;
        case wide16x8:
        case wide32x8:
        case wide32x16:
        case wide64x32:
            attr0mask = 0x7FFF;
            break;
        case tall8x16:
        case tall8x32:
        case tall16x32:
        case tall32x64:
            attr0mask = 0xBFFF;
            break;
        default:
            return false;
    }

    switch ( newMode ) {
        case square8x8:
        case wide16x8:
        case tall8x16:
            attr1mask = 0x3FFF;
            break;
        case square16x16:
        case wide32x8:
        case tall8x32:
            attr1mask = 0x7FFF;
            break;

        case square32x32:
        case wide32x16:
        case tall16x32:
            attr1mask = 0xBFFF;
            break;
        case square64x64:
        case wide64x32:
        case tall32x64:
            attr1mask = 0xFFFF;
            break;
        default:
            return false;
    }

    // We first set the size bits to 1.
    sprites[this->id].attr0 |= 0XC000;
    sprites[this->id].attr1 |= 0XC000;
    // And then we apply the mask.
    sprites[this->id].attr0 &= attr0mask;
    sprites[this->id].attr1 &= attr1mask;

    return true;
}

SpriteSizeMode Sprite::getSizeMode() {
    uint16 shape = sprites[this->id].attr0 & 0xC000;
    uint16 size  = sprites[this->id].attr1 & 0xC000;
    SpriteSizeMode sizeMode;

    switch ( shape ) {
        // Square.
        case 0x0000:
            switch (size) {
                case 0x0000:
                    sizeMode = square8x8;
                    break;
                case 0x4000:
                    sizeMode = square16x16;
                    break;
                case 0x8000:
                    sizeMode = square32x32;
                    break;
                case 0xC000:
                    sizeMode = square64x64;
                    break;
                default:
                    sizeMode = unknown;
                    break;
            }
            break;
        // Wide.
        case 0x4000:
            switch (size) {
                case 0x0000:
                    sizeMode = wide16x8;
                    break;
                case 0x4000:
                    sizeMode = wide32x8;
                    break;
                case 0x8000:
                    sizeMode = wide32x16;
                    break;
                case 0xC000:
                    sizeMode = wide64x32;
                    break;
                default:
                    sizeMode = unknown;
                    break;
            }
            break;
        // Tall.
        case 0x8000:
            switch (size) {
                case 0x0000:
                    sizeMode = tall8x16;
                    break;
                case 0x4000:
                    sizeMode = tall8x32;
                    break;
                case 0x8000:
                    sizeMode = tall16x32;
                    break;
                case 0xC000:
                    sizeMode = tall32x64;
                    break;
                default:
                    sizeMode = unknown;
                    break;
            }
            break;
        // Not used.
        case 0xC000:
        default:
            sizeMode = unknown;
            break;
    }

    return sizeMode;
}

//----------//------------------------------------------------------------------
//----------// Flip settings.
//----------//------------------------------------------------------------------

void Sprite::enableHorizontalFlip() {
    this->disableRotationAndScale();
    sprites[this->id].attr1 |= 0x1000;
}

void Sprite::disableHorizontalFlip() {
    this->disableRotationAndScale();
    sprites[this->id].attr1 &= 0xEFFF;
}

// If rotation/scaling is disabled it'll return false.
bool Sprite::horizontalFlipIsEnabled() {
    if ( this->rotationAndScaleAreDisabled() )
        return false;
    return (sprites[this->id].attr1 & 0x1000) != 0;
}

// If rotation/scaling is disabled it'll return false.
// THIS IS NOT EQUIVALENT TO !horizontalFlipIsEnabled() !!
bool Sprite::horizontalFlipIsDisabled() {
    if ( this->rotationAndScaleAreDisabled() )
        return false;
    return (sprites[this->id].attr1 & 0x1000) == 0;
}

void Sprite::enableVerticalFlip() {
    sprites[this->id].attr1 |= 0x2000;
}

void Sprite::disableVerticalFlip() {
    sprites[this->id].attr1 &= 0xDFFF;
}

// If rotation/scaling is disabled it'll return false.
bool Sprite::verticalFlipIsEnabled() {
    if ( this->rotationAndScaleAreDisabled() )
        return false;
    return (sprites[this->id].attr1 & 0x2000) != 0;
}

// If rotation/scaling is disabled it'll return false.
// THIS IS NOT EQUIVALENT TO !verticalFlipIsEnabled() !!
bool Sprite::verticalFlipIsDisabled() {
    if ( this->rotationAndScaleAreDisabled() )
        return false;
    return (sprites[this->id].attr1 & 0x2000) == 0;
}

//----------//------------------------------------------------------------------
//----------// Priority settings.
//----------//------------------------------------------------------------------

void Sprite::setPriority( SpritePriority priority ) {
    sprites[this->id].attr2 |= 0x0C00;
    sprites[this->id].attr2 &= priority;
}

SpritePriority Sprite::getPriority() {
    uint16 half_word = sprites[this->id].attr2 | 0xF3FF;

    switch (half_word) {
        case spHIGHEST:
            return spHIGHEST;
        case spHIGH:
            return spHIGH;
        case spLOW:
            return spLOW;
        case spLOWEST:
            return spLOWEST;
        default:
            // This won't ever happen.
            return spHIGHEST;
    }
}

//----------//------------------------------------------------------------------
//----------// Other settings.
//----------//------------------------------------------------------------------

void Sprite::clear() {
    sprites[this->id].attr0 = ATTR0_DISABLED;
    sprites[this->id].attr1 = 0;
    sprites[this->id].attr2 = 0;
    sprites[this->id].affine_data = 0;
}

void Sprite::disable() {
    uint16 disableMask = 0xFEFF;
    sprites[this->id].attr0 &= disableMask;
}

void Sprite::enable() {
    uint16 enableMask = 0xFCFF;
    sprites[this->id].attr0 &= enableMask;
}

void Sprite::print() {
    FMAW::printf("%s\r\n  Sprite %u:%s\r\n|%s|",
                 "\r\n|----------------|", this->id, "\r\n|----------------|",
                 half_word_to_binary(sprites[this->id].attr0).c_str());
    FMAW::printf("|%s|\r\n|%s|",
                 half_word_to_binary(sprites[this->id].attr1).c_str(),
                 half_word_to_binary(sprites[this->id].attr2).c_str());
    FMAW::printf("|%s|\r\n%s",
                 half_word_to_binary(sprites[this->id].affine_data).c_str(),
                 "|----------------|");
}

}<commit_msg>Minor type change<commit_after>#include <string>

#include <nds.h>

#include "./math.h"
#include "./sprite.h"
#include "./debug.h"

namespace FMAW {

//------------------------------------------------------------------------------
// Common sprite helpers.
//------------------------------------------------------------------------------

void clearAllSprites() {
    for ( sprite_id id = 0; id < TOTAL_SPRITES; id++ ) {
        Sprite sprite (id);
        sprite.clear();
    }
}

//------------------------------------------------------------------------------
// Sprite class.
//------------------------------------------------------------------------------

sprite_id Sprite::nextEmptySprite = 0;

//----------//------------------------------------------------------------------
//----------// Position.
//----------//------------------------------------------------------------------

bool Sprite::setXPosition( int x ) {
    bool isNegative = x < 0;
    if ( isNegative ) x = -x;

    uint16 xCapped = x & 0x00FF;
    printf("X Original: %d New: %u", x, xCapped);
    if ( x != xCapped ) return false;

    // If x was negative we have to apply 2's complement.
    if ( isNegative ) x = twosComplement9B(x);

    // We have to set the upper part of the half-word to 1 so AND doesn't
    // break anything.
    x |= 0xFE00;
    // We have to set position's bits to 1 so we can then make an AND.
    sprites[this->id].attr1 |= 0x01FF;
    // Now we can set position with a simple AND.
    sprites[this->id].attr1 &= x;

    return true;
}

bool Sprite::setYPosition( int y ) {
    bool isNegative = y < 0;
    if ( isNegative ) y = -y;

    uint16 yCapped = y & 0x007F;
    printf("Y Original: %d New: %u", y, yCapped);
    if ( y != yCapped ) return false;

    // If x was negative we have to apply 2's complement.
    if ( isNegative ) y = twosComplement8B(y);

    // We have to set the upper part of the half-word to 1 so AND doesn't
    // break anything.
    y |= 0xFF00;
    // We have to set position's bits to 1 so we can then make an AND.
    sprites[this->id].attr0 |= 0x00FF;
    // Now we can set position with a simple AND.
    sprites[this->id].attr0 &= y;

    return true;
}

bool Sprite::setPosition( int x, int y ) {
    Point previousPosition = this->getPosition();
    if ( this->setXPosition( x ) && this->setYPosition( y ) ) return true;
    else {
        this->setXPosition( previousPosition.x );
        this->setYPosition( previousPosition.y );
        return false;
    }
    return true;
}

bool Sprite::setPosition( Point point ) {
    return this->setPosition( point.x, point.y );
}

int Sprite::getXPosition() {
    uint8 x = sprites[this->id].attr1 & 0x01FF;
    // If x-position was a negative number...
    if ( (x & 0x0100) != 0 ) return -twosComplement9B(x);
    return x;
}

int Sprite::getYPosition() {
    uint8 y = sprites[this->id].attr0 & 0x00FF;
    // If y-position was a negative number...
    if ( (y & 0x0080) != 0 ) return -twosComplement8B(y);
    return y;
}

Point Sprite::getPosition() {
    Point p {};
    p.x = this->getXPosition();
    p.y = this->getYPosition();
    return p;
}

//----------//------------------------------------------------------------------
//----------// Tile & palette settings.
//----------//------------------------------------------------------------------

bool Sprite::setTile( uint16 tileIndex ) {
    uint16 tileIndexCapped = tileIndex & 0x01FF;
    if ( tileIndex != tileIndexCapped ) return false;
    // We first set tile bits to 1 so we can apply an AND later.
    sprites[this->id].attr2 |= 0x01FF;
    // We apply and AND to set the bits properly.
    sprites[this->id].attr2 &= tileIndexCapped;
    return true;
}

uint16 Sprite::getTile() {
    return sprites[this->id].attr2 & 0x01FF;
}

bool Sprite::setPalette( uint8 paletteIndex ) {
    uint8 paletteIndexCapped = paletteIndex & 0x000F;
    if ( paletteIndex != paletteIndexCapped ) return false;
    // We first set tile bits to 1 so we can apply an AND later.
    sprites[this->id].attr2 |= 0xF000;
    // We apply and AND to set the bits properly.
    sprites[this->id].attr2 &= paletteIndexCapped << 12;
    return true;
}

uint8 Sprite::getPalette() {
    return (sprites[this->id].attr2 & 0xF000) >> 12;
}

//----------//------------------------------------------------------------------
//----------// Rotation & scale settings.
//----------//------------------------------------------------------------------

void Sprite::enableRotationAndScale() {
    sprites[this->id].attr0 |= 0x0100;
}

void Sprite::disableRotationAndScale() {
    sprites[this->id].attr0 &= 0xFEFF;
}

bool Sprite::rotationAndScaleAreEnabled() {
    return (sprites[this->id].attr0 & 0x0100) != 0 ;
}

bool Sprite::rotationAndScaleAreDisabled() {
    return !this->rotationAndScaleAreEnabled();
}

void Sprite::enableDoubleSize() {
    sprites[this->id].attr0 |= 0x0200;
}

void Sprite::disableDoubleSize() {
    sprites[this->id].attr0 &= 0xFDFF;
}

bool Sprite::doubleSizeEnabled() {
    return (sprites[this->id].attr0 = 0x0200) != 0;
}

bool Sprite::doubleSizeDisabled() {
    return !this->doubleSizeEnabled();
}

//----------//------------------------------------------------------------------
//----------// Object mode settings.
//----------//------------------------------------------------------------------

void Sprite::setObjectMode( SpriteObjectMode newMode ) {
    sprites[this->id].attr0 |= 0x0C00;
    sprites[this->id].attr0 &= newMode;
}

SpriteObjectMode Sprite::getObjectMode() {
    uint16 half_word = sprites[this->id].attr0 | 0xF3FF;

    switch (half_word) {
        case normal:
            return normal;
        case alpha_first_target:
            return normal;
        case add_to_window:
            return add_to_window;
        case bitmap:
            return bitmap;
        default:
            // This won't ever happen.
            return normal;
    }
}

//----------//------------------------------------------------------------------
//----------// Mosaic & color settings.
//----------//------------------------------------------------------------------

void Sprite::enableMosaic() {
    sprites[this->id].attr0 |= 0x1000;
}

void Sprite::disableMosaic() {
    sprites[this->id].attr0 &= 0xEFFF;
}

bool Sprite::mosaicIsEnabled() {
    return (sprites[this->id].attr0 & 0x1000) != 0;
}

bool Sprite::mosaicIsDisabled() {
    return !this->mosaicIsEnabled();
}

void Sprite::use16BitColors() {
    sprites[this->id].attr0 &= 0xDFFF;
}

void Sprite::use256BitColors() {
    sprites[this->id].attr0 |= 0x2000;
}

bool Sprite::isUsing16BitColors() {
    return (sprites[this->id].attr0 & 0x2000) != 0;
}

bool Sprite::isUsing256BitColors() {
    return !this->isUsing16BitColors();
}

//----------//------------------------------------------------------------------
//----------// Shape & size settings.
//----------//------------------------------------------------------------------

bool Sprite::setSizeMode( SpriteSizeMode newMode ) {
    uint16 attr0mask;
    uint16 attr1mask;

    switch ( newMode ) {
        case square8x8:
        case square16x16:
        case square32x32:
        case square64x64:
            attr0mask = 0x3FFF;
            break;
        case wide16x8:
        case wide32x8:
        case wide32x16:
        case wide64x32:
            attr0mask = 0x7FFF;
            break;
        case tall8x16:
        case tall8x32:
        case tall16x32:
        case tall32x64:
            attr0mask = 0xBFFF;
            break;
        default:
            return false;
    }

    switch ( newMode ) {
        case square8x8:
        case wide16x8:
        case tall8x16:
            attr1mask = 0x3FFF;
            break;
        case square16x16:
        case wide32x8:
        case tall8x32:
            attr1mask = 0x7FFF;
            break;

        case square32x32:
        case wide32x16:
        case tall16x32:
            attr1mask = 0xBFFF;
            break;
        case square64x64:
        case wide64x32:
        case tall32x64:
            attr1mask = 0xFFFF;
            break;
        default:
            return false;
    }

    // We first set the size bits to 1.
    sprites[this->id].attr0 |= 0XC000;
    sprites[this->id].attr1 |= 0XC000;
    // And then we apply the mask.
    sprites[this->id].attr0 &= attr0mask;
    sprites[this->id].attr1 &= attr1mask;

    return true;
}

SpriteSizeMode Sprite::getSizeMode() {
    uint16 shape = sprites[this->id].attr0 & 0xC000;
    uint16 size  = sprites[this->id].attr1 & 0xC000;
    SpriteSizeMode sizeMode;

    switch ( shape ) {
        // Square.
        case 0x0000:
            switch (size) {
                case 0x0000:
                    sizeMode = square8x8;
                    break;
                case 0x4000:
                    sizeMode = square16x16;
                    break;
                case 0x8000:
                    sizeMode = square32x32;
                    break;
                case 0xC000:
                    sizeMode = square64x64;
                    break;
                default:
                    sizeMode = unknown;
                    break;
            }
            break;
        // Wide.
        case 0x4000:
            switch (size) {
                case 0x0000:
                    sizeMode = wide16x8;
                    break;
                case 0x4000:
                    sizeMode = wide32x8;
                    break;
                case 0x8000:
                    sizeMode = wide32x16;
                    break;
                case 0xC000:
                    sizeMode = wide64x32;
                    break;
                default:
                    sizeMode = unknown;
                    break;
            }
            break;
        // Tall.
        case 0x8000:
            switch (size) {
                case 0x0000:
                    sizeMode = tall8x16;
                    break;
                case 0x4000:
                    sizeMode = tall8x32;
                    break;
                case 0x8000:
                    sizeMode = tall16x32;
                    break;
                case 0xC000:
                    sizeMode = tall32x64;
                    break;
                default:
                    sizeMode = unknown;
                    break;
            }
            break;
        // Not used.
        case 0xC000:
        default:
            sizeMode = unknown;
            break;
    }

    return sizeMode;
}

//----------//------------------------------------------------------------------
//----------// Flip settings.
//----------//------------------------------------------------------------------

void Sprite::enableHorizontalFlip() {
    this->disableRotationAndScale();
    sprites[this->id].attr1 |= 0x1000;
}

void Sprite::disableHorizontalFlip() {
    this->disableRotationAndScale();
    sprites[this->id].attr1 &= 0xEFFF;
}

// If rotation/scaling is disabled it'll return false.
bool Sprite::horizontalFlipIsEnabled() {
    if ( this->rotationAndScaleAreDisabled() )
        return false;
    return (sprites[this->id].attr1 & 0x1000) != 0;
}

// If rotation/scaling is disabled it'll return false.
// THIS IS NOT EQUIVALENT TO !horizontalFlipIsEnabled() !!
bool Sprite::horizontalFlipIsDisabled() {
    if ( this->rotationAndScaleAreDisabled() )
        return false;
    return (sprites[this->id].attr1 & 0x1000) == 0;
}

void Sprite::enableVerticalFlip() {
    sprites[this->id].attr1 |= 0x2000;
}

void Sprite::disableVerticalFlip() {
    sprites[this->id].attr1 &= 0xDFFF;
}

// If rotation/scaling is disabled it'll return false.
bool Sprite::verticalFlipIsEnabled() {
    if ( this->rotationAndScaleAreDisabled() )
        return false;
    return (sprites[this->id].attr1 & 0x2000) != 0;
}

// If rotation/scaling is disabled it'll return false.
// THIS IS NOT EQUIVALENT TO !verticalFlipIsEnabled() !!
bool Sprite::verticalFlipIsDisabled() {
    if ( this->rotationAndScaleAreDisabled() )
        return false;
    return (sprites[this->id].attr1 & 0x2000) == 0;
}

//----------//------------------------------------------------------------------
//----------// Priority settings.
//----------//------------------------------------------------------------------

void Sprite::setPriority( SpritePriority priority ) {
    sprites[this->id].attr2 |= 0x0C00;
    sprites[this->id].attr2 &= priority;
}

SpritePriority Sprite::getPriority() {
    uint16 half_word = sprites[this->id].attr2 | 0xF3FF;

    switch (half_word) {
        case spHIGHEST:
            return spHIGHEST;
        case spHIGH:
            return spHIGH;
        case spLOW:
            return spLOW;
        case spLOWEST:
            return spLOWEST;
        default:
            // This won't ever happen.
            return spHIGHEST;
    }
}

//----------//------------------------------------------------------------------
//----------// Other settings.
//----------//------------------------------------------------------------------

void Sprite::clear() {
    sprites[this->id].attr0 = ATTR0_DISABLED;
    sprites[this->id].attr1 = 0;
    sprites[this->id].attr2 = 0;
    sprites[this->id].affine_data = 0;
}

void Sprite::disable() {
    uint16 disableMask = 0xFEFF;
    sprites[this->id].attr0 &= disableMask;
}

void Sprite::enable() {
    uint16 enableMask = 0xFCFF;
    sprites[this->id].attr0 &= enableMask;
}

void Sprite::print() {
    FMAW::printf("%s\r\n  Sprite %u:%s\r\n|%s|",
                 "\r\n|----------------|", this->id, "\r\n|----------------|",
                 half_word_to_binary(sprites[this->id].attr0).c_str());
    FMAW::printf("|%s|\r\n|%s|",
                 half_word_to_binary(sprites[this->id].attr1).c_str(),
                 half_word_to_binary(sprites[this->id].attr2).c_str());
    FMAW::printf("|%s|\r\n%s",
                 half_word_to_binary(sprites[this->id].affine_data).c_str(),
                 "|----------------|");
}

}<|endoftext|>


<commit_before>/*
 * Copyright 2010-2020 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
 */

#include "bx_p.h"
#include <bx/thread.h>

#if BX_CONFIG_SUPPORTS_THREADING

#if BX_PLATFORM_WINDOWS && !BX_CRT_NONE
#	include <bx/string.h>
#endif

#if BX_CRT_NONE
#	include "crt0.h"
#elif  BX_PLATFORM_ANDROID \
	|| BX_PLATFORM_BSD     \
	|| BX_PLATFORM_HAIKU   \
	|| BX_PLATFORM_LINUX   \
	|| BX_PLATFORM_IOS     \
	|| BX_PLATFORM_OSX     \
	|| BX_PLATFORM_PS4     \
	|| BX_PLATFORM_RPI
#	include <pthread.h>
#	if defined(__FreeBSD__)
#		include <pthread_np.h>
#	endif
#	if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200)
#		include <sys/prctl.h>
#	endif // BX_PLATFORM_
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
#	include <windows.h>
#	include <limits.h>
#	include <errno.h>
#	if BX_PLATFORM_WINRT
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::System::Threading;
#	endif // BX_PLATFORM_WINRT
#endif // BX_PLATFORM_

namespace bx
{
	static AllocatorI* getAllocator()
	{
		static DefaultAllocator s_allocator;
		return &s_allocator;
	}

	struct ThreadInternal
	{
#if BX_CRT_NONE
		static int32_t threadFunc(void* _arg);
		int32_t m_handle;
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
		static DWORD WINAPI threadFunc(LPVOID _arg);
		HANDLE m_handle;
		DWORD  m_threadId;
#elif BX_PLATFORM_POSIX
		static void* threadFunc(void* _arg);
		pthread_t m_handle;
#endif // BX_PLATFORM_
	};

#if BX_CRT_NONE
	int32_t ThreadInternal::threadFunc(void* _arg)
	{
		Thread* thread = (Thread*)_arg;
		int32_t result = thread->entry();
		return result;
	}
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_XBOXONE \
	|| BX_PLATFORM_WINRT
	DWORD WINAPI ThreadInternal::threadFunc(LPVOID _arg)
	{
		Thread* thread = (Thread*)_arg;
		int32_t result = thread->entry();
		return result;
	}
#else
	void* ThreadInternal::threadFunc(void* _arg)
	{
		Thread* thread = (Thread*)_arg;
		union
		{
			void* ptr;
			int32_t i;
		} cast;
		cast.i = thread->entry();
		return cast.ptr;
	}
#endif // BX_PLATFORM_

	Thread::Thread()
		: m_fn(NULL)
		, m_userData(NULL)
		, m_queue(getAllocator() )
		, m_stackSize(0)
		, m_exitCode(kExitSuccess)
		, m_running(false)
	{
		BX_STATIC_ASSERT(sizeof(ThreadInternal) <= sizeof(m_internal) );

		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		ti->m_handle = INT32_MIN;
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
		ti->m_handle   = INVALID_HANDLE_VALUE;
		ti->m_threadId = UINT32_MAX;
#elif BX_PLATFORM_POSIX
		ti->m_handle = 0;
#endif // BX_PLATFORM_
	}

	Thread::~Thread()
	{
		if (m_running)
		{
			shutdown();
		}
	}

	bool Thread::init(ThreadFn _fn, void* _userData, uint32_t _stackSize, const char* _name)
	{
		BX_ASSERT(!m_running, "Already running!");

		m_fn = _fn;
		m_userData = _userData;
		m_stackSize = _stackSize;

		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		ti->m_handle = crt0::threadCreate(&ti->threadFunc, _userData, m_stackSize, _name);

		if (NULL == ti->m_handle)
		{
			return false;
		}
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_XBOXONE
		ti->m_handle = ::CreateThread(NULL
				, m_stackSize
				, (LPTHREAD_START_ROUTINE)ti->threadFunc
				, this
				, 0
				, NULL
				);
		if (NULL == ti->m_handle)
		{
			return false;
		}
#elif BX_PLATFORM_WINRT
		ti->m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);

		if (NULL == ti->m_handle)
		{
			return false;
		}

		auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
			{
				m_exitCode = ti->threadFunc(this);
				SetEvent(ti->m_handle);
			}
			, CallbackContext::Any
			);

		ThreadPool::RunAsync(workItemHandler, WorkItemPriority::Normal, WorkItemOptions::TimeSliced);
#elif BX_PLATFORM_POSIX
		int result;
		BX_UNUSED(result);

		pthread_attr_t attr;
		result = pthread_attr_init(&attr);
		BX_WARN(0 == result, "pthread_attr_init failed! %d", result);
		if (0 != result)
		{
			return false;
		}

		if (0 != m_stackSize)
		{
			result = pthread_attr_setstacksize(&attr, m_stackSize);
			BX_WARN(0 == result, "pthread_attr_setstacksize failed! %d", result);

			if (0 != result)
			{
				return false;
			}
		}

		result = pthread_create(&ti->m_handle, &attr, &ti->threadFunc, this);
		BX_WARN(0 == result, "pthread_attr_setschedparam failed! %d", result);
		if (0 != result)
		{
			return false;
		}
#else
#	error "Not implemented!"
#endif // BX_PLATFORM_

		m_running = true;
		m_sem.wait();

		if (NULL != _name)
		{
			setThreadName(_name);
		}

		return true;
	}

	void Thread::shutdown()
	{
		BX_ASSERT(m_running, "Not running!");
		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		crt0::threadJoin(ti->m_handle, NULL);
#elif BX_PLATFORM_WINDOWS
		WaitForSingleObject(ti->m_handle, INFINITE);
		GetExitCodeThread(ti->m_handle, (DWORD*)&m_exitCode);
		CloseHandle(ti->m_handle);
		ti->m_handle = INVALID_HANDLE_VALUE;
#elif BX_PLATFORM_WINRT || BX_PLATFORM_XBOXONE
		WaitForSingleObjectEx(ti->m_handle, INFINITE, FALSE);
		CloseHandle(ti->m_handle);
		ti->m_handle = INVALID_HANDLE_VALUE;
#elif BX_PLATFORM_POSIX
		union
		{
			void* ptr;
			int32_t i;
		} cast;
		pthread_join(ti->m_handle, &cast.ptr);
		m_exitCode = cast.i;
		ti->m_handle = 0;
#endif // BX_PLATFORM_

		m_running = false;
	}

	bool Thread::isRunning() const
	{
		return m_running;
	}

	int32_t Thread::getExitCode() const
	{
		return m_exitCode;
	}

	void Thread::setThreadName(const char* _name)
	{
		ThreadInternal* ti = (ThreadInternal*)m_internal;
		BX_UNUSED(ti);
#if BX_CRT_NONE
		BX_UNUSED(_name);
#elif  BX_PLATFORM_OSX \
	|| BX_PLATFORM_IOS
		pthread_setname_np(_name);
#elif (BX_CRT_GLIBC >= 21200) && ! BX_PLATFORM_HURD
		pthread_setname_np(ti->m_handle, _name);
#elif BX_PLATFORM_LINUX
		prctl(PR_SET_NAME,_name, 0, 0, 0);
#elif BX_PLATFORM_BSD
#	if defined(__NetBSD__)
		pthread_setname_np(ti->m_handle, "%s", (void*)_name);
#	else
		pthread_set_name_np(ti->m_handle, _name);
#	endif // defined(__NetBSD__)
#elif BX_PLATFORM_WINDOWS
		// Try to use the new thread naming API from Win10 Creators update onwards if we have it
		typedef HRESULT (WINAPI *SetThreadDescriptionProc)(HANDLE, PCWSTR);
		SetThreadDescriptionProc SetThreadDescription = bx::functionCast<SetThreadDescriptionProc>(
			  GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetThreadDescription")
			);
		if (SetThreadDescription)
		{
			uint32_t length = (uint32_t)bx::strLen(_name)+1;
			uint32_t size = length*sizeof(wchar_t);
			wchar_t* name = (wchar_t*)alloca(size);
			mbstowcs(name, _name, size-2);
			SetThreadDescription(ti->m_handle, name);
		}
#	if BX_COMPILER_MSVC
#		pragma pack(push, 8)
			struct ThreadName
			{
				DWORD  type;
				LPCSTR name;
				DWORD  id;
				DWORD  flags;
			};
#		pragma pack(pop)
			ThreadName tn;
			tn.type  = 0x1000;
			tn.name  = _name;
			tn.id    = ti->m_threadId;
			tn.flags = 0;

			__try
			{
				RaiseException(0x406d1388
						, 0
						, sizeof(tn)/4
						, reinterpret_cast<ULONG_PTR*>(&tn)
						);
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
			}
#	endif // BX_COMPILER_MSVC
#else
		BX_UNUSED(_name);
#endif // BX_PLATFORM_
	}

	void Thread::push(void* _ptr)
	{
		m_queue.push(_ptr);
	}

	void* Thread::pop()
	{
		void* ptr = m_queue.pop();
		return ptr;
	}

	int32_t Thread::entry()
	{
#if BX_PLATFORM_WINDOWS
		ThreadInternal* ti = (ThreadInternal*)m_internal;
		ti->m_threadId = ::GetCurrentThreadId();
#endif // BX_PLATFORM_WINDOWS

		m_sem.post();
		int32_t result = m_fn(this, m_userData);
		return result;
	}

	struct TlsDataInternal
	{
#if BX_CRT_NONE
#elif BX_PLATFORM_WINDOWS
		uint32_t m_id;
#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT)
		pthread_key_t m_id;
#endif // BX_PLATFORM_*
	};

#if BX_CRT_NONE
	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}

	void* TlsData::get() const
	{
		return NULL;
	}

	void TlsData::set(void* _ptr)
	{
		BX_UNUSED(_ptr);

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}
#elif BX_PLATFORM_WINDOWS
	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		ti->m_id = TlsAlloc();
		BX_ASSERT(TLS_OUT_OF_INDEXES != ti->m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BOOL result = TlsFree(ti->m_id);
		BX_ASSERT(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
	}

	void* TlsData::get() const
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		return TlsGetValue(ti->m_id);
	}

	void TlsData::set(void* _ptr)
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		TlsSetValue(ti->m_id, _ptr);
	}

#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT)

	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_key_create(&ti->m_id, NULL);
		BX_ASSERT(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_key_delete(ti->m_id);
		BX_ASSERT(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
	}

	void* TlsData::get() const
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		return pthread_getspecific(ti->m_id);
	}

	void TlsData::set(void* _ptr)
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_setspecific(ti->m_id, _ptr);
		BX_ASSERT(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
	}
#endif // BX_PLATFORM_*

} // namespace bx

#endif // BX_CONFIG_SUPPORTS_THREADING
<commit_msg>Fixed build.<commit_after>/*
 * Copyright 2010-2020 Branimir Karadzic. All rights reserved.
 * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
 */

#include "bx_p.h"
#include <bx/thread.h>

#if BX_CONFIG_SUPPORTS_THREADING

#if BX_PLATFORM_WINDOWS && !BX_CRT_NONE
#	include <bx/string.h>
#endif

#if BX_CRT_NONE
#	include "crt0.h"
#elif  BX_PLATFORM_ANDROID \
	|| BX_PLATFORM_BSD     \
	|| BX_PLATFORM_HAIKU   \
	|| BX_PLATFORM_LINUX   \
	|| BX_PLATFORM_IOS     \
	|| BX_PLATFORM_OSX     \
	|| BX_PLATFORM_PS4     \
	|| BX_PLATFORM_RPI
#	include <pthread.h>
#	if defined(__FreeBSD__)
#		include <pthread_np.h>
#	endif
#	if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200)
#		include <sys/prctl.h>
#	endif // BX_PLATFORM_
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
#	include <windows.h>
#	include <limits.h>
#	include <errno.h>
#	if BX_PLATFORM_WINRT
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::System::Threading;
#	endif // BX_PLATFORM_WINRT
#endif // BX_PLATFORM_

namespace bx
{
	static AllocatorI* getAllocator()
	{
		static DefaultAllocator s_allocator;
		return &s_allocator;
	}

	struct ThreadInternal
	{
#if BX_CRT_NONE
		static int32_t threadFunc(void* _arg);
		int32_t m_handle;
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
		static DWORD WINAPI threadFunc(LPVOID _arg);
		HANDLE m_handle;
		DWORD  m_threadId;
#elif BX_PLATFORM_POSIX
		static void* threadFunc(void* _arg);
		pthread_t m_handle;
#endif // BX_PLATFORM_
	};

#if BX_CRT_NONE
	int32_t ThreadInternal::threadFunc(void* _arg)
	{
		Thread* thread = (Thread*)_arg;
		int32_t result = thread->entry();
		return result;
	}
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_XBOXONE \
	|| BX_PLATFORM_WINRT
	DWORD WINAPI ThreadInternal::threadFunc(LPVOID _arg)
	{
		Thread* thread = (Thread*)_arg;
		int32_t result = thread->entry();
		return result;
	}
#else
	void* ThreadInternal::threadFunc(void* _arg)
	{
		Thread* thread = (Thread*)_arg;
		union
		{
			void* ptr;
			int32_t i;
		} cast;
		cast.i = thread->entry();
		return cast.ptr;
	}
#endif // BX_PLATFORM_

	Thread::Thread()
		: m_fn(NULL)
		, m_userData(NULL)
		, m_queue(getAllocator() )
		, m_stackSize(0)
		, m_exitCode(kExitSuccess)
		, m_running(false)
	{
		BX_STATIC_ASSERT(sizeof(ThreadInternal) <= sizeof(m_internal) );

		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		ti->m_handle = INT32_MIN;
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_WINRT   \
	|| BX_PLATFORM_XBOXONE
		ti->m_handle   = INVALID_HANDLE_VALUE;
		ti->m_threadId = UINT32_MAX;
#elif BX_PLATFORM_POSIX
		ti->m_handle = 0;
#endif // BX_PLATFORM_
	}

	Thread::~Thread()
	{
		if (m_running)
		{
			shutdown();
		}
	}

	bool Thread::init(ThreadFn _fn, void* _userData, uint32_t _stackSize, const char* _name)
	{
		BX_ASSERT(!m_running, "Already running!");

		m_fn = _fn;
		m_userData = _userData;
		m_stackSize = _stackSize;

		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		ti->m_handle = crt0::threadCreate(&ti->threadFunc, _userData, m_stackSize, _name);

		if (NULL == ti->m_handle)
		{
			return false;
		}
#elif  BX_PLATFORM_WINDOWS \
	|| BX_PLATFORM_XBOXONE
		ti->m_handle = ::CreateThread(NULL
				, m_stackSize
				, (LPTHREAD_START_ROUTINE)ti->threadFunc
				, this
				, 0
				, NULL
				);
		if (NULL == ti->m_handle)
		{
			return false;
		}
#elif BX_PLATFORM_WINRT
		ti->m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);

		if (NULL == ti->m_handle)
		{
			return false;
		}

		auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
			{
				m_exitCode = ti->threadFunc(this);
				SetEvent(ti->m_handle);
			}
			, CallbackContext::Any
			);

		ThreadPool::RunAsync(workItemHandler, WorkItemPriority::Normal, WorkItemOptions::TimeSliced);
#elif BX_PLATFORM_POSIX
		int result;
		BX_UNUSED(result);

		pthread_attr_t attr;
		result = pthread_attr_init(&attr);
		BX_WARN(0 == result, "pthread_attr_init failed! %d", result);
		if (0 != result)
		{
			return false;
		}

		if (0 != m_stackSize)
		{
			result = pthread_attr_setstacksize(&attr, m_stackSize);
			BX_WARN(0 == result, "pthread_attr_setstacksize failed! %d", result);

			if (0 != result)
			{
				return false;
			}
		}

		result = pthread_create(&ti->m_handle, &attr, &ti->threadFunc, this);
		BX_WARN(0 == result, "pthread_attr_setschedparam failed! %d", result);
		if (0 != result)
		{
			return false;
		}
#else
#	error "Not implemented!"
#endif // BX_PLATFORM_

		m_running = true;
		m_sem.wait();

		if (NULL != _name)
		{
			setThreadName(_name);
		}

		return true;
	}

	void Thread::shutdown()
	{
		BX_ASSERT(m_running, "Not running!");
		ThreadInternal* ti = (ThreadInternal*)m_internal;
#if BX_CRT_NONE
		crt0::threadJoin(ti->m_handle, NULL);
#elif BX_PLATFORM_WINDOWS
		WaitForSingleObject(ti->m_handle, INFINITE);
		GetExitCodeThread(ti->m_handle, (DWORD*)&m_exitCode);
		CloseHandle(ti->m_handle);
		ti->m_handle = INVALID_HANDLE_VALUE;
#elif BX_PLATFORM_WINRT || BX_PLATFORM_XBOXONE
		WaitForSingleObjectEx(ti->m_handle, INFINITE, FALSE);
		CloseHandle(ti->m_handle);
		ti->m_handle = INVALID_HANDLE_VALUE;
#elif BX_PLATFORM_POSIX
		union
		{
			void* ptr;
			int32_t i;
		} cast;
		pthread_join(ti->m_handle, &cast.ptr);
		m_exitCode = cast.i;
		ti->m_handle = 0;
#endif // BX_PLATFORM_

		m_running = false;
	}

	bool Thread::isRunning() const
	{
		return m_running;
	}

	int32_t Thread::getExitCode() const
	{
		return m_exitCode;
	}

	void Thread::setThreadName(const char* _name)
	{
		ThreadInternal* ti = (ThreadInternal*)m_internal;
		BX_UNUSED(ti);
#if BX_CRT_NONE
		BX_UNUSED(_name);
#elif  BX_PLATFORM_OSX \
	|| BX_PLATFORM_IOS
		pthread_setname_np(_name);
#elif (BX_CRT_GLIBC >= 21200) && ! BX_PLATFORM_HURD
		pthread_setname_np(ti->m_handle, _name);
#elif BX_PLATFORM_LINUX
		prctl(PR_SET_NAME,_name, 0, 0, 0);
#elif BX_PLATFORM_BSD
#	if defined(__NetBSD__)
		pthread_setname_np(ti->m_handle, "%s", (void*)_name);
#	else
		pthread_set_name_np(ti->m_handle, _name);
#	endif // defined(__NetBSD__)
#elif BX_PLATFORM_WINDOWS
		// Try to use the new thread naming API from Win10 Creators update onwards if we have it
		typedef HRESULT (WINAPI *SetThreadDescriptionProc)(HANDLE, PCWSTR);
		SetThreadDescriptionProc SetThreadDescription = bx::functionCast<SetThreadDescriptionProc>(
			  bx::dlsym(GetModuleHandleA("Kernel32.dll"), "SetThreadDescription")
			);
		if (SetThreadDescription)
		{
			uint32_t length = (uint32_t)bx::strLen(_name)+1;
			uint32_t size = length*sizeof(wchar_t);
			wchar_t* name = (wchar_t*)alloca(size);
			mbstowcs(name, _name, size-2);
			SetThreadDescription(ti->m_handle, name);
		}
#	if BX_COMPILER_MSVC
#		pragma pack(push, 8)
			struct ThreadName
			{
				DWORD  type;
				LPCSTR name;
				DWORD  id;
				DWORD  flags;
			};
#		pragma pack(pop)
			ThreadName tn;
			tn.type  = 0x1000;
			tn.name  = _name;
			tn.id    = ti->m_threadId;
			tn.flags = 0;

			__try
			{
				RaiseException(0x406d1388
						, 0
						, sizeof(tn)/4
						, reinterpret_cast<ULONG_PTR*>(&tn)
						);
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
			}
#	endif // BX_COMPILER_MSVC
#else
		BX_UNUSED(_name);
#endif // BX_PLATFORM_
	}

	void Thread::push(void* _ptr)
	{
		m_queue.push(_ptr);
	}

	void* Thread::pop()
	{
		void* ptr = m_queue.pop();
		return ptr;
	}

	int32_t Thread::entry()
	{
#if BX_PLATFORM_WINDOWS
		ThreadInternal* ti = (ThreadInternal*)m_internal;
		ti->m_threadId = ::GetCurrentThreadId();
#endif // BX_PLATFORM_WINDOWS

		m_sem.post();
		int32_t result = m_fn(this, m_userData);
		return result;
	}

	struct TlsDataInternal
	{
#if BX_CRT_NONE
#elif BX_PLATFORM_WINDOWS
		uint32_t m_id;
#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT)
		pthread_key_t m_id;
#endif // BX_PLATFORM_*
	};

#if BX_CRT_NONE
	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}

	void* TlsData::get() const
	{
		return NULL;
	}

	void TlsData::set(void* _ptr)
	{
		BX_UNUSED(_ptr);

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BX_UNUSED(ti);
	}
#elif BX_PLATFORM_WINDOWS
	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		ti->m_id = TlsAlloc();
		BX_ASSERT(TLS_OUT_OF_INDEXES != ti->m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() );
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		BOOL result = TlsFree(ti->m_id);
		BX_ASSERT(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result);
	}

	void* TlsData::get() const
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		return TlsGetValue(ti->m_id);
	}

	void TlsData::set(void* _ptr)
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		TlsSetValue(ti->m_id, _ptr);
	}

#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT)

	TlsData::TlsData()
	{
		BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) );

		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_key_create(&ti->m_id, NULL);
		BX_ASSERT(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result);
	}

	TlsData::~TlsData()
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_key_delete(ti->m_id);
		BX_ASSERT(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result);
	}

	void* TlsData::get() const
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		return pthread_getspecific(ti->m_id);
	}

	void TlsData::set(void* _ptr)
	{
		TlsDataInternal* ti = (TlsDataInternal*)m_internal;
		int result = pthread_setspecific(ti->m_id, _ptr);
		BX_ASSERT(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result);
	}
#endif // BX_PLATFORM_*

} // namespace bx

#endif // BX_CONFIG_SUPPORTS_THREADING
<|endoftext|>


<commit_before>#pragma once

#include "render/target.hpp"
#include "gui/gui.hpp"

namespace ve
{
	class render::Target;
	class Gui;

	class Window final
	{
	public:
		// Construct the window.
		Window();

		// Destruct the window.
		~Window();

		// Returns the gui.
		Ptr<Gui> getGui() const;

		// Sets the function to be called when the user has requested to close the window.
		void setCloseRequestedHandler(std::function<void()> closeRequestedHandler);

		// Internal. Gets the SDL Window handle.
		void * getSDLWindow() const;

		// Internal. Called when the user clicks the close button on the window or equivalent shortcut.
		void onCloseRequested();

		// Internal. Called when the user resizes the window.
		void onResized(Vector2i size);

		// Internal. Called when the user moves the cursor within the window or out of the window.
		void onCursorPositionChanged(std::optional<Vector2i> cursorPosition);

		// Internal. Updates the window and the contained gui.
		void update(float dt);

		// Internal. Called to render the window.
		void render() const;

	private:
		void * sdlWindow;
		std::function<void()> closeRequestedHandler;
		OwnPtr<render::WindowTarget> target;
		std::optional<Vector2i> cursorPosition;
		OwnPtr<Gui> gui;
	};
}<commit_msg>Fixed Window comments<commit_after>#pragma once

#include "render/target.hpp"
#include "gui/gui.hpp"

namespace ve
{
	class render::Target;
	class Gui;

	class Window final
	{
	public:
		// Construct the window.
		Window();

		// Destruct the window.
		~Window();

		// Returns the gui.
		Ptr<Gui> getGui() const;

		// Sets the function to be called when the user has requested to close the window.
		void setCloseRequestedHandler(std::function<void()> closeRequestedHandler);

		// Called by App to get the SDL Window handle.
		void * getSDLWindow() const;

		// Called by App when the user clicks the close button on the window or equivalent shortcut.
		void onCloseRequested();

		// Called by App when the user resizes the window.
		void onResized(Vector2i size);

		// Called by App when the user moves the cursor within the window or out of the window.
		void onCursorPositionChanged(std::optional<Vector2i> cursorPosition);

		// Called by App to updates the window and the contained gui.
		void update(float dt);

		// Called by App to render the window. dt is the number of seconds left over since the last update, used for extrapolation into the next frame.
		void render(float dt) const;

	private:
		void * sdlWindow;
		std::function<void()> closeRequestedHandler;
		OwnPtr<render::WindowTarget> target;
		std::optional<Vector2i> cursorPosition;
		OwnPtr<Gui> gui;
	};
}<|endoftext|>


<commit_before>#include "word_db.hh"

#include "utils.hh"
#include "line_modification.hh"
#include "utf8_iterator.hh"

namespace Kakoune
{

UsedLetters used_letters(StringView str)
{
    UsedLetters res;
    for (auto c : str)
    {
        if (c >= 'a' and c <= 'z')
            res.set(c - 'a');
        else if (c >= 'A' and c <= 'Z')
            res.set(c - 'A' + 26);
        else if (c == '_')
            res.set(53);
        else if (c == '-')
            res.set(54);
        else
            res.set(63);
    }
    return res;
}

static WordDB::WordList get_words(const SharedString& content)
{
    WordDB::WordList res;
    using Iterator = utf8::iterator<const char*, utf8::InvalidPolicy::Pass>;
    const char* word_start = content.begin();
    bool in_word = false;
    for (Iterator it{word_start}, end{content.end()}; it != end; ++it)
    {
        Codepoint c = *it;
        const bool word = is_word(c);
        if (not in_word and word)
        {
            word_start = it.base();
            in_word = true;
        }
        else if (in_word and not word)
        {
            const ByteCount start = word_start - content.begin();
            const ByteCount length = it.base() - word_start;
            res.push_back(content.acquire_substr(start, length));
            in_word = false;
        }
    }
    return res;
}

void WordDB::add_words(const WordList& words)
{
    for (auto& w : words)
    {
        WordDB::WordInfo& info = m_words[intern(w)];
        ++info.refcount;
        if (info.letters.none())
            info.letters = used_letters(w);
    }
}

void WordDB::remove_words(const WordList& words)
{
    for (auto& w : words)
    {
        auto it = m_words.find({w, SharedString::NoCopy()});
        kak_assert(it != m_words.end() and it->second.refcount > 0);
        if (--it->second.refcount == 0)
            m_words.erase(it);
    }
}

WordDB::WordDB(const Buffer& buffer)
    : m_buffer{&buffer}, m_timestamp{buffer.timestamp()}
{
    m_lines.reserve((int)buffer.line_count());
    for (auto line = 0_line, end = buffer.line_count(); line < end; ++line)
    {
        m_lines.push_back(buffer.line_storage(line));
        add_words(get_words(SharedString{m_lines.back()}));
    }
}

void WordDB::update_db()
{
    auto& buffer = *m_buffer;

    auto modifs = compute_line_modifications(buffer, m_timestamp);
    m_timestamp = buffer.timestamp();

    if (modifs.empty())
        return;

    Lines new_lines;
    new_lines.reserve((int)buffer.line_count());

    auto old_line = 0_line;
    for (auto& modif : modifs)
    {
        kak_assert(0_line <= modif.new_line and modif.new_line < buffer.line_count());
        kak_assert(old_line <= modif.old_line);
        while (old_line < modif.old_line)
            new_lines.push_back(std::move(m_lines[(int)old_line++]));

        kak_assert((int)new_lines.size() == (int)modif.new_line);

        while (old_line < modif.old_line + modif.num_removed)
        {
            kak_assert(old_line < m_lines.size());
            remove_words(get_words(SharedString{m_lines[(int)old_line++]}));
        }

        for (auto l = 0_line; l < modif.num_added; ++l)
        {
            if (modif.new_line + l >= buffer.line_count())
                break;

            new_lines.push_back(buffer.line_storage(modif.new_line + l));
            add_words(get_words(SharedString{new_lines.back()}));
        }
    }
    while (old_line != (int)m_lines.size())
        new_lines.push_back(std::move(m_lines[(int)old_line++]));

    m_lines = std::move(new_lines);
}

int WordDB::get_word_occurences(StringView word) const
{
    auto it = m_words.find({word, SharedString::NoCopy()});
    if (it != m_words.end())
        return it->second.refcount;
    return 0;
}

}
<commit_msg>Fix too strict assert and unneeded (lets hope) check<commit_after>#include "word_db.hh"

#include "utils.hh"
#include "line_modification.hh"
#include "utf8_iterator.hh"

namespace Kakoune
{

UsedLetters used_letters(StringView str)
{
    UsedLetters res;
    for (auto c : str)
    {
        if (c >= 'a' and c <= 'z')
            res.set(c - 'a');
        else if (c >= 'A' and c <= 'Z')
            res.set(c - 'A' + 26);
        else if (c == '_')
            res.set(53);
        else if (c == '-')
            res.set(54);
        else
            res.set(63);
    }
    return res;
}

static WordDB::WordList get_words(const SharedString& content)
{
    WordDB::WordList res;
    using Iterator = utf8::iterator<const char*, utf8::InvalidPolicy::Pass>;
    const char* word_start = content.begin();
    bool in_word = false;
    for (Iterator it{word_start}, end{content.end()}; it != end; ++it)
    {
        Codepoint c = *it;
        const bool word = is_word(c);
        if (not in_word and word)
        {
            word_start = it.base();
            in_word = true;
        }
        else if (in_word and not word)
        {
            const ByteCount start = word_start - content.begin();
            const ByteCount length = it.base() - word_start;
            res.push_back(content.acquire_substr(start, length));
            in_word = false;
        }
    }
    return res;
}

void WordDB::add_words(const WordList& words)
{
    for (auto& w : words)
    {
        WordDB::WordInfo& info = m_words[intern(w)];
        ++info.refcount;
        if (info.letters.none())
            info.letters = used_letters(w);
    }
}

void WordDB::remove_words(const WordList& words)
{
    for (auto& w : words)
    {
        auto it = m_words.find({w, SharedString::NoCopy()});
        kak_assert(it != m_words.end() and it->second.refcount > 0);
        if (--it->second.refcount == 0)
            m_words.erase(it);
    }
}

WordDB::WordDB(const Buffer& buffer)
    : m_buffer{&buffer}, m_timestamp{buffer.timestamp()}
{
    m_lines.reserve((int)buffer.line_count());
    for (auto line = 0_line, end = buffer.line_count(); line < end; ++line)
    {
        m_lines.push_back(buffer.line_storage(line));
        add_words(get_words(SharedString{m_lines.back()}));
    }
}

void WordDB::update_db()
{
    auto& buffer = *m_buffer;

    auto modifs = compute_line_modifications(buffer, m_timestamp);
    m_timestamp = buffer.timestamp();

    if (modifs.empty())
        return;

    Lines new_lines;
    new_lines.reserve((int)buffer.line_count());

    auto old_line = 0_line;
    for (auto& modif : modifs)
    {
        kak_assert(0_line <= modif.new_line and modif.new_line <= buffer.line_count());
        kak_assert(modif.new_line < buffer.line_count() or modif.num_added == 0);
        kak_assert(old_line <= modif.old_line);
        while (old_line < modif.old_line)
            new_lines.push_back(std::move(m_lines[(int)old_line++]));

        kak_assert((int)new_lines.size() == (int)modif.new_line);

        while (old_line < modif.old_line + modif.num_removed)
        {
            kak_assert(old_line < m_lines.size());
            remove_words(get_words(SharedString{m_lines[(int)old_line++]}));
        }

        for (auto l = 0_line; l < modif.num_added; ++l)
        {
            new_lines.push_back(buffer.line_storage(modif.new_line + l));
            add_words(get_words(SharedString{new_lines.back()}));
        }
    }
    while (old_line != (int)m_lines.size())
        new_lines.push_back(std::move(m_lines[(int)old_line++]));

    m_lines = std::move(new_lines);
}

int WordDB::get_word_occurences(StringView word) const
{
    auto it = m_words.find({word, SharedString::NoCopy()});
    if (it != m_words.end())
        return it->second.refcount;
    return 0;
}

}
<|endoftext|>


<commit_before>#include <dlfcn.h>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cstdlib>

#include <iostream>
#include <fstream>
#include <vector>
#include <array>
#include <string>
#include <map>
#include <functional>
#include <experimental/optional>

#include "History.hpp"
#include "TerminalInfo.hpp"

#define cursor_forward(x) printf("\033[%dC", static_cast<int>(x))
#define cursor_backward(x) printf("\033[%dD", static_cast<int>(x))

// https://www.akkadia.org/drepper/tls.pdf

using namespace yb;

thread_local std::array<char, 1024> lineBuffer;
thread_local auto lineBufferPos = lineBuffer.begin();

thread_local std::string printBuffer;
thread_local std::string::iterator printBufferPos;

thread_local History history;
thread_local History::const_iterator historyPos;

thread_local static char arrowIndicator = 0;

using ReadSignature = ssize_t (*)(int, void*, size_t);
using Char = unsigned char;
using CharOpt = std::experimental::optional<Char>;

CharOpt newlineHandler(Char);
CharOpt tabHandler(Char);
CharOpt backspaceHandler(Char);
CharOpt regularCHarHandler(Char);
CharOpt arrowHandler1(Char);
CharOpt arrowHandler2(Char);
CharOpt arrowHandler3(Char);

thread_local std::map<Char, std::function<CharOpt(Char)>> handlers = {
    {0x06, tabHandler},
    {0x0d, newlineHandler},
    {0x17, newlineHandler}, // TODO: this should delete one word
    {0x1b, arrowHandler1},
    {0x5b, arrowHandler2},
    {0x43, arrowHandler3},
    {0x7f, backspaceHandler}
};

void clearTerminalLine() {
    int pos, width;
    if (!(pos = TerminalInfo::getCursorPosition())) return;
    width = TerminalInfo::getWidth();
    for (int i = 0; i < width - pos; i++)
        printf(" ");
    for (int i = 0; i < width - pos; i++)
        cursor_backward(1);
    fflush(stdout);
}

std::string findCompletion(History::const_iterator start, const std::string &pattern) {
    for (auto it = start; it != history.end(); it++) {
        if (it->compare(0, pattern.length(), pattern) == 0) {
            historyPos = it;
            return *it;
        }
    }

    historyPos = history.begin();
    return pattern;
}

void printCompletion(History::const_iterator startIterator, int offset) {
    std::string pattern(lineBuffer.data());
    auto completion = findCompletion(startIterator, pattern);
    if (completion == pattern) return;

    clearTerminalLine();

    if (offset)
        cursor_forward(offset);
    printf("\e[1;30m%s\e[0m", completion.c_str() + pattern.length());

    cursor_backward(completion.length() - pattern.length() + offset);
    fflush(stdout);
}

CharOpt newlineHandler(Char) {
    lineBuffer.fill(0);
    lineBufferPos = lineBuffer.begin();
    return {};
}

CharOpt backspaceHandler(Char) {
    if (lineBufferPos != lineBuffer.begin()) {
        *(--lineBufferPos) = 0;
    }

    return {};
}

CharOpt regularCharHandler(Char c) {
    *lineBufferPos = c;
    lineBufferPos++;

    printCompletion(history.begin(), 1);

    return {};
}

CharOpt tabHandler(Char) {
    printCompletion(std::next(historyPos, 1), 0);
    return Char{0}; // TODO: this does not seem to work.
}

CharOpt arrowHandler1(Char) {
    arrowIndicator = 1;
    return {};
}

CharOpt arrowHandler2(Char c) {
    if (arrowIndicator == 1) {
        arrowIndicator = 2;
        return {};
    }
    else {
        return regularCharHandler(c);
    }
}

CharOpt arrowHandler3(Char c) {
    CharOpt return_value = {};
    if (arrowIndicator == 2) {
        arrowIndicator = 0;
        try {
            printBuffer = historyPos->substr(lineBufferPos - lineBuffer.begin());
            printBufferPos = printBuffer.begin();
        } catch (...) {
            // FIXME:
        }
    }
    else {
        return_value = regularCharHandler(c);
    }

    return return_value;
}

static unsigned char yebash(unsigned char c) {

    // TODO: uncomment later
    //if (!getenv("YEBASH"))
    //    return;
    history.read(std::string{getenv("HOME")} + "/.bash_history");

    auto handler = handlers[c];

    // TODO(Mrokkk): There would be a problem with processing all escape codes
    // that bash is using (e.g. ctrl+r for history searching, arrows for moving, etc.).
    // It would be thoughtful if we just disable our yebash if any of these codes would
    // occur and reenable it after a newline
    CharOpt cReturned;

    if (handler) {
        cReturned = handler(c);
    }
    else {
        if (c < 0x20) {
            newlineHandler(c);
        }
        else {
            regularCharHandler(c);
        }
    }

    return cReturned.value_or(c);

}

static inline bool is_terminal_input(int fd) {
    return isatty(fd);
}

ssize_t read(int fd, void *buf, size_t count) {

    ssize_t returnValue;
    static thread_local ReadSignature realRead = nullptr;

    if (is_terminal_input(fd)) { // TODO: make it look good
        if (printBuffer.length()) {
            // Return printBuffer to bash one char at time
            *reinterpret_cast<char *>(buf) = *printBufferPos;
            *lineBufferPos++ =  *printBufferPos++;
            if (printBufferPos == printBuffer.end()) {
                printBuffer.erase(printBuffer.begin(), printBuffer.end());
            }
            return 1;
        }
    }

    if (!realRead)
        realRead = reinterpret_cast<ReadSignature>(dlsym(RTLD_NEXT, "read"));

    returnValue = realRead(fd, buf, count);

    if (is_terminal_input(fd))
        *reinterpret_cast<unsigned char *>(buf) = yebash(*reinterpret_cast<unsigned char *>(buf));

    return returnValue;
}

<commit_msg>Make findCompletion return value optional<commit_after>#include <dlfcn.h>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <cstdlib>

#include <iostream>
#include <fstream>
#include <vector>
#include <array>
#include <string>
#include <map>
#include <functional>
#include <experimental/optional>

#include "History.hpp"
#include "TerminalInfo.hpp"

#define cursor_forward(x) printf("\033[%dC", static_cast<int>(x))
#define cursor_backward(x) printf("\033[%dD", static_cast<int>(x))

// https://www.akkadia.org/drepper/tls.pdf

using namespace yb;

thread_local std::array<char, 1024> lineBuffer;
thread_local auto lineBufferPos = lineBuffer.begin();

thread_local std::string printBuffer;
thread_local std::string::iterator printBufferPos;

thread_local History history;
thread_local History::const_iterator historyPos;

thread_local static char arrowIndicator = 0;

using ReadSignature = ssize_t (*)(int, void*, size_t);
using Char = unsigned char;
using CharOpt = std::experimental::optional<Char>;
using StringOpt = std::experimental::optional<std::string>;

CharOpt newlineHandler(Char);
CharOpt tabHandler(Char);
CharOpt backspaceHandler(Char);
CharOpt regularCHarHandler(Char);
CharOpt arrowHandler1(Char);
CharOpt arrowHandler2(Char);
CharOpt arrowHandler3(Char);

thread_local std::map<Char, std::function<CharOpt(Char)>> handlers = {
    {0x06, tabHandler},
    {0x0d, newlineHandler},
    {0x17, newlineHandler}, // TODO: this should delete one word
    {0x1b, arrowHandler1},
    {0x5b, arrowHandler2},
    {0x43, arrowHandler3},
    {0x7f, backspaceHandler}
};

void clearTerminalLine() {
    int pos, width;
    if (!(pos = TerminalInfo::getCursorPosition())) return;
    width = TerminalInfo::getWidth();
    for (int i = 0; i < width - pos; i++)
        printf(" ");
    for (int i = 0; i < width - pos; i++)
        cursor_backward(1);
    fflush(stdout);
}

StringOpt findCompletion(History::const_iterator start, const std::string &pattern) {
    for (auto it = start; it != history.end(); it++) {
        if (it->compare(0, pattern.length(), pattern) == 0) {
            historyPos = it;
            return *it;
        }
    }
    historyPos = history.begin();
    return {};
}

void printCompletion(History::const_iterator startIterator, int offset) {
    std::string pattern(lineBuffer.data());
    auto completion = findCompletion(startIterator, pattern);
    if (!completion) return;

    clearTerminalLine();

    if (offset)
        cursor_forward(offset);
    printf("\e[1;30m%s\e[0m", completion.value().c_str() + pattern.length());

    cursor_backward(completion.value().length() - pattern.length() + offset);
    fflush(stdout);
}

CharOpt newlineHandler(Char) {
    lineBuffer.fill(0);
    lineBufferPos = lineBuffer.begin();
    return {};
}

CharOpt backspaceHandler(Char) {
    if (lineBufferPos != lineBuffer.begin()) {
        *(--lineBufferPos) = 0;
    }

    return {};
}

CharOpt regularCharHandler(Char c) {
    *lineBufferPos = c;
    lineBufferPos++;

    printCompletion(history.begin(), 1);

    return {};
}

CharOpt tabHandler(Char) {
    printCompletion(std::next(historyPos, 1), 0);
    return Char{0}; // TODO: this does not seem to work.
}

CharOpt arrowHandler1(Char) {
    arrowIndicator = 1;
    return {};
}

CharOpt arrowHandler2(Char c) {
    if (arrowIndicator == 1) {
        arrowIndicator = 2;
        return {};
    }
    else {
        return regularCharHandler(c);
    }
}

CharOpt arrowHandler3(Char c) {
    CharOpt return_value = {};
    if (arrowIndicator == 2) {
        arrowIndicator = 0;
        try {
            printBuffer = historyPos->substr(lineBufferPos - lineBuffer.begin());
            printBufferPos = printBuffer.begin();
        } catch (...) {
            // FIXME:
        }
    }
    else {
        return_value = regularCharHandler(c);
    }

    return return_value;
}

static unsigned char yebash(unsigned char c) {

    // TODO: uncomment later
    //if (!getenv("YEBASH"))
    //    return;
    history.read(std::string{getenv("HOME")} + "/.bash_history");

    auto handler = handlers[c];

    // TODO(Mrokkk): There would be a problem with processing all escape codes
    // that bash is using (e.g. ctrl+r for history searching, arrows for moving, etc.).
    // It would be thoughtful if we just disable our yebash if any of these codes would
    // occur and reenable it after a newline
    CharOpt cReturned;

    if (handler) {
        cReturned = handler(c);
    }
    else {
        if (c < 0x20) {
            newlineHandler(c);
        }
        else {
            regularCharHandler(c);
        }
    }

    return cReturned.value_or(c);

}

static inline bool is_terminal_input(int fd) {
    return isatty(fd);
}

ssize_t read(int fd, void *buf, size_t count) {

    ssize_t returnValue;
    static thread_local ReadSignature realRead = nullptr;

    if (is_terminal_input(fd)) { // TODO: make it look good
        if (printBuffer.length()) {
            // Return printBuffer to bash one char at time
            *reinterpret_cast<char *>(buf) = *printBufferPos;
            *lineBufferPos++ =  *printBufferPos++;
            if (printBufferPos == printBuffer.end()) {
                printBuffer.erase(printBuffer.begin(), printBuffer.end());
            }
            return 1;
        }
    }

    if (!realRead)
        realRead = reinterpret_cast<ReadSignature>(dlsym(RTLD_NEXT, "read"));

    returnValue = realRead(fd, buf, count);

    if (is_terminal_input(fd))
        *reinterpret_cast<unsigned char *>(buf) = yebash(*reinterpret_cast<unsigned char *>(buf));

    return returnValue;
}

<|endoftext|>


<commit_before>/*
 *  IceWM - C++ wrapper for locale/unicode conversion
 *  Copyright (C) 2001 The Authors of IceWM
 *
 *  Released under terms of the GNU Library General Public License
 *
 *  2001/07/21: Mathias Hasselmann <mathias.hasselmann@gmx.net>
 *      - initial revision
 */

#include "config.h"
#include "ylocale.h"

#include "base.h"

#include "intl.h"
#include <string.h>

#ifdef CONFIG_I18N
#include <errno.h>
#include <langinfo.h>
#include <locale.h>
#include <stdlib.h>
#include <wchar.h>
#include <assert.h>
#endif

#include "ylib.h"
#include "yprefs.h"

#ifdef CONFIG_I18N
YLocale * YLocale::instance(NULL);
#endif

#ifndef CONFIG_I18N
YLocale::YLocale(char const * ) {
#else
YLocale::YLocale(char const * localeName) {
    assert(NULL == instance);

    instance = this;

    if (NULL == (fLocaleName = setlocale(LC_ALL, localeName))
        /* || False == XSupportsLocale()*/) {
        warn(_("Locale not supported by C library. "
               "Falling back to 'C' locale'."));
        fLocaleName = setlocale(LC_ALL, "C");
    }
#ifndef NO_CONFIGURE
    multiByte = true;
#endif

    char const * codeset = NULL;
    int const codesetItems[] = {
#ifdef CONFIG_NL_CODESETS
	CONFIG_NL_CODESETS
#else
	CODESET, _NL_CTYPE_CODESET_NAME, 0
#endif
    };

    for (unsigned int i = 0;
         i + 1 < ACOUNT(codesetItems)
         && NULL != (codeset = nl_langinfo(codesetItems[i]))
         && '\0' == *codeset;
         ++i) {}

    if (NULL == codeset || '\0' == *codeset) {
        warn(_("Failed to determinate the current locale's codeset. "
               "Assuming ISO-8859-1.\n"));
        codeset = "ISO-8859-1";
    }

    union { int i; char c[sizeof(int)]; } endian; endian.i = 1;

    MSG(("locale: %s, MB_CUR_MAX: %zd, "
         "multibyte: %d, codeset: %s, endian: %c",
         fLocaleName, MB_CUR_MAX, multiByte, codeset, *endian.c ? 'l' : 'b'));

/// TODO #warning "this is getting way too complicated"

    char const * unicodeCharsets[] = {
#ifdef CONFIG_UNICODE_SET
        CONFIG_UNICODE_SET,
#endif
//      "WCHAR_T//TRANSLIT",
        (*endian.c ? "UCS-4LE//TRANSLIT" : "UCS-4BE//TRANSLIT"),
//      "WCHAR_T",
        (*endian.c ? "UCS-4LE" : "UCS-4BE"),
        "UCS-4//TRANSLIT",
        "UCS-4",
        NULL
    };

    char const * localeCharsets[] = {
        cstrJoin(codeset, "//TRANSLIT", NULL), codeset, NULL
    };

    char const ** ucs(unicodeCharsets);
    if ((iconv_t) -1 == (toUnicode = getConverter (localeCharsets[1], ucs)))
        die(1, _("iconv doesn't supply (sufficient) "
                 "%s to %s converters."), localeCharsets[1], "Unicode");

    MSG(("toUnicode converts from %s to %s", localeCharsets[1], *ucs));

    char const ** lcs(localeCharsets);
    if ((iconv_t) -1 == (toLocale = getConverter (*ucs, lcs)))
        die(1, _("iconv doesn't supply (sufficient) "
                 "%s to %s converters."), "Unicode", localeCharsets[1]);

    MSG(("toLocale converts from %s to %s", *ucs, *lcs));

    delete[] localeCharsets[0];
#endif

#ifdef ENABLE_NLS
    bindtextdomain(PACKAGE, LOCDIR);
    textdomain(PACKAGE);
#endif
}

YLocale::~YLocale() {
#ifdef CONFIG_I18N
    instance = NULL;

    if ((iconv_t) -1 != toUnicode) iconv_close(toUnicode);
    if ((iconv_t) -1 != toLocale) iconv_close(toLocale);
#endif
}

#ifdef CONFIG_I18N
iconv_t YLocale::getConverter (const char *from, const char **&to) {
    iconv_t cd = (iconv_t) -1;

    while (NULL != *to)
        if ((iconv_t) -1 != (cd = iconv_open(*to, from))) return cd;
        else ++to;

    return (iconv_t) -1;
}

/*
YLChar * YLocale::localeString(YUChar const * uStr) {
    YLChar * lStr(NULL);

    return lStr;
}
*/

YUChar *YLocale::unicodeString(const YLChar *lStr, size_t const lLen,
                               size_t & uLen)
{
    PRECONDITION(instance != NULL);
    if (NULL == lStr)
        return NULL;

    YUChar * uStr(new YUChar[lLen + 1]);
    char * inbuf((char *) lStr), * outbuf((char *) uStr);
    size_t inlen(lLen), outlen(4 * lLen);

    if (0 > (int) iconv(instance->toUnicode, &inbuf, &inlen, &outbuf, &outlen))
        warn(_("Invalid multibyte string \"%s\": %s"), lStr, strerror(errno));

    *((YUChar *) outbuf) = 0;
    uLen = ((YUChar *) outbuf) - uStr;

    return uStr;
}
#endif

const char *YLocale::getLocaleName() {
#ifdef CONFIG_I18N
    return instance->fLocaleName;
#else
    return "C";
#endif
}

int YLocale::getRating(const char *localeStr) {
    const char *s1 = getLocaleName();
    const char *s2 = localeStr;

    while (*s1 && *s1++ == *s2++) {}
    if (*s1) while (--s2 > localeStr && !strchr("_@.", *s2)) {}

    return s2 - localeStr;
}
<commit_msg>make sure X supports locale from start<commit_after>/*
 *  IceWM - C++ wrapper for locale/unicode conversion
 *  Copyright (C) 2001 The Authors of IceWM
 *
 *  Released under terms of the GNU Library General Public License
 *
 *  2001/07/21: Mathias Hasselmann <mathias.hasselmann@gmx.net>
 *      - initial revision
 */

#include "config.h"
#include "ylocale.h"

#include "base.h"

#include "intl.h"
#include <string.h>

#ifdef CONFIG_I18N
#include <errno.h>
#include <langinfo.h>
#include <locale.h>
#include <stdlib.h>
#include <wchar.h>
#include <assert.h>
#endif

#include "ylib.h"
#include "yprefs.h"

#ifdef CONFIG_I18N
YLocale * YLocale::instance(NULL);
#endif

#ifndef CONFIG_I18N
YLocale::YLocale(char const * ) {
#else
YLocale::YLocale(char const * localeName) {
    assert(NULL == instance);

    instance = this;

    if (NULL == (fLocaleName = setlocale(LC_ALL, localeName))
        || False == XSupportsLocale()) {
        warn(_("Locale not supported by C library or Xlib. "
               "Falling back to 'C' locale'."));
        fLocaleName = setlocale(LC_ALL, "C");
    }
#ifndef NO_CONFIGURE
    multiByte = true;
#endif

    char const * codeset = NULL;
    int const codesetItems[] = {
#ifdef CONFIG_NL_CODESETS
        CONFIG_NL_CODESETS
#else
        CODESET, _NL_CTYPE_CODESET_NAME, 0
#endif
    };

    for (unsigned int i = 0;
         i + 1 < ACOUNT(codesetItems)
         && NULL != (codeset = nl_langinfo(codesetItems[i]))
         && '\0' == *codeset;
         ++i) {}

    if (NULL == codeset || '\0' == *codeset) {
        warn(_("Failed to determinate the current locale's codeset. "
               "Assuming ISO-8859-1.\n"));
        codeset = "ISO-8859-1";
    }

    union { int i; char c[sizeof(int)]; } endian; endian.i = 1;

    MSG(("locale: %s, MB_CUR_MAX: %zd, "
         "multibyte: %d, codeset: %s, endian: %c",
         fLocaleName, MB_CUR_MAX, multiByte, codeset, *endian.c ? 'l' : 'b'));

/// TODO #warning "this is getting way too complicated"

    char const * unicodeCharsets[] = {
#ifdef CONFIG_UNICODE_SET
        CONFIG_UNICODE_SET,
#endif
//      "WCHAR_T//TRANSLIT",
        (*endian.c ? "UCS-4LE//TRANSLIT" : "UCS-4BE//TRANSLIT"),
//      "WCHAR_T",
        (*endian.c ? "UCS-4LE" : "UCS-4BE"),
        "UCS-4//TRANSLIT",
        "UCS-4",
        NULL
    };

    char const * localeCharsets[] = {
        cstrJoin(codeset, "//TRANSLIT", NULL), codeset, NULL
    };

    char const ** ucs(unicodeCharsets);
    if ((iconv_t) -1 == (toUnicode = getConverter (localeCharsets[1], ucs)))
        die(1, _("iconv doesn't supply (sufficient) "
                 "%s to %s converters."), localeCharsets[1], "Unicode");

    MSG(("toUnicode converts from %s to %s", localeCharsets[1], *ucs));

    char const ** lcs(localeCharsets);
    if ((iconv_t) -1 == (toLocale = getConverter (*ucs, lcs)))
        die(1, _("iconv doesn't supply (sufficient) "
                 "%s to %s converters."), "Unicode", localeCharsets[1]);

    MSG(("toLocale converts from %s to %s", *ucs, *lcs));

    delete[] localeCharsets[0];
#endif

#ifdef ENABLE_NLS
    bindtextdomain(PACKAGE, LOCDIR);
    textdomain(PACKAGE);
#endif
}

YLocale::~YLocale() {
#ifdef CONFIG_I18N
    instance = NULL;

    if ((iconv_t) -1 != toUnicode) iconv_close(toUnicode);
    if ((iconv_t) -1 != toLocale) iconv_close(toLocale);
#endif
}

#ifdef CONFIG_I18N
iconv_t YLocale::getConverter (const char *from, const char **&to) {
    iconv_t cd = (iconv_t) -1;

    while (NULL != *to)
        if ((iconv_t) -1 != (cd = iconv_open(*to, from))) return cd;
        else ++to;

    return (iconv_t) -1;
}

/*
YLChar * YLocale::localeString(YUChar const * uStr) {
    YLChar * lStr(NULL);

    return lStr;
}
*/

YUChar *YLocale::unicodeString(const YLChar *lStr, size_t const lLen,
                               size_t & uLen)
{
    PRECONDITION(instance != NULL);
    if (NULL == lStr)
        return NULL;

    YUChar * uStr(new YUChar[lLen + 1]);
    char * inbuf((char *) lStr), * outbuf((char *) uStr);
    size_t inlen(lLen), outlen(4 * lLen);

    if (0 > (int) iconv(instance->toUnicode, &inbuf, &inlen, &outbuf, &outlen))
        warn(_("Invalid multibyte string \"%s\": %s"), lStr, strerror(errno));

    *((YUChar *) outbuf) = 0;
    uLen = ((YUChar *) outbuf) - uStr;

    return uStr;
}
#endif

const char *YLocale::getLocaleName() {
#ifdef CONFIG_I18N
    return instance->fLocaleName;
#else
    return "C";
#endif
}

int YLocale::getRating(const char *localeStr) {
    const char *s1 = getLocaleName();
    const char *s2 = localeStr;

    while (*s1 && *s1++ == *s2++) {}
    if (*s1) while (--s2 > localeStr && !strchr("_@.", *s2)) {}

    return s2 - localeStr;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: testresource.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: vg $ $Date: 2006-06-02 13:04:44 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <smart/com/sun/star/registry/XImplementationRegistration.hxx>
#include <smart/com/sun/star/script/XInvocation.hxx>

#include <rtl/ustring.hxx>
#include <vos/dynload.hxx>
#include <vos/diagnose.hxx>
#include <usr/services.hxx>
#include <vcl/svapp.hxx>

using namespace rtl;
using namespace vos;
using namespace usr;

class MyApp : public Application
{
public:
    void        Main();
};

MyApp aMyApp;

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

void MyApp::Main()
{
    XMultiServiceFactoryRef xSMgr = createRegistryServiceManager();
    registerUsrServices( xSMgr );
    setProcessServiceManager( xSMgr );

    XInterfaceRef x = xSMgr->createInstance( L"com.sun.star.registry.ImplementationRegistration" );
    XImplementationRegistrationRef xReg( x, USR_QUERY );
    sal_Char szBuf[1024];
    ORealDynamicLoader::computeModuleName( "res", szBuf, 1024 );
    UString aDllName( StringToOUString( szBuf, CHARSET_SYSTEM ) );
    xReg->registerImplementation( L"com.sun.star.loader.SharedLibrary", aDllName, XSimpleRegistryRef() );

    x = xSMgr->createInstance( L"com.sun.star.resource.VclStringResourceLoader" );
    XInvocationRef xResLoader( x, USR_QUERY );
    XIntrospectionAccessRef xIntrospection = xResLoader->getIntrospection();
    UString aFileName( L"TestResource" );
    UsrAny aVal;
    aVal.setString( aFileName );
    xResLoader->setValue( L"FileName", aVal );

    Sequence< UsrAny > Args( 1 );
    Sequence< INT16 > OutPos;
    Sequence< UsrAny > OutArgs;
    Args.getArray()[0].setINT32( 1000 );

    BOOL b = xResLoader->invoke( L"hasString", Args, OutPos, OutArgs ).getBOOL();
    VOS_ENSHURE( b, "hasString" );

    UString aStr = xResLoader->invoke( L"getString", Args, OutPos, OutArgs ).getString();
    VOS_ENSHURE( aStr == L"Hello", "getString" );

    Args.getArray()[0].setINT32( 1001 );
    b = xResLoader->invoke( L"hasString", Args, OutPos, OutArgs ).getBOOL();
    VOS_ENSHURE( !b, "!hasString" );

    xReg->revokeImplementation( aDllName, XSimpleRegistryRef() );
}

<commit_msg>INTEGRATION: CWS pchfix02 (1.3.46); FILE MERGED 2006/09/01 17:26:54 kaib 1.3.46.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: testresource.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 13:36:10 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_extensions.hxx"

#include <smart/com/sun/star/registry/XImplementationRegistration.hxx>
#include <smart/com/sun/star/script/XInvocation.hxx>

#include <rtl/ustring.hxx>
#include <vos/dynload.hxx>
#include <vos/diagnose.hxx>
#include <usr/services.hxx>
#include <vcl/svapp.hxx>

using namespace rtl;
using namespace vos;
using namespace usr;

class MyApp : public Application
{
public:
    void        Main();
};

MyApp aMyApp;

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

void MyApp::Main()
{
    XMultiServiceFactoryRef xSMgr = createRegistryServiceManager();
    registerUsrServices( xSMgr );
    setProcessServiceManager( xSMgr );

    XInterfaceRef x = xSMgr->createInstance( L"com.sun.star.registry.ImplementationRegistration" );
    XImplementationRegistrationRef xReg( x, USR_QUERY );
    sal_Char szBuf[1024];
    ORealDynamicLoader::computeModuleName( "res", szBuf, 1024 );
    UString aDllName( StringToOUString( szBuf, CHARSET_SYSTEM ) );
    xReg->registerImplementation( L"com.sun.star.loader.SharedLibrary", aDllName, XSimpleRegistryRef() );

    x = xSMgr->createInstance( L"com.sun.star.resource.VclStringResourceLoader" );
    XInvocationRef xResLoader( x, USR_QUERY );
    XIntrospectionAccessRef xIntrospection = xResLoader->getIntrospection();
    UString aFileName( L"TestResource" );
    UsrAny aVal;
    aVal.setString( aFileName );
    xResLoader->setValue( L"FileName", aVal );

    Sequence< UsrAny > Args( 1 );
    Sequence< INT16 > OutPos;
    Sequence< UsrAny > OutArgs;
    Args.getArray()[0].setINT32( 1000 );

    BOOL b = xResLoader->invoke( L"hasString", Args, OutPos, OutArgs ).getBOOL();
    VOS_ENSHURE( b, "hasString" );

    UString aStr = xResLoader->invoke( L"getString", Args, OutPos, OutArgs ).getString();
    VOS_ENSHURE( aStr == L"Hello", "getString" );

    Args.getArray()[0].setINT32( 1001 );
    b = xResLoader->invoke( L"hasString", Args, OutPos, OutArgs ).getBOOL();
    VOS_ENSHURE( !b, "!hasString" );

    xReg->revokeImplementation( aDllName, XSimpleRegistryRef() );
}

<|endoftext|>


<commit_before><commit_msg>coverity#735429 Logically dead code<commit_after><|endoftext|>


<commit_before>/**
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Da Zheng (zhengda1936@gmail.com)
 *
 * This file is part of FlashGraph.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <signal.h>
#ifdef PROFILER
#include <google/profiler.h>
#endif

#include <vector>

#include "thread.h"
#include "io_interface.h"
#include "container.h"
#include "concurrency.h"

#include "vertex_index.h"
#include "graph_engine.h"
#include "graph_config.h"

edge_type traverse_edge = edge_type::OUT_EDGE;

class bfs_vertex: public compute_directed_vertex
{
	enum {
		VISITED,
	};

	atomic_flags<int> flags;
public:
	bfs_vertex(vertex_id_t id): compute_directed_vertex(id) {
	}

	bool has_visited() const {
		return flags.test_flag(VISITED);
	}

	bool set_visited(bool visited) {
		if (visited)
			return flags.set_flag(VISITED);
		else
			return flags.clear_flag(VISITED);
	}

	void run(vertex_program &prog) {
		if (!has_visited()) {
			directed_vertex_request req(get_id(), traverse_edge);
			request_partial_vertices(&req, 1);
		}
	}

	void run(vertex_program &prog, const page_vertex &vertex);

	void run_on_message(vertex_program &prog, const vertex_message &msg) {
	}
};

void bfs_vertex::run(vertex_program &prog, const page_vertex &vertex)
{
	assert(!has_visited());
	set_visited(true);

	int num_dests = vertex.get_num_edges(traverse_edge);
	if (num_dests == 0)
		return;

	// We need to add the neighbors of the vertex to the queue of
	// the next level.
#ifdef USE_ARRAY
	stack_array<vertex_id_t, 1024> neighs(num_dests);
	vertex.read_edges(traverse_edge, neighs.data(), num_dests);
	prog.activate_vertices(neighs.data(), num_dests);
#else
	edge_seq_iterator it = vertex.get_neigh_seq_it(traverse_edge, 0, num_dests);
	prog.activate_vertices(it);
#endif
}

class count_vertex_query: public vertex_query
{
	size_t num_visited;
public:
	count_vertex_query() {
		num_visited = 0;
	}

	virtual void run(graph_engine &graph, compute_vertex &v) {
		bfs_vertex &bfs_v = (bfs_vertex &) v;
		if (bfs_v.has_visited())
			num_visited++;
	}

	virtual void merge(graph_engine &graph, vertex_query::ptr q) {
		count_vertex_query *cvq = (count_vertex_query *) q.get();
		num_visited += cvq->num_visited;
	}

	virtual ptr clone() {
		return vertex_query::ptr(new count_vertex_query());
	}

	size_t get_num_visited() const {
		return num_visited;
	}
};

void int_handler(int sig_num)
{
#ifdef PROFILER
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
#endif
	exit(0);
}

void print_usage()
{
	fprintf(stderr,
			"bfs [options] conf_file graph_file index_file start_vertex\n");
	fprintf(stderr, "-c confs: add more configurations to the system\n");
	fprintf(stderr, "-b: traverse with both in-edges and out-edges\n");
	graph_conf.print_help();
	params.print_help();
}

int main(int argc, char *argv[])
{
	int opt;
	std::string confs;
	int num_opts = 0;
	while ((opt = getopt(argc, argv, "c:b")) != -1) {
		num_opts++;
		switch (opt) {
			case 'c':
				confs = optarg;
				num_opts++;
				break;
			case 'b':
				traverse_edge = edge_type::BOTH_EDGES;
				break;
			default:
				print_usage();
		}
	}
	argv += 1 + num_opts;
	argc -= 1 + num_opts;

	if (argc < 4) {
		print_usage();
		exit(-1);
	}

	std::string conf_file = argv[0];
	std::string graph_file = argv[1];
	std::string index_file = argv[2];
	vertex_id_t start_vertex = atoi(argv[3]);

	config_map configs(conf_file);
	configs.add_options(confs);

	signal(SIGINT, int_handler);

	graph_index::ptr index = NUMA_graph_index<bfs_vertex>::create(index_file);
	graph_engine::ptr graph = graph_engine::create(graph_file, index, configs);
	printf("BFS starts\n");
	printf("prof_file: %s\n", graph_conf.get_prof_file().c_str());
#ifdef PROFILER
	if (!graph_conf.get_prof_file().empty())
		ProfilerStart(graph_conf.get_prof_file().c_str());
#endif

	struct timeval start, end;
	gettimeofday(&start, NULL);
	graph->start(&start_vertex, 1);
	graph->wait4complete();
	gettimeofday(&end, NULL);

	vertex_query::ptr cvq(new count_vertex_query());
	graph->query_on_all(cvq);
	size_t num_visited = ((count_vertex_query *) cvq.get())->get_num_visited();

#ifdef PROFILER
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
#endif
	printf("BFS from vertex %ld visits %ld vertices. It takes %f seconds\n",
			(unsigned long) start_vertex, num_visited, time_diff(start, end));
}
<commit_msg>[Graph]: simplify bfs.<commit_after>/**
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Da Zheng (zhengda1936@gmail.com)
 *
 * This file is part of FlashGraph.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <signal.h>
#ifdef PROFILER
#include <google/profiler.h>
#endif

#include <vector>

#include "thread.h"
#include "io_interface.h"
#include "container.h"
#include "concurrency.h"

#include "vertex_index.h"
#include "graph_engine.h"
#include "graph_config.h"

edge_type traverse_edge = edge_type::OUT_EDGE;

class bfs_vertex: public compute_directed_vertex
{
	bool visited;
public:
	bfs_vertex(vertex_id_t id): compute_directed_vertex(id) {
		visited = false;
	}

	bool has_visited() const {
		return visited;
	}

	bool set_visited(bool visited) {
		this->visited = visited;
	}

	void run(vertex_program &prog) {
		if (!has_visited()) {
			directed_vertex_request req(get_id(), traverse_edge);
			request_partial_vertices(&req, 1);
		}
	}

	void run(vertex_program &prog, const page_vertex &vertex);

	void run_on_message(vertex_program &prog, const vertex_message &msg) {
	}
};

void bfs_vertex::run(vertex_program &prog, const page_vertex &vertex)
{
	assert(!has_visited());
	set_visited(true);

	int num_dests = vertex.get_num_edges(traverse_edge);
	if (num_dests == 0)
		return;

	// We need to add the neighbors of the vertex to the queue of
	// the next level.
#ifdef USE_ARRAY
	stack_array<vertex_id_t, 1024> neighs(num_dests);
	vertex.read_edges(traverse_edge, neighs.data(), num_dests);
	prog.activate_vertices(neighs.data(), num_dests);
#else
	edge_seq_iterator it = vertex.get_neigh_seq_it(traverse_edge, 0, num_dests);
	prog.activate_vertices(it);
#endif
}

class count_vertex_query: public vertex_query
{
	size_t num_visited;
public:
	count_vertex_query() {
		num_visited = 0;
	}

	virtual void run(graph_engine &graph, compute_vertex &v) {
		bfs_vertex &bfs_v = (bfs_vertex &) v;
		if (bfs_v.has_visited())
			num_visited++;
	}

	virtual void merge(graph_engine &graph, vertex_query::ptr q) {
		count_vertex_query *cvq = (count_vertex_query *) q.get();
		num_visited += cvq->num_visited;
	}

	virtual ptr clone() {
		return vertex_query::ptr(new count_vertex_query());
	}

	size_t get_num_visited() const {
		return num_visited;
	}
};

void int_handler(int sig_num)
{
#ifdef PROFILER
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
#endif
	exit(0);
}

void print_usage()
{
	fprintf(stderr,
			"bfs [options] conf_file graph_file index_file start_vertex\n");
	fprintf(stderr, "-c confs: add more configurations to the system\n");
	fprintf(stderr, "-b: traverse with both in-edges and out-edges\n");
	graph_conf.print_help();
	params.print_help();
}

int main(int argc, char *argv[])
{
	int opt;
	std::string confs;
	int num_opts = 0;
	while ((opt = getopt(argc, argv, "c:b")) != -1) {
		num_opts++;
		switch (opt) {
			case 'c':
				confs = optarg;
				num_opts++;
				break;
			case 'b':
				traverse_edge = edge_type::BOTH_EDGES;
				break;
			default:
				print_usage();
		}
	}
	argv += 1 + num_opts;
	argc -= 1 + num_opts;

	if (argc < 4) {
		print_usage();
		exit(-1);
	}

	std::string conf_file = argv[0];
	std::string graph_file = argv[1];
	std::string index_file = argv[2];
	vertex_id_t start_vertex = atoi(argv[3]);

	config_map configs(conf_file);
	configs.add_options(confs);

	signal(SIGINT, int_handler);

	graph_index::ptr index = NUMA_graph_index<bfs_vertex>::create(index_file);
	graph_engine::ptr graph = graph_engine::create(graph_file, index, configs);
	printf("BFS starts\n");
	printf("prof_file: %s\n", graph_conf.get_prof_file().c_str());
#ifdef PROFILER
	if (!graph_conf.get_prof_file().empty())
		ProfilerStart(graph_conf.get_prof_file().c_str());
#endif

	struct timeval start, end;
	gettimeofday(&start, NULL);
	graph->start(&start_vertex, 1);
	graph->wait4complete();
	gettimeofday(&end, NULL);

	vertex_query::ptr cvq(new count_vertex_query());
	graph->query_on_all(cvq);
	size_t num_visited = ((count_vertex_query *) cvq.get())->get_num_visited();

#ifdef PROFILER
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
#endif
	printf("BFS from vertex %ld visits %ld vertices. It takes %f seconds\n",
			(unsigned long) start_vertex, num_visited, time_diff(start, end));
}
<|endoftext|>