<commit_before>#include <act-common/common.h>

// ========================================================================
// ===================== Critical Macrodefinitions ========================
// ========================================================================

/*
 * FOSC = 1MHz is confugured via Flash Fuses CKSEL=1 and SUT=2.
 */

#define BAUD_RATE    4800    // 4.8kbps
#define FOSC         1000000 // 1MHz
#define TC2_PRESCALE 1       // no Timer/Counter2 prescale

#include <act-photo/usart.h>
#include <act-photo/pwm.h>

#define REMUX(c) ADMUX = (3<<REFS0)|(1<<ADLAR)|(c<<MUX0)

// ========================================================================
// ===================== Initialization ===================================
// ========================================================================

inline __monitor void init()
{
    /* USART initialization */
    usart_init();
    /* Timer/Counter2 initialization */
    init_tc2_wg();
    /* ADC initialization (1/8 prescaling,
       1st channel, internal Vref, left alignment) */
    REMUX(0);
    ADCSR = (1<<ADEN)|(3<<ADPS0);

    /* Pin configuration */
    PORTB = (1<<PORTB0)|(1<<PORTB1)|(1<<PORTB2)|
            (0<<PORTB3)|(1<<PORTB4)|(1<<PORTB5)|
            (1<<PORTB6)|(1<<PORTB7);
    DDRB = (0<<DDB0)|(0<<DDB1)|(0<<DDB2)|
           (1<<DDB3)|(0<<DDB4)|(0<<DDB5)|
           (0<<DDB6)|(0<<DDB7);
    PORTC = (0<<PORTC0)|(0<<PORTC1)|(1<<PORTC2)|
            (1<<PORTC3)|(1<<PORTC4)|(1<<PORTC5)|
            (1<<PORTC6);
    DDRC = (0<<DDC0)|(0<<DDC1)|(0<<DDC2)|
           (0<<DDC3)|(0<<DDC4)|(0<<DDC5)|
           (0<<DDC6);
    PORTD = (0<<PORTD0)|(0<<PORTD1)|(1<<PORTD2)|
            (1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5)|
            (1<<PORTD6)|(1<<PORTD7);
    DDRD = (0<<DDD0)|(1<<DDD1)|(0<<DDD2)|
           (0<<DDD3)|(0<<DDD4)|(0<<DDD5)|
           (0<<DDD6)|(0<<DDD7);
}

// ========================================================================
// ===================== Common Variables =================================
// ========================================================================

/*
 * #40 <bug> <enchancement>
 *
 *     Modify coefficient format.
 *
 * Let C = one of { KP KI KS }.
 *
 *     C * x = (M * x) >> d
 *
 * Since ATMega8 does not support floating point operations,
 * and just (x << d) or (x >> d) cannot provide precise regulation.
 */

unsigned int kp_m = 0; byte kp_d = 0;   /* proportional factor */
unsigned int ki_m = 0; byte ki_d = 0;   /* integral factor     */
unsigned int ks_m = 0; byte ks_d = 0;   /* scale factor        */

#define COEF(c, x) (((long) x) * (c##_m)) >> (c##_d)

bool  pause  = false; /* paused state                          */
bool  sync   = false; /* USART async/sync transmit operation   */

byte  adc1, adc2;     /* ADC 1st and 2nd channel               */

int   int_err = 0;    /* integral error                        */
int   cur_err = 0;    /* current error                         */
int   pwm     = 0;    /* PWM                                   */

// ========================================================================
// ===================== Message Loop Variables ===========================
// ========================================================================

/*
 * #33 <enchancement>
 *
 *     Simplify IO protocol.
 *
 * The new protocol is user-friendly and quite simple.
 * The typical command starts with `METHOD`
 * (1 byte: `SET`, `GET`, `ECHO`, etc.). The next byte is
 * method-dependent. E.g. `VARIABLE` for `SET` and `GET`.
 * `SET` method also requires the variable value (1..any bytes)
 * to be set.
 *
 * COMMAND = METHOD [CONTENT]
 * METHOD = `SET` | `GET` | `ECHO` | BYTE
 * CONTENT = {
 *     METHOD=`SET`  => VARIABLE [DATA],
 *     METHOD=`GET`  => VARIABLE,
 *     METHOD=`ECHO` => BYTE,
 *     METHOD=BYTE   => any
 * }
 * VARIABLE = BYTE
 * DATA = any
 *
 * BYTE = 1 any byte
 * any = any bytes
 */

byte command_method;
bool command_present = false;
byte command_variable;
bool command_variable_present = false;

/*
 * #47 <enchancement>
 *
 *     Add `COEFS` variable and `PACKET` output format
 *     to support controller-gui tool.
 *
 * Data packet GET format is:
 *     <0 ADC1 ADC2 CUR_ERR INT_ERR PWM OCR2>
 * Coefficient packet SET format is:
 *     <KP KI KS>
 */

#define METHOD_GET     (byte) 0
#define METHOD_SET     (byte) 1
#define METHOD_ECHO    (byte) 2

// SET
#define VAR_PAUSE      (byte) 0
#define VAR_SYNC_USART (byte) 1
#define VAR_KP         (byte) 2
#define VAR_KI         (byte) 3
#define VAR_KS         (byte) 4
#define VAR_COEFS      (byte) 5

// GET
#define NO_OUTPUT      (byte) 0
#define VAR_ADC1       (byte) 1
#define VAR_ADC2       (byte) 2
#define VAR_INT_ERR    (byte) 3
#define VAR_CUR_ERR    (byte) 4
#define VAR_PWM        (byte) 5
#define VAR_OCR2       (byte) 6
#define VAR_PACKET     (byte) 7

byte output_mode = NO_OUTPUT;

// ========================================================================
// ===================== Utility Functions ================================
// ========================================================================

inline byte transmit_all(byte * src, byte length)
{
    return iobuf_write < sp_process_full, lp_use_lock > (usart_obuf, src, length);
}

inline byte receive_all(byte * dst, byte length)
{
    return iobuf_read < sp_process_full, lp_use_lock > (dst, usart_ibuf, length);
}

inline byte receive(byte * dst)
{
    return iobuf_read < lp_use_lock > (*dst, usart_ibuf);
}

void send_all(byte *data, byte size)
{
    if (!sync)
    {
        transmit_all(data, size);
    }
    else
    {
        while (!transmit_all(data, size)) // wait in sync mode
            ;
    }
}

void send_byte(byte data)
{
    send_all(&data, 1);
}

void send_int(unsigned int data)
{
    byte hi_lo[2] = { (byte) (data >> 8), (byte) (data & 0xff) };
    send_all(hi_lo, 2);
}

void send_packet(/* byte adc1, byte adc2, int cur_err, int int_err, int pwm, byte OCR2 */)
{
    /*
     * #53 <enchancement>
     *     Review the packet format.
     *
     * The new packet format is < delimiter | data | checksum >,
     * where checksum is calculated as delimiter ^ adc1 ^ (cerr & 0xff) ^ ocr2.
     */

    byte packet[11] = {
       103,
       adc1,
       adc2,
       ((unsigned int) cur_err) >> 8, cur_err & 0xff,
       ((unsigned int) int_err) >> 8, int_err & 0xff,
       ((unsigned int) pwm) >> 8,     pwm     & 0xff,
       OCR2
    };
    packet[10] = packet[0] ^ packet[1] ^ packet[4] ^ packet[9];
    send_all(packet, 11);
}

// ========================================================================
// ===================== Command Processors ===============================
// ========================================================================

bool process_set_variable()
{
    byte packet[9];
    switch(command_variable)
    {
    case VAR_PAUSE:
        if (!receive(&packet[0])) return false; // wait for the value
        pause = packet[0];
        break;
    case VAR_SYNC_USART:
        if (!receive(packet)) return false; // wait for the value
        sync = packet[0];
        break;
    case VAR_KP:
        if (!receive_all(packet, 3)) return false; // wait for the value
        kp_m = (((unsigned int) packet[0]) << 8) | (packet[1]);
        kp_d = packet[2];
        break;
    case VAR_KI:
        if (!receive_all(packet, 3)) return false; // wait for the value
        ki_m = (((unsigned int) packet[0]) << 8) | (packet[1]);
        ki_d = packet[2];
        break;
    case VAR_KS:
        if (!receive_all(packet, 3)) return false; // wait for the value
        ks_m = (((unsigned int) packet[0]) << 8) | (packet[1]);
        ks_d = packet[2];
        break;
    case VAR_COEFS:
        if (!receive_all(packet, 9)) return false; // wait for the value
        kp_m = (((unsigned int) packet[0]) << 8) | (packet[1]);
        kp_d = packet[2];
        ki_m = (((unsigned int) packet[3]) << 8) | (packet[4]);
        ki_d = packet[5];
        ks_m = (((unsigned int) packet[6]) << 8) | (packet[7]);
        ks_d = packet[8];
        break;
    }
    return true;
}

void process_command()
{
    byte echo_value;
    switch(command_method)
    {
    case METHOD_ECHO:
        if (!receive(&echo_value)) return; // wait for the value to send back
        send_byte(echo_value);
        break;
    case METHOD_GET:
        if (!receive(&output_mode)) return; // wait for the variable
        break;
    case METHOD_SET:
        // wait for the variable
        if (!command_variable_present)
        {
            if (!(command_variable_present = receive(&command_variable))) return;
        }
        if (!process_set_variable()) return; // wait for the argument(s)
        break;
    }
    command_present = false;
    command_variable_present = false;
}

// ========================================================================
// ===================== Program Logic ====================================
// ========================================================================

void do_computations()
{
    /* Read ADC input */

    REMUX(0);                       /* 1st ADC channel                    */
    ADCSR |= (1 << ADSC);           /* Initialize single-ended conversion */
    while(!(ADCSR & (1 << ADIF)))   /* Wait for the end of the conversion */
      ;
    adc1 = ADCH;                    /* Read the 8-bit conversion result   */
    ADCSR &= ~(1 << ADIF);          /* Clear Conversion Complete flag     */

    REMUX(1);                       /* 2nd ADC channel                    */
    ADCSR |= (1 << ADSC);           /* Initialize single-ended conversion */
    while(!(ADCSR & (1 << ADIF)))   /* Wait for the end of the conversion */
      ;
    adc2 = ADCH;                    /* Read the 8-bit conversion result   */
    ADCSR &= ~(1 << ADIF);          /* Clear Conversion Complete flag     */

    /* Calculate PWM width */

    /*
     * pwm = KP * e + KI * err
     */

    cur_err = ((int)(adc2) - (int)(adc1));

    long p = COEF(kp, cur_err), q = COEF(ki, int_err);
    if (ABS(p) > INT_MAX) p = ((p < 0) ? (INT_MIN) : (INT_MAX));
    if (ABS(q) > INT_MAX) q = ((q < 0) ? (INT_MIN) : (INT_MAX));
    pwm = safe_add((int) p, (int) q);

    int_err = safe_add(int_err, cur_err);

    /* Setup PWM width */

    long t = COEF(ks, pwm) + INT_MAX;
    if (ABS(t) > INT_MAX) t = ((p < 0) ? (INT_MIN) : (INT_MAX));

    OCR2 = (((unsigned int) t) + INT_MAX) >> 8;

    /* Report back */

    switch(output_mode)
    {
    case NO_OUTPUT:
        break;
    case VAR_ADC1:
        send_byte(adc1);
        break;
    case VAR_ADC2:
        send_byte(adc2);
        break;
    case VAR_INT_ERR:
        send_int(int_err);
        break;
    case VAR_CUR_ERR:
        send_int(cur_err);
        break;
    case VAR_PWM:
        send_int(pwm);
        break;
    case VAR_OCR2:
        send_byte(OCR2);
        break;
    case VAR_PACKET:
        send_packet();
        break;
    }
}

// ========================================================================
// ===================== Program Entry Point ==============================
// ========================================================================

int main()
{

    /* Initialization here */

    init();

    __enable_interrupt();

    /* Program Loop */

    for(;;)
    {

        /* Message Loop */

        if (command_present)
        {
            process_command();
        }
        else
        {
            command_present = receive(&command_method);
        }

        /* Program Body */

        if (!pause)
        {
            do_computations();
        }

    }

    return 0;
}
<commit_msg>/mc/controller common.h dlib support activated<commit_after>#define DLIB

#include <act-common/common.h>

// ========================================================================
// ===================== Critical Macrodefinitions ========================
// ========================================================================

/*
 * FOSC = 1MHz is confugured via Flash Fuses CKSEL=1 and SUT=2.
 */

#define BAUD_RATE    4800    // 4.8kbps
#define FOSC         1000000 // 1MHz
#define TC2_PRESCALE 1       // no Timer/Counter2 prescale

#include <act-photo/usart.h>
#include <act-photo/pwm.h>

#define REMUX(c) ADMUX = (3<<REFS0)|(1<<ADLAR)|(c<<MUX0)

// ========================================================================
// ===================== Initialization ===================================
// ========================================================================

inline __monitor void init()
{
    /* USART initialization */
    usart_init();
    /* Timer/Counter2 initialization */
    init_tc2_wg();
    /* ADC initialization (1/8 prescaling,
       1st channel, internal Vref, left alignment) */
    REMUX(0);
    ADCSR = (1<<ADEN)|(3<<ADPS0);

    /* Pin configuration */
    PORTB = (1<<PORTB0)|(1<<PORTB1)|(1<<PORTB2)|
            (0<<PORTB3)|(1<<PORTB4)|(1<<PORTB5)|
            (1<<PORTB6)|(1<<PORTB7);
    DDRB = (0<<DDB0)|(0<<DDB1)|(0<<DDB2)|
           (1<<DDB3)|(0<<DDB4)|(0<<DDB5)|
           (0<<DDB6)|(0<<DDB7);
    PORTC = (0<<PORTC0)|(0<<PORTC1)|(1<<PORTC2)|
            (1<<PORTC3)|(1<<PORTC4)|(1<<PORTC5)|
            (1<<PORTC6);
    DDRC = (0<<DDC0)|(0<<DDC1)|(0<<DDC2)|
           (0<<DDC3)|(0<<DDC4)|(0<<DDC5)|
           (0<<DDC6);
    PORTD = (0<<PORTD0)|(0<<PORTD1)|(1<<PORTD2)|
            (1<<PORTD3)|(1<<PORTD4)|(1<<PORTD5)|
            (1<<PORTD6)|(1<<PORTD7);
    DDRD = (0<<DDD0)|(1<<DDD1)|(0<<DDD2)|
           (0<<DDD3)|(0<<DDD4)|(0<<DDD5)|
           (0<<DDD6)|(0<<DDD7);
}

// ========================================================================
// ===================== Common Variables =================================
// ========================================================================

/*
 * #40 <bug> <enchancement>
 *
 *     Modify coefficient format.
 *
 * Let C = one of { KP KI KS }.
 *
 *     C * x = (M * x) >> d
 *
 * Since ATMega8 does not support floating point operations,
 * and just (x << d) or (x >> d) cannot provide precise regulation.
 */

unsigned int kp_m = 0; byte kp_d = 0;   /* proportional factor */
unsigned int ki_m = 0; byte ki_d = 0;   /* integral factor     */
unsigned int ks_m = 0; byte ks_d = 0;   /* scale factor        */

#define COEF(c, x) (((long) x) * (c##_m)) >> (c##_d)

bool  pause  = false; /* paused state                          */
bool  sync   = false; /* USART async/sync transmit operation   */

byte  adc1, adc2;     /* ADC 1st and 2nd channel               */

int   int_err = 0;    /* integral error                        */
int   cur_err = 0;    /* current error                         */
int   pwm     = 0;    /* PWM                                   */

// ========================================================================
// ===================== Message Loop Variables ===========================
// ========================================================================

/*
 * #33 <enchancement>
 *
 *     Simplify IO protocol.
 *
 * The new protocol is user-friendly and quite simple.
 * The typical command starts with `METHOD`
 * (1 byte: `SET`, `GET`, `ECHO`, etc.). The next byte is
 * method-dependent. E.g. `VARIABLE` for `SET` and `GET`.
 * `SET` method also requires the variable value (1..any bytes)
 * to be set.
 *
 * COMMAND = METHOD [CONTENT]
 * METHOD = `SET` | `GET` | `ECHO` | BYTE
 * CONTENT = {
 *     METHOD=`SET`  => VARIABLE [DATA],
 *     METHOD=`GET`  => VARIABLE,
 *     METHOD=`ECHO` => BYTE,
 *     METHOD=BYTE   => any
 * }
 * VARIABLE = BYTE
 * DATA = any
 *
 * BYTE = 1 any byte
 * any = any bytes
 */

byte command_method;
bool command_present = false;
byte command_variable;
bool command_variable_present = false;

/*
 * #47 <enchancement>
 *
 *     Add `COEFS` variable and `PACKET` output format
 *     to support controller-gui tool.
 *
 * Data packet GET format is:
 *     <0 ADC1 ADC2 CUR_ERR INT_ERR PWM OCR2>
 * Coefficient packet SET format is:
 *     <KP KI KS>
 */

#define METHOD_GET     (byte) 0
#define METHOD_SET     (byte) 1
#define METHOD_ECHO    (byte) 2

// SET
#define VAR_PAUSE      (byte) 0
#define VAR_SYNC_USART (byte) 1
#define VAR_KP         (byte) 2
#define VAR_KI         (byte) 3
#define VAR_KS         (byte) 4
#define VAR_COEFS      (byte) 5

// GET
#define NO_OUTPUT      (byte) 0
#define VAR_ADC1       (byte) 1
#define VAR_ADC2       (byte) 2
#define VAR_INT_ERR    (byte) 3
#define VAR_CUR_ERR    (byte) 4
#define VAR_PWM        (byte) 5
#define VAR_OCR2       (byte) 6
#define VAR_PACKET     (byte) 7

byte output_mode = NO_OUTPUT;

// ========================================================================
// ===================== Utility Functions ================================
// ========================================================================

inline byte transmit_all(byte * src, byte length)
{
    return iobuf_write < sp_process_full, lp_use_lock > (usart_obuf, src, length);
}

inline byte receive_all(byte * dst, byte length)
{
    return iobuf_read < sp_process_full, lp_use_lock > (dst, usart_ibuf, length);
}

inline byte receive(byte * dst)
{
    return iobuf_read < lp_use_lock > (*dst, usart_ibuf);
}

void send_all(byte *data, byte size)
{
    if (!sync)
    {
        transmit_all(data, size);
    }
    else
    {
        while (!transmit_all(data, size)) // wait in sync mode
            ;
    }
}

void send_byte(byte data)
{
    send_all(&data, 1);
}

void send_int(unsigned int data)
{
    byte hi_lo[2] = { (byte) (data >> 8), (byte) (data & 0xff) };
    send_all(hi_lo, 2);
}

void send_packet(/* byte adc1, byte adc2, int cur_err, int int_err, int pwm, byte OCR2 */)
{
    /*
     * #53 <enchancement>
     *     Review the packet format.
     *
     * The new packet format is < delimiter | data | checksum >,
     * where checksum is calculated as delimiter ^ adc1 ^ (cerr & 0xff) ^ ocr2.
     */

    byte packet[11] = {
       103,
       adc1,
       adc2,
       ((unsigned int) cur_err) >> 8, cur_err & 0xff,
       ((unsigned int) int_err) >> 8, int_err & 0xff,
       ((unsigned int) pwm) >> 8,     pwm     & 0xff,
       OCR2
    };
    packet[10] = packet[0] ^ packet[1] ^ packet[4] ^ packet[9];
    send_all(packet, 11);
}

// ========================================================================
// ===================== Command Processors ===============================
// ========================================================================

bool process_set_variable()
{
    byte packet[9];
    switch(command_variable)
    {
    case VAR_PAUSE:
        if (!receive(&packet[0])) return false; // wait for the value
        pause = packet[0];
        break;
    case VAR_SYNC_USART:
        if (!receive(packet)) return false; // wait for the value
        sync = packet[0];
        break;
    case VAR_KP:
        if (!receive_all(packet, 3)) return false; // wait for the value
        kp_m = (((unsigned int) packet[0]) << 8) | (packet[1]);
        kp_d = packet[2];
        break;
    case VAR_KI:
        if (!receive_all(packet, 3)) return false; // wait for the value
        ki_m = (((unsigned int) packet[0]) << 8) | (packet[1]);
        ki_d = packet[2];
        break;
    case VAR_KS:
        if (!receive_all(packet, 3)) return false; // wait for the value
        ks_m = (((unsigned int) packet[0]) << 8) | (packet[1]);
        ks_d = packet[2];
        break;
    case VAR_COEFS:
        if (!receive_all(packet, 9)) return false; // wait for the value
        kp_m = (((unsigned int) packet[0]) << 8) | (packet[1]);
        kp_d = packet[2];
        ki_m = (((unsigned int) packet[3]) << 8) | (packet[4]);
        ki_d = packet[5];
        ks_m = (((unsigned int) packet[6]) << 8) | (packet[7]);
        ks_d = packet[8];
        break;
    }
    return true;
}

void process_command()
{
    byte echo_value;
    switch(command_method)
    {
    case METHOD_ECHO:
        if (!receive(&echo_value)) return; // wait for the value to send back
        send_byte(echo_value);
        break;
    case METHOD_GET:
        if (!receive(&output_mode)) return; // wait for the variable
        break;
    case METHOD_SET:
        // wait for the variable
        if (!command_variable_present)
        {
            if (!(command_variable_present = receive(&command_variable))) return;
        }
        if (!process_set_variable()) return; // wait for the argument(s)
        break;
    }
    command_present = false;
    command_variable_present = false;
}

// ========================================================================
// ===================== Program Logic ====================================
// ========================================================================

void do_computations()
{
    /* Read ADC input */

    REMUX(0);                       /* 1st ADC channel                    */
    ADCSR |= (1 << ADSC);           /* Initialize single-ended conversion */
    while(!(ADCSR & (1 << ADIF)))   /* Wait for the end of the conversion */
      ;
    adc1 = ADCH;                    /* Read the 8-bit conversion result   */
    ADCSR &= ~(1 << ADIF);          /* Clear Conversion Complete flag     */

    REMUX(1);                       /* 2nd ADC channel                    */
    ADCSR |= (1 << ADSC);           /* Initialize single-ended conversion */
    while(!(ADCSR & (1 << ADIF)))   /* Wait for the end of the conversion */
      ;
    adc2 = ADCH;                    /* Read the 8-bit conversion result   */
    ADCSR &= ~(1 << ADIF);          /* Clear Conversion Complete flag     */

    /* Calculate PWM width */

    /*
     * pwm = KP * e + KI * err
     */

    cur_err = ((int)(adc2) - (int)(adc1));

    long p = COEF(kp, cur_err), q = COEF(ki, int_err);
    if (ABS(p) > INT_MAX) p = ((p < 0) ? (INT_MIN) : (INT_MAX));
    if (ABS(q) > INT_MAX) q = ((q < 0) ? (INT_MIN) : (INT_MAX));
    pwm = safe_add((int) p, (int) q);

    int_err = safe_add(int_err, cur_err);

    /* Setup PWM width */

    long t = COEF(ks, pwm) + INT_MAX;
    if (ABS(t) > INT_MAX) t = ((p < 0) ? (INT_MIN) : (INT_MAX));

    OCR2 = (((unsigned int) t) + INT_MAX) >> 8;

    /* Report back */

    switch(output_mode)
    {
    case NO_OUTPUT:
        break;
    case VAR_ADC1:
        send_byte(adc1);
        break;
    case VAR_ADC2:
        send_byte(adc2);
        break;
    case VAR_INT_ERR:
        send_int(int_err);
        break;
    case VAR_CUR_ERR:
        send_int(cur_err);
        break;
    case VAR_PWM:
        send_int(pwm);
        break;
    case VAR_OCR2:
        send_byte(OCR2);
        break;
    case VAR_PACKET:
        send_packet();
        break;
    }
}

// ========================================================================
// ===================== Program Entry Point ==============================
// ========================================================================

int main()
{

    /* Initialization here */

    init();

    __enable_interrupt();

    /* Program Loop */

    for(;;)
    {

        /* Message Loop */

        if (command_present)
        {
            process_command();
        }
        else
        {
            command_present = receive(&command_method);
        }

        /* Program Body */

        if (!pause)
        {
            do_computations();
        }

    }

    return 0;
}
<|endoftext|>


<commit_before>#ifndef		__WORLD_HH__
#define		__WORLD_HH__

#include	<cmath>
#include	<cstdio>
#include	<stdint.h>
#include	<vector>
#include	<algorithm>
#include	"../vbam/gba/Globals.h"
#include	"PokemonUtils.hh"

class		World
{
private:
  struct	Header
  {
    uint32_t	mapPtr;
    uint32_t	evtPtr;
    uint32_t	scriptPtr;
    uint32_t	connectPtr;
    uint16_t	musicId;
    uint16_t	mapId;
    uint8_t	labelId;
    uint8_t	flash;
    uint8_t	weather;
    uint8_t	type;
    uint16_t	unknown;
    uint8_t	showLabel;
    uint8_t	battleType;
  };

  struct	DataHeader
  {
    uint32_t	width;
    uint32_t	height;
    uint32_t	border;
    uint32_t	data;
    uint32_t	globalTileset;
    uint32_t	localTileset;
    uint8_t	borderW;
    uint8_t	borderH;
  };

  struct	TilesetHeader
  {
    uint8_t	compressed;
    uint8_t	primary;
    uint16_t	unknown;
    uint32_t	imgPtr;
    uint32_t	palettePtr;
    uint32_t	blocksPtr;
    uint32_t	animPtr;
    uint32_t	behaviorPtr;
  };

  struct	Event
  {
    uint8_t	nbPersons;
    uint8_t	nbWarps;
    uint8_t	nbScripts;
    uint8_t	nbSigns;
    uint32_t	personsPtr;
    uint32_t	warpsPtr;
    uint32_t	scriptsPtr;
    uint32_t	signsPtr;
  };

  struct	SignEvt
  {
    uint16_t	x;
    uint16_t	y;
    uint8_t	level;
    uint8_t	type;
    uint32_t	scriptPtr;
  };

  struct	WarpEvt
  {
    uint16_t	x;
    uint16_t	y;
    uint8_t	level;
    uint8_t	destWarp;
    uint8_t	destMap;
    uint8_t	destBank;
  };

  struct	PersonEvt
  {
    uint8_t	evtNb;
    uint8_t	pictureNb;
    uint16_t	unknown;
    uint16_t	x;
    uint16_t	y;
    uint8_t	level;
    uint8_t	mvtType;
    uint8_t	mvt;
    uint8_t	unknown2;
    uint8_t	trainer;
    uint8_t	unknown3;
    uint16_t	view;
    uint32_t	scriptPtr;
    uint16_t	id;
    uint16_t	unknown4;

    bool	isVisible() const
    {
      if (!id)
	return (true);
      return (!getFlag(id));
    }
  };

  struct	ScriptEvt
  {
    uint16_t	x;
    uint16_t	y;
    uint8_t	level;
    uint8_t	unknown;
    uint16_t	varNb;
    uint16_t	varVal;
    uint16_t	unknown2;
    uint32_t	scriptPtr;
  };

  struct	Connection
  {
    uint32_t	type;
    uint32_t	offset;
    uint8_t	bank;
    uint8_t	map;
    uint16_t	padding;
  };

  struct	WildHeader
  {
    uint8_t	bank;
    uint8_t	map;
    uint16_t	padding;
    uint32_t	entryPtr[4];
  };

  struct	WildEntry
  {
    uint8_t	minLvl;
    uint8_t	maxLvl;
    uint16_t	species;
  };

public:
  struct	Map
  {
    struct	TileAttr
    {
      uint16_t	behavior;
      uint16_t	bg;
    };

    struct	Node
    {
      uint8_t	status;
      uint16_t	tile;
      TileAttr	*attr;
      Node	*from;
      uint32_t	g;
      uint32_t	f;
      uint32_t	x;
      uint32_t	y;

      Node(uint32_t px = 0, uint32_t py = 0) : status(0), from(NULL), g(0), f(0), x(px), y(py) {}
      void	setG(uint32_t pg) { g = pg; }
      void	setF(uint32_t xe, uint32_t ye) { f = g + 10 * sqrt(POW(xe - x) + POW(ye - y)); }

      uint8_t   getStatus() const { return (status); }
      uint16_t  getBehavior() const { return (attr->behavior); }
      uint16_t  getBackground() const { return (attr->bg); }
      uint32_t  getX() const { return (x); }
      uint32_t  getY() const { return (y); }
    };

    struct	WildBattle
    {
      uint8_t	ratio;
      WildEntry	*entries;
      uint8_t	nbEntries;
    };

    enum
      {
	ROCK = 35,
	HILL = 35,
	LADDER = 34,
	WATER = 36,
	ROAD = 32,
	WALL = 30,
	PLAYER = 31
      };

    uint64_t	width;
    uint64_t	height;
    Node	**data;
    uint8_t	nbPersons;
    uint8_t	nbWarps;
    uint8_t	nbScripts;
    uint8_t	nbSigns;
    PersonEvt	*persons;
    WarpEvt	*warps;
    ScriptEvt	*scripts;
    SignEvt	*signs;
    uint32_t	nbConnects;
    Connection	*connects;
    uint32_t	scriptPtr;
    WildBattle	wildBattles[4];
    uint8_t     labelId;
    std::string name;

  public:
    // Getters
    uint64_t    getWidth() const { return (width); }
    uint64_t    getHeight() const { return (height); }
    const Node  &getNode(uint8_t x, uint8_t y) const { return (data[y][x]); }
    uint8_t     getNbPersons() const { return (nbPersons); }
    uint8_t     getNbWarps() const { return (nbWarps); }
    uint8_t     getNbScripts() const { return (nbScripts); }
    uint8_t     getNbSigns() const { return (nbSigns); }
    uint32_t    getNbConnections() const { return (nbConnects); }
    uint32_t    getScripPtr() const { return (scriptPtr); }
    uint8_t     getLabelId() const { return (labelId); }
    const std::string&  getName() const { return (name); }

  public:
    void                loadName(uint8_t id);
    Node		*operator[](uint8_t y) { return (data[y]); }
    inline uint8_t	getMatterColor(uint8_t matter, bool pos) {
      return (pos ? PLAYER:
	      !matter ? LADDER :
	      matter == 1 ? WALL :
	      matter == 4 ? WATER :
	      matter == 12 ? ROAD :
	      matter == 13 ? HILL :
	      matter == 16 ? LADDER : 0);
    }
  };
  typedef	std::vector<Map::Node*>	Path;

public:
  World();
  ~World();

private:
  void		_initWorld();
  void		_initWildBattles();

public:
  std::vector<Map>	&operator[](uint8_t bank) { return (_banks[(bank < _banks.size()) * bank]); }
  Map                   &getMap(uint8_t bank, uint8_t map) { return ((*this)[bank][(map < (*this)[bank].size()) * map]); }

public:
  std::vector<std::vector<Map> >	_banks;
};

#endif
<commit_msg>add: getters for events and connection data<commit_after>#ifndef		__WORLD_HH__
#define		__WORLD_HH__

#include	<cmath>
#include	<cstdio>
#include	<stdint.h>
#include	<vector>
#include	<algorithm>
#include	"../vbam/gba/Globals.h"
#include	"PokemonUtils.hh"

class		World
{
private:
  struct	Header
  {
    uint32_t	mapPtr;
    uint32_t	evtPtr;
    uint32_t	scriptPtr;
    uint32_t	connectPtr;
    uint16_t	musicId;
    uint16_t	mapId;
    uint8_t	labelId;
    uint8_t	flash;
    uint8_t	weather;
    uint8_t	type;
    uint16_t	unknown;
    uint8_t	showLabel;
    uint8_t	battleType;
  };

  struct	DataHeader
  {
    uint32_t	width;
    uint32_t	height;
    uint32_t	border;
    uint32_t	data;
    uint32_t	globalTileset;
    uint32_t	localTileset;
    uint8_t	borderW;
    uint8_t	borderH;
  };

  struct	TilesetHeader
  {
    uint8_t	compressed;
    uint8_t	primary;
    uint16_t	unknown;
    uint32_t	imgPtr;
    uint32_t	palettePtr;
    uint32_t	blocksPtr;
    uint32_t	animPtr;
    uint32_t	behaviorPtr;
  };

  struct	Event
  {
    uint8_t	nbPersons;
    uint8_t	nbWarps;
    uint8_t	nbScripts;
    uint8_t	nbSigns;
    uint32_t	personsPtr;
    uint32_t	warpsPtr;
    uint32_t	scriptsPtr;
    uint32_t	signsPtr;
  };

public:
  struct	SignEvt
  {
    uint16_t	x;
    uint16_t	y;
    uint8_t	level;
    uint8_t	type;
    uint32_t	scriptPtr;

    uint16_t	getX() const { return (x); }
    uint16_t	getY() const { return (y); }
    uint8_t	getLevel() const { return (level); }
    uint16_t	getTyoe() const { return (type); }
    uint32_t	getScript() const { return (scriptPtr); }
  };

  struct	WarpEvt
  {
    uint16_t	x;
    uint16_t	y;
    uint8_t	level;
    uint8_t	destWarp;
    uint8_t	destMap;
    uint8_t	destBank;

    uint16_t	getX() const { return (x); }
    uint16_t	getY() const { return (y); }
    uint8_t	getLevel() const { return (level); }
    uint8_t	getWarp() const { return (destWarp); }
    uint8_t	getMap() const { return (destMap); }
    uint8_t	getBank() const { return (destBank); }
  };

  struct	PersonEvt
  {
    uint8_t	evtNb;
    uint8_t	pictureNb;
    uint16_t	unknown;
    uint16_t	x;
    uint16_t	y;
    uint8_t	level;
    uint8_t	mvtType;
    uint8_t	mvt;
    uint8_t	unknown2;
    uint8_t	trainer;
    uint8_t	unknown3;
    uint16_t	view;
    uint32_t	scriptPtr;
    uint16_t	id;
    uint16_t	unknown4;

    bool	isVisible() const
    {
      if (!id)
	return (true);
      return (!getFlag(id));
    }
    uint8_t     getEventNb() const { return (evtNb); }
    uint16_t	getX() const { return (x); }
    uint16_t	getY() const { return (y); }
    uint8_t	getLevel() const { return (level); }
    uint8_t	getMovementType() const { return (mvtType); }
    uint8_t	getMovement() const { return (mvt); }
    bool	isTrainer() const { return (trainer); }
    uint16_t	getView() const { return (view); }
    uint32_t	getScript() const { return (scriptPtr); }
    uint16_t	getId() const { return (id); }
  };

  struct	ScriptEvt
  {
    uint16_t	x;
    uint16_t	y;
    uint8_t	level;
    uint8_t	unknown;
    uint16_t	varNb;
    uint16_t	varVal;
    uint16_t	unknown2;
    uint32_t	scriptPtr;

    uint16_t	getX() const { return (x); }
    uint16_t	getY() const { return (y); }
    uint8_t	getLevel() const { return (level); }
    uint8_t	getVarNb() const { return (varNb); }
    uint8_t	getVarValue() const { return (varVal); }
    uint32_t	getScript() const { return (scriptPtr); }
  };

  struct	Connection
  {
    uint32_t	type;
    uint32_t	offset;
    uint8_t	bank;
    uint8_t	map;
    uint16_t	padding;

    uint32_t	getType() const { return (type); }
    uint32_t	getOffset() const { return (offset); }
    uint8_t	getBank() const { return (bank); }
    uint8_t	getMap() const { return (map); }
    uint16_t	getPadding() const { return (padding); }
  };

  struct	WildHeader
  {
    uint8_t	bank;
    uint8_t	map;
    uint16_t	padding;
    uint32_t	entryPtr[4];
  };

  struct	WildEntry
  {
    uint8_t	minLvl;
    uint8_t	maxLvl;
    uint16_t	species;
  };

public:
  struct	Map
  {
    struct	TileAttr
    {
      uint16_t	behavior;
      uint16_t	bg;
    };

    struct	Node
    {
      uint8_t	status;
      uint16_t	tile;
      TileAttr	*attr;
      Node	*from;
      uint32_t	g;
      uint32_t	f;
      uint32_t	x;
      uint32_t	y;

      Node(uint32_t px = 0, uint32_t py = 0) : status(0), from(NULL), g(0), f(0), x(px), y(py) {}
      void	setG(uint32_t pg) { g = pg; }
      void	setF(uint32_t xe, uint32_t ye) { f = g + 10 * sqrt(POW(xe - x) + POW(ye - y)); }

      uint8_t   getStatus() const { return (status); }
      uint16_t  getBehavior() const { return (attr->behavior); }
      uint16_t  getBackground() const { return (attr->bg); }
      uint32_t  getX() const { return (x); }
      uint32_t  getY() const { return (y); }
    };

    struct	WildBattle
    {
      uint8_t	ratio;
      WildEntry	*entries;
      uint8_t	nbEntries;
    };

    enum
      {
	ROCK = 35,
	HILL = 35,
	LADDER = 34,
	WATER = 36,
	ROAD = 32,
	WALL = 30,
	PLAYER = 31
      };

    uint64_t	width;
    uint64_t	height;
    Node	**data;
    uint8_t	nbPersons;
    uint8_t	nbWarps;
    uint8_t	nbScripts;
    uint8_t	nbSigns;
    PersonEvt	*persons;
    WarpEvt	*warps;
    ScriptEvt	*scripts;
    SignEvt	*signs;
    uint32_t	nbConnects;
    Connection	*connects;
    uint32_t	scriptPtr;
    WildBattle	wildBattles[4];
    uint8_t     labelId;
    std::string name;

  public:
    // Getters
    uint64_t    getWidth() const { return (width); }
    uint64_t    getHeight() const { return (height); }
    const Node  &getNode(uint8_t x, uint8_t y) const { return (data[y][x]); }
    uint8_t     getNbPersons() const { return (nbPersons); }
    uint8_t     getNbWarps() const { return (nbWarps); }
    uint8_t     getNbScripts() const { return (nbScripts); }
    uint8_t     getNbSigns() const { return (nbSigns); }
    uint32_t    getNbConnections() const { return (nbConnects); }
    uint32_t    getScripPtr() const { return (scriptPtr); }
    uint8_t     getLabelId() const { return (labelId); }
    const std::string&  getName() const { return (name); }

  public:
    void                loadName(uint8_t id);
    Node		*operator[](uint8_t y) { return (data[y]); }
    inline uint8_t	getMatterColor(uint8_t matter, bool pos) {
      return (pos ? PLAYER:
	      !matter ? LADDER :
	      matter == 1 ? WALL :
	      matter == 4 ? WATER :
	      matter == 12 ? ROAD :
	      matter == 13 ? HILL :
	      matter == 16 ? LADDER : 0);
    }
  };
  typedef	std::vector<Map::Node*>	Path;

public:
  World();
  ~World();

private:
  void		_initWorld();
  void		_initWildBattles();

public:
  std::vector<Map>	&operator[](uint8_t bank) { return (_banks[(bank < _banks.size()) * bank]); }
  Map                   &getMap(uint8_t bank, uint8_t map) { return ((*this)[bank][(map < (*this)[bank].size()) * map]); }

public:
  std::vector<std::vector<Map> >	_banks;
};

#endif
<|endoftext|>


<commit_before>#pragma once

#include "kernel.hh"
#include "refcache.hh"
#include "chainhash.hh"
#include "radix_array.hh"
#include "page_info.hh"
#include "kalloc.hh"
#include "fs.h"

#include <limits.h>

class mdir;
class mfile;
class mdev;
class msock;

class mnode : public refcache::weak_referenced
{
private:
  struct inumber {
    u64 v_;
    static const int type_bits = 8;
    static const int cpu_bits = 8;

    inumber(u64 v) : v_(v) {}
    inumber(u8 type, u64 cpu, u64 count)
      : v_(type | (cpu << type_bits) | (count << (type_bits + cpu_bits)))
    {
      assert(type < (1 << type_bits));
      assert(cpu < (1 << cpu_bits));
    }

    u8 type() {
      return v_ & ((1 << type_bits) - 1);
    }
  };

public:
  struct types {
    enum {
      dir = 1,
      file,
      dev,
      sock,
    };
  };

  static sref<mnode> get(u64 n);
  static sref<mnode> alloc(u8 type);

  void cache_pin(bool flag);
  u8 type() const { return inumber(inum_).type(); }

  mdir* as_dir();
  const mdir* as_dir() const;
  mfile* as_file();
  const mfile* as_file() const;
  mdev* as_dev();
  const mdev* as_dev() const;
  msock* as_sock();
  const msock* as_sock() const;

  class linkcount : public FS_NLINK_REFCOUNT referenced {
  public:
    linkcount() : referenced(0) {};
    void onzero() override;
  };

  const u64 inum_;
  linkcount nlink_;

protected:
  mnode(u64 inum);

private:
  void onzero() override;

  std::atomic<bool> cache_pin_;
  std::atomic<bool> dirty_;
  std::atomic<bool> valid_;
};

/*
 * An mlinkref represents a link count reference on an mnode.
 * The caller must ensure that mlinkref::acquire() is not called
 * after mnode::nlink_ reaches stable zero, perhaps by blocking
 * refcache epochs using cli when looking up the inode number in
 * a directory.
 *
 * Each mlinkref holds a reference to the mnode as well, to ensure
 * that the memory used to store the nlink_ count is not evicted
 * before all of the refcache deltas are flushed.  Otherwise this
 * would just be an sref<linkcount>.
 */
class mlinkref {
public:
  mlinkref() {}
  mlinkref(sref<mnode> mref) : m_(mref) {}

  sref<mnode> mn() {
    return m_;
  }

  bool held() {
    return !!l_;
  }

  /*
   * Increment the link count on the mnode.
   */
  void acquire() {
    assert(m_ && !l_);
    l_ = sref<mnode::linkcount>::newref(&m_->nlink_);
  }

  /*
   * Transfer an existing link count on the mnode to this mlinkref.
   */
  void transfer() {
    assert(m_ && !l_);
    l_ = sref<mnode::linkcount>::transfer(&m_->nlink_);
  }

private:
  /*
   * The order is important due to C++ constructor/destructor
   * rules: we must hold the mnode reference while manipulating
   * the linkcount reference.
   */
  sref<mnode> m_;
  sref<mnode::linkcount> l_;
};

class mdir : public mnode {
private:
  mdir(u64 inum) : mnode(inum), map_(257) {}
  NEW_DELETE_OPS(mdir);
  friend sref<mnode> mnode::get(u64);

  chainhash<strbuf<DIRSIZ>, u64> map_;

public:
  bool insert(const strbuf<DIRSIZ>& name, mlinkref* ilink) {
    if (name == ".")
      return false;
    if (!map_.insert(name, ilink->mn()->inum_))
      return false;
    assert(ilink->held());
    ilink->mn()->nlink_.inc();
    return true;
  }

  bool remove(const strbuf<DIRSIZ>& name, sref<mnode> m) {
    if (!map_.remove(name, m->inum_))
      return false;
    m->nlink_.dec();
    return true;
  }

  bool replace(const strbuf<DIRSIZ>& name, sref<mnode> mold, mlinkref* ilinknew) {
    if (mold->inum_ == ilinknew->mn()->inum_)
      return true;
    if (!map_.replace(name, mold->inum_, ilinknew->mn()->inum_))
      return false;
    assert(ilinknew->held());
    ilinknew->mn()->nlink_.inc();
    mold->nlink_.dec();
    return true;
  }

  bool exists(const strbuf<DIRSIZ>& name) const {
    if (name == ".")
      return true;

    return map_.lookup(name);
  }

  sref<mnode> lookup(const strbuf<DIRSIZ>& name) const {
    if (name == ".")
      return mnode::get(inum_);

    u64 iprev = -1;
    for (;;) {
      u64 inum;
      if (!map_.lookup(name, &inum))
        return sref<mnode>();

      sref<mnode> m = mnode::get(inum);
      if (m)
        return m;

      /*
       * The inode was GCed between the lookup and mnode::get().
       * Retry the lookup.  Crash if we repeatedly can't find
       * the same inode (to make such bugs easier to track down).
       */
      assert(inum != iprev);
      iprev = inum;
    }
  }

  mlinkref lookup_link(const strbuf<DIRSIZ>& name) const {
    if (name == ".")
      /*
       * We cannot convert the name "." to a link count on the mnode,
       * because "." does not hold a link count of its own.
       */
      return mlinkref();

    for (;;) {
      sref<mnode> m = lookup(name);
      if (!m)
        return mlinkref();

      scoped_cli cli;
      /*
       * Retry the lookup, now that we have an sref<mnode>, since
       * we don't want to do lookup's mnode::get() under cli.
       */
      u64 inum;
      if (!map_.lookup(name, &inum) || inum != m->inum_)
        /*
         * The name has either been unlinked or changed to point
         * to another inode.  Retry.
         */
        continue;

      mlinkref ilink(m);

      /*
       * At this point, we know the inode had a non-zero link
       * count prior to the second lookup.  Since we are holding
       * cli, refcache cannot advance its epoch, and will not
       * garbage-collect the inode until after we release cli.
       *
       * Mild POSIX violation: an inode can appear to have a
       * zero link count, according to fstat, but get a positive
       * link counter later, because the fstat occurs after the
       * last name has been unlinked, but before we increment
       * the link count here.
       */

      ilink.acquire();

      /*
       * Mild POSIX violation: an inode can appear to have a
       * link count, according to fstat, that is higher than
       * the number of all its names.  For instance, sys_link()
       * first grabs a mlinkref on the existing name, and then
       * drops it if the new name already exists.
       */

      return ilink;
    }
  }

  bool enumerate(const strbuf<DIRSIZ>* prev, strbuf<DIRSIZ>* name) const {
    if (!prev) {
      *name = ".";
      return true;
    }

    if (*prev == ".")
      prev = nullptr;

    return map_.enumerate(prev, name);
  }

  bool kill(sref<mnode> parent) {
    if (!map_.remove_and_kill("..", parent->inum_))
      return false;

    parent->nlink_.dec();
    return true;
  }

  bool killed() const {
    return map_.killed();
  }
};

inline mdir*
mnode::as_dir()
{
  assert(type() == types::dir);
  return static_cast<mdir*>(this);
}

inline const mdir*
mnode::as_dir() const
{
  assert(type() == types::dir);
  return static_cast<const mdir*>(this);
}

class mfile : public mnode {
private:
  mfile(u64 inum) : mnode(inum), size_(0) {}
  NEW_DELETE_OPS(mfile);
  friend sref<mnode> mnode::get(u64);

  struct page_state {
    enum {
      FLAG_LOCK_BIT = 0,
      FLAG_LOCK = 1 << FLAG_LOCK_BIT,
      FLAG_SET = 1 << 1,
    };

    page_state() : flags(0) {}
    page_state(sref<page_info> p) : flags(FLAG_SET), pg(p) {}

    bool is_set() const {
      return flags & FLAG_SET;
    }

    bit_spinlock get_lock() {
      return bit_spinlock(&flags, FLAG_LOCK_BIT);
    }

    u64 flags;
    sref<page_info> pg;
  };

  enum { maxidx = ULONG_MAX / PGSIZE + 1 };
  radix_array<page_state, maxidx, PGSIZE,
              kalloc_allocator<page_state>> pages_;

  spinlock resize_lock_;
  seqcount<u32> size_seq_;
  u64 size_;

public:
  class resizer : public lock_guard<spinlock>,
                  public seq_writer {
  private:
    resizer(mfile* mf) : lock_guard<spinlock>(&mf->resize_lock_),
                         seq_writer(&mf->size_seq_),
                         mf_(mf) {}
    mfile* mf_;
    friend class mfile;

  public:
    resizer() : mf_(nullptr) {}
    explicit operator bool () const { return !!mf_; }
    u64 read_size() { return mf_->size_; }
    void resize_nogrow(u64 size);
    void resize_append(u64 size, sref<page_info> pi);
  };

  resizer write_size() {
    return resizer(this);
  }

  seq_reader<u64> read_size() {
    return seq_reader<u64>(&size_, &size_seq_);
  }

  sref<page_info> get_page(u64 pageidx);
};

inline mfile*
mnode::as_file()
{
  assert(type() == types::file);
  return static_cast<mfile*>(this);
}

inline const mfile*
mnode::as_file() const
{
  assert(type() == types::file);
  return static_cast<const mfile*>(this);
}

class mdev : public mnode {
private:
  mdev(u64 inum) : mnode(inum), major_(0), minor_(0) {}
  NEW_DELETE_OPS(mdev);
  friend sref<mnode> mnode::get(u64);

  u16 major_;
  u16 minor_;

public:
  u16 major() const { return major_; }
  u16 minor() const { return minor_; }

  void init(u16 major, u16 minor) {
    assert(!major_ && !minor_);
    major_ = major;
    minor_ = minor;
  }
};

inline mdev*
mnode::as_dev()
{
  assert(type() == types::dev);
  return static_cast<mdev*>(this);
}

inline const mdev*
mnode::as_dev() const
{
  assert(type() == types::dev);
  return static_cast<const mdev*>(this);
}

class msock : public mnode {
private:
  msock(u64 inum) : mnode(inum), localsock_(nullptr) {}
  NEW_DELETE_OPS(msock);
  friend sref<mnode> mnode::get(u64);

  localsock* localsock_;

public:
  localsock* get_sock() const { return localsock_; }

  void init(localsock* ls) {
    assert(!localsock_);
    localsock_ = ls;
  }
};

inline msock*
mnode::as_sock()
{
  assert(type() == types::sock);
  return static_cast<msock*>(this);
}

inline const msock*
mnode::as_sock() const
{
  assert(type() == types::sock);
  return static_cast<const msock*>(this);
}
<commit_msg>mnode: Put nlink on its own cache line<commit_after>#pragma once

#include "kernel.hh"
#include "refcache.hh"
#include "chainhash.hh"
#include "radix_array.hh"
#include "page_info.hh"
#include "kalloc.hh"
#include "fs.h"

#include <limits.h>

class mdir;
class mfile;
class mdev;
class msock;

class mnode : public refcache::weak_referenced
{
private:
  struct inumber {
    u64 v_;
    static const int type_bits = 8;
    static const int cpu_bits = 8;

    inumber(u64 v) : v_(v) {}
    inumber(u8 type, u64 cpu, u64 count)
      : v_(type | (cpu << type_bits) | (count << (type_bits + cpu_bits)))
    {
      assert(type < (1 << type_bits));
      assert(cpu < (1 << cpu_bits));
    }

    u8 type() {
      return v_ & ((1 << type_bits) - 1);
    }
  };

public:
  struct types {
    enum {
      dir = 1,
      file,
      dev,
      sock,
    };
  };

  static sref<mnode> get(u64 n);
  static sref<mnode> alloc(u8 type);

  void cache_pin(bool flag);
  u8 type() const { return inumber(inum_).type(); }

  mdir* as_dir();
  const mdir* as_dir() const;
  mfile* as_file();
  const mfile* as_file() const;
  mdev* as_dev();
  const mdev* as_dev() const;
  msock* as_sock();
  const msock* as_sock() const;

  class linkcount : public FS_NLINK_REFCOUNT referenced {
  public:
    linkcount() : referenced(0) {};
    void onzero() override;
  };

  const u64 inum_;
  linkcount nlink_ __mpalign__;
  __padout__;

protected:
  mnode(u64 inum);

private:
  void onzero() override;

  std::atomic<bool> cache_pin_;
  std::atomic<bool> dirty_;
  std::atomic<bool> valid_;
};

/*
 * An mlinkref represents a link count reference on an mnode.
 * The caller must ensure that mlinkref::acquire() is not called
 * after mnode::nlink_ reaches stable zero, perhaps by blocking
 * refcache epochs using cli when looking up the inode number in
 * a directory.
 *
 * Each mlinkref holds a reference to the mnode as well, to ensure
 * that the memory used to store the nlink_ count is not evicted
 * before all of the refcache deltas are flushed.  Otherwise this
 * would just be an sref<linkcount>.
 */
class mlinkref {
public:
  mlinkref() {}
  mlinkref(sref<mnode> mref) : m_(mref) {}

  sref<mnode> mn() {
    return m_;
  }

  bool held() {
    return !!l_;
  }

  /*
   * Increment the link count on the mnode.
   */
  void acquire() {
    assert(m_ && !l_);
    l_ = sref<mnode::linkcount>::newref(&m_->nlink_);
  }

  /*
   * Transfer an existing link count on the mnode to this mlinkref.
   */
  void transfer() {
    assert(m_ && !l_);
    l_ = sref<mnode::linkcount>::transfer(&m_->nlink_);
  }

private:
  /*
   * The order is important due to C++ constructor/destructor
   * rules: we must hold the mnode reference while manipulating
   * the linkcount reference.
   */
  sref<mnode> m_;
  sref<mnode::linkcount> l_;
};

class mdir : public mnode {
private:
  mdir(u64 inum) : mnode(inum), map_(257) {}
  NEW_DELETE_OPS(mdir);
  friend sref<mnode> mnode::get(u64);

  chainhash<strbuf<DIRSIZ>, u64> map_;

public:
  bool insert(const strbuf<DIRSIZ>& name, mlinkref* ilink) {
    if (name == ".")
      return false;
    if (!map_.insert(name, ilink->mn()->inum_))
      return false;
    assert(ilink->held());
    ilink->mn()->nlink_.inc();
    return true;
  }

  bool remove(const strbuf<DIRSIZ>& name, sref<mnode> m) {
    if (!map_.remove(name, m->inum_))
      return false;
    m->nlink_.dec();
    return true;
  }

  bool replace(const strbuf<DIRSIZ>& name, sref<mnode> mold, mlinkref* ilinknew) {
    if (mold->inum_ == ilinknew->mn()->inum_)
      return true;
    if (!map_.replace(name, mold->inum_, ilinknew->mn()->inum_))
      return false;
    assert(ilinknew->held());
    ilinknew->mn()->nlink_.inc();
    mold->nlink_.dec();
    return true;
  }

  bool exists(const strbuf<DIRSIZ>& name) const {
    if (name == ".")
      return true;

    return map_.lookup(name);
  }

  sref<mnode> lookup(const strbuf<DIRSIZ>& name) const {
    if (name == ".")
      return mnode::get(inum_);

    u64 iprev = -1;
    for (;;) {
      u64 inum;
      if (!map_.lookup(name, &inum))
        return sref<mnode>();

      sref<mnode> m = mnode::get(inum);
      if (m)
        return m;

      /*
       * The inode was GCed between the lookup and mnode::get().
       * Retry the lookup.  Crash if we repeatedly can't find
       * the same inode (to make such bugs easier to track down).
       */
      assert(inum != iprev);
      iprev = inum;
    }
  }

  mlinkref lookup_link(const strbuf<DIRSIZ>& name) const {
    if (name == ".")
      /*
       * We cannot convert the name "." to a link count on the mnode,
       * because "." does not hold a link count of its own.
       */
      return mlinkref();

    for (;;) {
      sref<mnode> m = lookup(name);
      if (!m)
        return mlinkref();

      scoped_cli cli;
      /*
       * Retry the lookup, now that we have an sref<mnode>, since
       * we don't want to do lookup's mnode::get() under cli.
       */
      u64 inum;
      if (!map_.lookup(name, &inum) || inum != m->inum_)
        /*
         * The name has either been unlinked or changed to point
         * to another inode.  Retry.
         */
        continue;

      mlinkref ilink(m);

      /*
       * At this point, we know the inode had a non-zero link
       * count prior to the second lookup.  Since we are holding
       * cli, refcache cannot advance its epoch, and will not
       * garbage-collect the inode until after we release cli.
       *
       * Mild POSIX violation: an inode can appear to have a
       * zero link count, according to fstat, but get a positive
       * link counter later, because the fstat occurs after the
       * last name has been unlinked, but before we increment
       * the link count here.
       */

      ilink.acquire();

      /*
       * Mild POSIX violation: an inode can appear to have a
       * link count, according to fstat, that is higher than
       * the number of all its names.  For instance, sys_link()
       * first grabs a mlinkref on the existing name, and then
       * drops it if the new name already exists.
       */

      return ilink;
    }
  }

  bool enumerate(const strbuf<DIRSIZ>* prev, strbuf<DIRSIZ>* name) const {
    if (!prev) {
      *name = ".";
      return true;
    }

    if (*prev == ".")
      prev = nullptr;

    return map_.enumerate(prev, name);
  }

  bool kill(sref<mnode> parent) {
    if (!map_.remove_and_kill("..", parent->inum_))
      return false;

    parent->nlink_.dec();
    return true;
  }

  bool killed() const {
    return map_.killed();
  }
};

inline mdir*
mnode::as_dir()
{
  assert(type() == types::dir);
  return static_cast<mdir*>(this);
}

inline const mdir*
mnode::as_dir() const
{
  assert(type() == types::dir);
  return static_cast<const mdir*>(this);
}

class mfile : public mnode {
private:
  mfile(u64 inum) : mnode(inum), size_(0) {}
  NEW_DELETE_OPS(mfile);
  friend sref<mnode> mnode::get(u64);

  struct page_state {
    enum {
      FLAG_LOCK_BIT = 0,
      FLAG_LOCK = 1 << FLAG_LOCK_BIT,
      FLAG_SET = 1 << 1,
    };

    page_state() : flags(0) {}
    page_state(sref<page_info> p) : flags(FLAG_SET), pg(p) {}

    bool is_set() const {
      return flags & FLAG_SET;
    }

    bit_spinlock get_lock() {
      return bit_spinlock(&flags, FLAG_LOCK_BIT);
    }

    u64 flags;
    sref<page_info> pg;
  };

  enum { maxidx = ULONG_MAX / PGSIZE + 1 };
  radix_array<page_state, maxidx, PGSIZE,
              kalloc_allocator<page_state>> pages_;

  spinlock resize_lock_;
  seqcount<u32> size_seq_;
  u64 size_;

public:
  class resizer : public lock_guard<spinlock>,
                  public seq_writer {
  private:
    resizer(mfile* mf) : lock_guard<spinlock>(&mf->resize_lock_),
                         seq_writer(&mf->size_seq_),
                         mf_(mf) {}
    mfile* mf_;
    friend class mfile;

  public:
    resizer() : mf_(nullptr) {}
    explicit operator bool () const { return !!mf_; }
    u64 read_size() { return mf_->size_; }
    void resize_nogrow(u64 size);
    void resize_append(u64 size, sref<page_info> pi);
  };

  resizer write_size() {
    return resizer(this);
  }

  seq_reader<u64> read_size() {
    return seq_reader<u64>(&size_, &size_seq_);
  }

  sref<page_info> get_page(u64 pageidx);
};

inline mfile*
mnode::as_file()
{
  assert(type() == types::file);
  return static_cast<mfile*>(this);
}

inline const mfile*
mnode::as_file() const
{
  assert(type() == types::file);
  return static_cast<const mfile*>(this);
}

class mdev : public mnode {
private:
  mdev(u64 inum) : mnode(inum), major_(0), minor_(0) {}
  NEW_DELETE_OPS(mdev);
  friend sref<mnode> mnode::get(u64);

  u16 major_;
  u16 minor_;

public:
  u16 major() const { return major_; }
  u16 minor() const { return minor_; }

  void init(u16 major, u16 minor) {
    assert(!major_ && !minor_);
    major_ = major;
    minor_ = minor;
  }
};

inline mdev*
mnode::as_dev()
{
  assert(type() == types::dev);
  return static_cast<mdev*>(this);
}

inline const mdev*
mnode::as_dev() const
{
  assert(type() == types::dev);
  return static_cast<const mdev*>(this);
}

class msock : public mnode {
private:
  msock(u64 inum) : mnode(inum), localsock_(nullptr) {}
  NEW_DELETE_OPS(msock);
  friend sref<mnode> mnode::get(u64);

  localsock* localsock_;

public:
  localsock* get_sock() const { return localsock_; }

  void init(localsock* ls) {
    assert(!localsock_);
    localsock_ = ls;
  }
};

inline msock*
mnode::as_sock()
{
  assert(type() == types::sock);
  return static_cast<msock*>(this);
}

inline const msock*
mnode::as_sock() const
{
  assert(type() == types::sock);
  return static_cast<const msock*>(this);
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_MAT_PROB_BERNOULLI_LOGIT_GLM_LPMF_HPP
#define STAN_MATH_PRIM_MAT_PROB_BERNOULLI_LOGIT_GLM_LPMF_HPP

/*
Fix includes
*/
#include <stan/math/prim/scal/meta/is_constant_struct.hpp>
#include <stan/math/prim/scal/meta/partials_return_type.hpp>
#include <stan/math/prim/scal/meta/operands_and_partials.hpp>
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp>
#include <stan/math/prim/scal/err/check_bounded.hpp>
#include <stan/math/prim/scal/err/check_finite.hpp>
#include <stan/math/prim/scal/err/check_not_nan.hpp>
#include <stan/math/prim/scal/fun/constants.hpp>
#include <stan/math/prim/scal/fun/inv_logit.hpp>
#include <stan/math/prim/scal/fun/log1m.hpp>
#include <stan/math/prim/scal/fun/value_of.hpp>
#include <stan/math/prim/scal/meta/include_summand.hpp>
#include <stan/math/prim/scal/meta/scalar_seq_view.hpp>
#include <boost/random/bernoulli_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <cmath>
#include <string>

using Eigen::Dynamic;
using Eigen::Matrix;

namespace stan {
  namespace math {

    /**
     * Returns the log PMF of the Generalized Linear Model (GLM) with Bernoulli distribution
     * and logit link function. If containers are supplied, returns the log sum of the probabilities.
     *
     * @tparam T_n type of integer parameter
     * @tparam T_x type of the data matrix (design matrix); this should be an Eigen::Matrix type
     * @tparam T_beta type of the weight vector
     * @tparam T_alpha type of the bias vector
     * @param n integer parameter
     * @param x design matrix
     * @param beta weight vector
     * @param alpha bias vector (in logits)
     * @return log probability or log sum of probabilities
     * @throw std::domain_error if theta is infinite.
     * @throw std::invalid_argument if container sizes mismatch.
     */

    template <bool propto, typename T_n, typename T_x, typename T_beta, typename T_alpha>
    typename return_type<T_x, T_beta, T_alpha>::type
    bernoulli_logit_glm_lpmf(const T_n& n, const T_x& x, const T_beta& beta, const T_alpha& alpha) {
      static const std::string function = "bernoulli_logit_glm_lpmf";
      typedef typename stan::partials_return_type<T_n, T_x, T_beta, T_alpha>::type
        T_partials_return;

      using stan::is_constant_struct;
      using std::exp;

      if (!(stan::length(n) && stan::length(x) && stan::length(beta) && stan::length(alpha)))
        return 0.0;

      T_partials_return logp(0.0);

      check_bounded(function, "n", n, 0, 1);
      check_not_nan(function, "Data matrix", x);
      check_not_nan(function, "Weight vector", beta);
      check_not_nan(function, "Bias vector", alpha);
      check_consistent_sizes(function,
                             "Random variable", n,
                             "Bias vector", alpha);
      //check_consistent_sizes(function,
      //                       "Random variable", n,
      //                       "Data matrix", x); // would this work?
	  //			!!! add one more check to see that x is compatible with beta

      if (!include_summand<propto, T_x, T_beta, T_alpha>::value)
        return 0.0;

      scalar_seq_view<T_n> n_vec(n);
      scalar_seq_view<T_beta> beta_vec(beta);
      scalar_seq_view<T_alpha> alpha_vec(alpha);
      const size_t N = max_size(n, alpha); // do we want to check anything about x here? and in the next line?
	  const size_t M = beta.size();
      operands_and_partials<T_x, T_beta, T_alpha> ops_partials(x, beta, alpha);
	  Matrix<double, Dynamic, 1> beta_dbl(M,1);
	  Matrix<double, Dynamic, Dynamic> x_dbl(N,M);
	  for (size_t m = 0; m < M; m++) {
		beta_dbl[m] = value_of(beta_vec[m]);
	  }
      for (size_t n = 0; n < N; n++) { // is there a point in vectorising this loop?
		for (size_t m = 0; m < M; m++) {
			x_dbl(n,m) = value_of(x(n,m));
		}
        const int n_int = value_of(n_vec[n]);
        const T_partials_return theta_dbl = (x_dbl.row(n)* beta_dbl)[0] + value_of(alpha_vec[n]);

        const int sign = 2 * n_int - 1;
        const T_partials_return ntheta = sign * theta_dbl;
        const T_partials_return exp_m_ntheta = exp(-ntheta);

        // Handle extreme values gracefully using Taylor approximations.
        static const double cutoff = 20.0;
        if (ntheta > cutoff)
          logp -= exp_m_ntheta;
        else if (ntheta < -cutoff)
          logp += ntheta;
        else
          logp -= log1p(exp_m_ntheta);

		const bool constant_x = is_constant_struct<T_x>::value;
		const bool constant_beta = is_constant_struct<T_beta>::value;
		const bool constant_alpha = is_constant_struct<T_alpha>::value;
        if ( !(constant_x && constant_beta && constant_alpha)) {
          static const double cutoff = 20.0; // do we really need this line?
		  T_partials_return theta_derivative;
          if (ntheta > cutoff)
            theta_derivative = - exp_m_ntheta;
          else if (ntheta < -cutoff)
            theta_derivative = sign;
          else
            theta_derivative = sign * exp_m_ntheta
              / (exp_m_ntheta + 1);
          if ( !constant_beta){
			for (size_t m = 0; m < M; m++) // vectorise this loop?
			{
				ops_partials.edge2_.partials_[m] += theta_derivative * x_dbl(n,m);
			}
		  }
		  if ( !constant_x){
			ops_partials.edge1_.partials_.row(n) += theta_derivative * beta_dbl.transpose();
		  }
		  if ( !constant_alpha){
            ops_partials.edge3_.partials_[n] += theta_derivative;
          }
        }
      }
      return ops_partials.build(logp);
    }

    template <typename T_n,
              typename T_x,
			  typename T_beta,
			  typename T_alpha>
    inline
    typename return_type<T_x, T_beta, T_alpha>::type
    bernoulli_logit_glm_lpmf(const T_n& n,
	                         const T_x& x,
							 const T_beta& beta,
							 const T_alpha& alpha) {
      return bernoulli_logit_glm_lpmf<false>(n, x, beta, alpha);
    }

  }
}
#endif
<commit_msg>cosmetic changes<commit_after>#ifndef STAN_MATH_PRIM_MAT_PROB_BERNOULLI_LOGIT_GLM_LPMF_HPP
#define STAN_MATH_PRIM_MAT_PROB_BERNOULLI_LOGIT_GLM_LPMF_HPP

/*
Fix includes
*/
#include <stan/math/prim/scal/meta/is_constant_struct.hpp>
#include <stan/math/prim/scal/meta/partials_return_type.hpp>
#include <stan/math/prim/scal/meta/operands_and_partials.hpp>
#include <stan/math/prim/scal/err/check_consistent_sizes.hpp>
#include <stan/math/prim/scal/err/check_bounded.hpp>
#include <stan/math/prim/scal/err/check_finite.hpp>
#include <stan/math/prim/scal/err/check_not_nan.hpp>
#include <stan/math/prim/scal/fun/constants.hpp>
#include <stan/math/prim/scal/fun/inv_logit.hpp>
#include <stan/math/prim/scal/fun/log1m.hpp>
#include <stan/math/prim/scal/fun/value_of.hpp>
#include <stan/math/prim/scal/meta/include_summand.hpp>
#include <stan/math/prim/scal/meta/scalar_seq_view.hpp>
#include <boost/random/bernoulli_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include <cmath>
#include <string>

using Eigen::Dynamic;
using Eigen::Matrix;

namespace stan {
  namespace math {

    /**
     * Returns the log PMF of the Generalized Linear Model (GLM) with Bernoulli distribution
     * and logit link function. If containers are supplied, returns the log sum of the probabilities.
     *
     * @tparam T_n type of integer parameter
     * @tparam T_x type of the data matrix (design matrix); this should be an Eigen::Matrix type
     * @tparam T_beta type of the weight vector
     * @tparam T_alpha type of the bias vector
     * @param n integer parameter
     * @param x design matrix
     * @param beta weight vector
     * @param alpha bias vector (in logits)
     * @return log probability or log sum of probabilities
     * @throw std::domain_error if theta is infinite.
     * @throw std::invalid_argument if container sizes mismatch.
     */

    template <bool propto, typename T_n, typename T_x, typename T_beta, typename T_alpha>
    typename return_type<T_x, T_beta, T_alpha>::type
    bernoulli_logit_glm_lpmf(const T_n& n, const T_x& x, const T_beta& beta, const T_alpha& alpha) {
      static const std::string function = "bernoulli_logit_glm_lpmf";
      typedef typename stan::partials_return_type<T_n, T_x, T_beta, T_alpha>::type
        T_partials_return;

      using stan::is_constant_struct;
      using std::exp;

      if (!(stan::length(n) && stan::length(x) && stan::length(beta) && stan::length(alpha)))
        return 0.0;

      T_partials_return logp(0.0);

      check_bounded(function, "n", n, 0, 1);
      check_not_nan(function, "Data matrix", x);
      check_not_nan(function, "Weight vector", beta);
      check_not_nan(function, "Bias vector", alpha);
      check_consistent_sizes(function,
                             "Random variable", n,
                             "Bias vector", alpha);
      //check_consistent_sizes(function,
      //                       "Random variable", n,
      //                       "Data matrix", x); // would this work?
	  //			           maybe add one more check to see that x is compatible with beta?

      if (!include_summand<propto, T_x, T_beta, T_alpha>::value)
        return 0.0;

      scalar_seq_view<T_n> n_vec(n);
      scalar_seq_view<T_beta> beta_vec(beta);
      scalar_seq_view<T_alpha> alpha_vec(alpha);
      const size_t N = max_size(n, alpha); // do we also want to check anything about x here? and in the next line?
	  const size_t M = beta.size();
      operands_and_partials<T_x, T_beta, T_alpha> ops_partials(x, beta, alpha);
	  Matrix<double, Dynamic, 1> beta_dbl(M,1);
	  Matrix<double, Dynamic, Dynamic> x_dbl(N,M);
	  for (size_t m = 0; m < M; m++) {
		beta_dbl[m] = value_of(beta_vec[m]);
	  }
      for (size_t n = 0; n < N; n++) { // could we vectorise this loop?
		for (size_t m = 0; m < M; m++) {
			x_dbl(n,m) = value_of(x(n,m));
		}
        const int n_int = value_of(n_vec[n]);
        const T_partials_return theta_dbl = (x_dbl.row(n)* beta_dbl)[0] + value_of(alpha_vec[n]);

        const int sign = 2 * n_int - 1;
        const T_partials_return ntheta = sign * theta_dbl;
        const T_partials_return exp_m_ntheta = exp(-ntheta);

        // Handle extreme values gracefully using Taylor approximations.
        static const double cutoff = 20.0;
        if (ntheta > cutoff)
          logp -= exp_m_ntheta;
        else if (ntheta < -cutoff)
          logp += ntheta;
        else
          logp -= log1p(exp_m_ntheta);

		const bool constant_x = is_constant_struct<T_x>::value;
		const bool constant_beta = is_constant_struct<T_beta>::value;
		const bool constant_alpha = is_constant_struct<T_alpha>::value;
        if ( !(constant_x && constant_beta && constant_alpha)) {
          static const double cutoff = 20.0; // do we really need this line?
		  T_partials_return theta_derivative;
          if (ntheta > cutoff)
            theta_derivative = - exp_m_ntheta;
          else if (ntheta < -cutoff)
            theta_derivative = sign;
          else
            theta_derivative = sign * exp_m_ntheta
              / (exp_m_ntheta + 1);
          if ( !constant_beta){
			for (size_t m = 0; m < M; m++) // can we vectorise this loop?
			{
				ops_partials.edge2_.partials_[m] += theta_derivative * x_dbl(n,m);
			}
		  }
		  if ( !constant_x){
			ops_partials.edge1_.partials_.row(n) += theta_derivative * beta_dbl.transpose();
		  }
		  if ( !constant_alpha){
            ops_partials.edge3_.partials_[n] += theta_derivative;
          }
        }
      }
      return ops_partials.build(logp);
    }

    template <typename T_n,
              typename T_x,
			  typename T_beta,
			  typename T_alpha>
    inline
    typename return_type<T_x, T_beta, T_alpha>::type
    bernoulli_logit_glm_lpmf(const T_n& n,
	                         const T_x& x,
							 const T_beta& beta,
							 const T_alpha& alpha) {
      return bernoulli_logit_glm_lpmf<false>(n, x, beta, alpha);
    }

  }
}
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "webkit/tools/test_shell/simple_socket_stream_bridge.h"

#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "googleurl/src/gurl.h"
#include "net/socket_stream/socket_stream.h"
#include "net/url_request/url_request_context.h"
#include "webkit/api/public/WebSocketStreamHandle.h"
#include "webkit/glue/websocketstreamhandle_bridge.h"
#include "webkit/glue/websocketstreamhandle_delegate.h"

using webkit_glue::WebSocketStreamHandleBridge;

static const int kNoSocketId = 0;

namespace {

MessageLoop* g_io_thread;
scoped_refptr<URLRequestContext> g_request_context;

class WebSocketStreamHandleBridgeImpl
    : public WebSocketStreamHandleBridge,
      public net::SocketStream::Delegate {
 public:
  WebSocketStreamHandleBridgeImpl(
      WebKit::WebSocketStreamHandle* handle,
      webkit_glue::WebSocketStreamHandleDelegate* delegate);

  // WebSocketStreamHandleBridge methods.
  virtual void Connect(const GURL& url);
  virtual bool Send(const std::vector<char>& data);
  virtual void Close();

  // net::SocketStream::Delegate methods.
  virtual void OnConnected(net::SocketStream* req,
                           int max_pending_send_allowed);
  virtual void OnSentData(net::SocketStream* req,
                          int amount_sent);
  virtual void OnReceivedData(net::SocketStream* req,
                              const char* data, int len);
  virtual void OnClose(net::SocketStream* req);

 private:
  virtual ~WebSocketStreamHandleBridgeImpl();

  // Runs on |g_io_thread|;
  void DoConnect(const GURL& url);
  void DoSend(std::vector<char>* data);
  void DoClose();

  // Runs on |message_loop_|;
  void DoOnConnected(int max_amount_send_allowed);
  void DoOnSentData(int amount_sent);
  void DoOnReceivedData(std::vector<char>* data);
  void DoOnClose(webkit_glue::WebSocketStreamHandleDelegate* delegate);

  int socket_id_;
  MessageLoop* message_loop_;
  WebKit::WebSocketStreamHandle* handle_;
  webkit_glue::WebSocketStreamHandleDelegate* delegate_;

  scoped_refptr<net::SocketStream> socket_;

  DISALLOW_COPY_AND_ASSIGN(WebSocketStreamHandleBridgeImpl);
};

WebSocketStreamHandleBridgeImpl::WebSocketStreamHandleBridgeImpl(
    WebKit::WebSocketStreamHandle* handle,
    webkit_glue::WebSocketStreamHandleDelegate* delegate)
    : socket_id_(kNoSocketId),
      message_loop_(MessageLoop::current()),
      handle_(handle),
      delegate_(delegate) {
}

WebSocketStreamHandleBridgeImpl::~WebSocketStreamHandleBridgeImpl() {
  CHECK(socket_id_ == kNoSocketId);
}

void WebSocketStreamHandleBridgeImpl::Connect(const GURL& url) {
  CHECK(g_io_thread);
  AddRef();  // Released in DoOnClose().
  g_io_thread->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoConnect,
                        url));
  if (delegate_)
    delegate_->WillOpenStream(handle_, url);
}

bool WebSocketStreamHandleBridgeImpl::Send(
    const std::vector<char>& data) {
  CHECK(g_io_thread);
  g_io_thread->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoSend,
                        new std::vector<char>(data)));
  return true;
}

void WebSocketStreamHandleBridgeImpl::Close() {
  CHECK(g_io_thread);
  g_io_thread->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoClose));
}

void WebSocketStreamHandleBridgeImpl::OnConnected(
    net::SocketStream* socket, int max_pending_send_allowed) {
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoOnConnected,
                        max_pending_send_allowed));
}

void WebSocketStreamHandleBridgeImpl::OnSentData(
    net::SocketStream* socket, int amount_sent) {
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoOnSentData,
                        amount_sent));
}

void WebSocketStreamHandleBridgeImpl::OnReceivedData(
    net::SocketStream* socket, const char* data, int len) {
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this,
                        &WebSocketStreamHandleBridgeImpl::DoOnReceivedData,
                        new std::vector<char>(data, data + len)));
}

void WebSocketStreamHandleBridgeImpl::OnClose(net::SocketStream* socket) {
  webkit_glue::WebSocketStreamHandleDelegate* delegate = delegate_;
  delegate_ = NULL;
  socket_ = 0;
  socket_id_ = kNoSocketId;
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoOnClose,
                        delegate));
}

void WebSocketStreamHandleBridgeImpl::DoConnect(const GURL& url) {
  CHECK(MessageLoop::current() == g_io_thread);
  socket_ = new net::SocketStream(url, this);
  socket_->set_context(g_request_context);
  socket_->Connect();
}

void WebSocketStreamHandleBridgeImpl::DoSend(std::vector<char>* data) {
  CHECK(MessageLoop::current() == g_io_thread);
  scoped_ptr<std::vector<char> > scoped_data(data);
  if (!socket_)
    return;
  if (!socket_->SendData(&(data->at(0)), data->size()))
    socket_->Close();
}

void WebSocketStreamHandleBridgeImpl::DoClose() {
  CHECK(MessageLoop::current() == g_io_thread);
  if (!socket_)
    return;
  socket_->Close();
}

void WebSocketStreamHandleBridgeImpl::DoOnConnected(
    int max_pending_send_allowed) {
  CHECK(MessageLoop::current() == message_loop_);
  if (delegate_)
    delegate_->DidOpenStream(handle_, max_pending_send_allowed);
}

void WebSocketStreamHandleBridgeImpl::DoOnSentData(int amount_sent) {
  CHECK(MessageLoop::current() == message_loop_);
  if (delegate_)
    delegate_->DidSendData(handle_, amount_sent);
}

void WebSocketStreamHandleBridgeImpl::DoOnReceivedData(
    std::vector<char>* data) {
  CHECK(MessageLoop::current() == message_loop_);
  scoped_ptr<std::vector<char> > scoped_data(data);
  if (delegate_)
    delegate_->DidReceiveData(handle_, &(data->at(0)), data->size());
}

void WebSocketStreamHandleBridgeImpl::DoOnClose(
    webkit_glue::WebSocketStreamHandleDelegate* delegate) {
  CHECK(MessageLoop::current() == message_loop_);
  CHECK(!socket_);
  if (delegate)
    delegate->DidClose(handle_);
  Release();
}

}  // namespace

/* static */
void SimpleSocketStreamBridge::InitializeOnIOThread(
    URLRequestContext* request_context) {
  g_io_thread = MessageLoop::current();
  g_request_context = request_context;
}

void SimpleSocketStreamBridge::Cleanup() {
  g_io_thread = NULL;
  g_request_context = NULL;
}

namespace webkit_glue {

/* static */
WebSocketStreamHandleBridge* WebSocketStreamHandleBridge::Create(
    WebKit::WebSocketStreamHandle* handle,
    WebSocketStreamHandleDelegate* delegate) {
  return new WebSocketStreamHandleBridgeImpl(handle, delegate);
}

}  // namespace webkit_glue
<commit_msg>Delay OnClose actions.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "webkit/tools/test_shell/simple_socket_stream_bridge.h"

#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "googleurl/src/gurl.h"
#include "net/socket_stream/socket_stream.h"
#include "net/url_request/url_request_context.h"
#include "webkit/api/public/WebSocketStreamHandle.h"
#include "webkit/glue/websocketstreamhandle_bridge.h"
#include "webkit/glue/websocketstreamhandle_delegate.h"

using webkit_glue::WebSocketStreamHandleBridge;

static const int kNoSocketId = 0;

namespace {

MessageLoop* g_io_thread;
scoped_refptr<URLRequestContext> g_request_context;

class WebSocketStreamHandleBridgeImpl
    : public WebSocketStreamHandleBridge,
      public net::SocketStream::Delegate {
 public:
  WebSocketStreamHandleBridgeImpl(
      WebKit::WebSocketStreamHandle* handle,
      webkit_glue::WebSocketStreamHandleDelegate* delegate);

  // WebSocketStreamHandleBridge methods.
  virtual void Connect(const GURL& url);
  virtual bool Send(const std::vector<char>& data);
  virtual void Close();

  // net::SocketStream::Delegate methods.
  virtual void OnConnected(net::SocketStream* req,
                           int max_pending_send_allowed);
  virtual void OnSentData(net::SocketStream* req,
                          int amount_sent);
  virtual void OnReceivedData(net::SocketStream* req,
                              const char* data, int len);
  virtual void OnClose(net::SocketStream* req);

 private:
  virtual ~WebSocketStreamHandleBridgeImpl();

  // Runs on |g_io_thread|;
  void DoConnect(const GURL& url);
  void DoSend(std::vector<char>* data);
  void DoClose();

  // Runs on |message_loop_|;
  void DoOnConnected(int max_amount_send_allowed);
  void DoOnSentData(int amount_sent);
  void DoOnReceivedData(std::vector<char>* data);
  void DoOnClose();

  int socket_id_;
  MessageLoop* message_loop_;
  WebKit::WebSocketStreamHandle* handle_;
  webkit_glue::WebSocketStreamHandleDelegate* delegate_;

  scoped_refptr<net::SocketStream> socket_;
  // Number of pending tasks to handle net::SocketStream::Delegate methods.
  int num_pending_tasks_;

  DISALLOW_COPY_AND_ASSIGN(WebSocketStreamHandleBridgeImpl);
};

WebSocketStreamHandleBridgeImpl::WebSocketStreamHandleBridgeImpl(
    WebKit::WebSocketStreamHandle* handle,
    webkit_glue::WebSocketStreamHandleDelegate* delegate)
    : socket_id_(kNoSocketId),
      message_loop_(MessageLoop::current()),
      handle_(handle),
      delegate_(delegate),
      num_pending_tasks_(0) {
}

WebSocketStreamHandleBridgeImpl::~WebSocketStreamHandleBridgeImpl() {
  DCHECK_EQ(socket_id_, kNoSocketId);
}

void WebSocketStreamHandleBridgeImpl::Connect(const GURL& url) {
  DCHECK(g_io_thread);
  AddRef();  // Released in DoOnClose().
  g_io_thread->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoConnect,
                        url));
  if (delegate_)
    delegate_->WillOpenStream(handle_, url);
}

bool WebSocketStreamHandleBridgeImpl::Send(
    const std::vector<char>& data) {
  DCHECK(g_io_thread);
  g_io_thread->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoSend,
                        new std::vector<char>(data)));
  return true;
}

void WebSocketStreamHandleBridgeImpl::Close() {
  DCHECK(g_io_thread);
  g_io_thread->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoClose));
}

void WebSocketStreamHandleBridgeImpl::OnConnected(
    net::SocketStream* socket, int max_pending_send_allowed) {
  ++num_pending_tasks_;
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoOnConnected,
                        max_pending_send_allowed));
}

void WebSocketStreamHandleBridgeImpl::OnSentData(
    net::SocketStream* socket, int amount_sent) {
  ++num_pending_tasks_;
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoOnSentData,
                        amount_sent));
}

void WebSocketStreamHandleBridgeImpl::OnReceivedData(
    net::SocketStream* socket, const char* data, int len) {
  ++num_pending_tasks_;
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this,
                        &WebSocketStreamHandleBridgeImpl::DoOnReceivedData,
                        new std::vector<char>(data, data + len)));
}

void WebSocketStreamHandleBridgeImpl::OnClose(net::SocketStream* socket) {
  ++num_pending_tasks_;
  // Release socket_ on IO thread.
  socket_ = NULL;
  socket_id_ = kNoSocketId;
  message_loop_->PostTask(
      FROM_HERE,
      NewRunnableMethod(this, &WebSocketStreamHandleBridgeImpl::DoOnClose));
}

void WebSocketStreamHandleBridgeImpl::DoConnect(const GURL& url) {
  DCHECK(MessageLoop::current() == g_io_thread);
  socket_ = new net::SocketStream(url, this);
  socket_->set_context(g_request_context);
  socket_->Connect();
}

void WebSocketStreamHandleBridgeImpl::DoSend(std::vector<char>* data) {
  DCHECK(MessageLoop::current() == g_io_thread);
  scoped_ptr<std::vector<char> > scoped_data(data);
  if (!socket_)
    return;
  if (!socket_->SendData(&(data->at(0)), data->size()))
    socket_->Close();
}

void WebSocketStreamHandleBridgeImpl::DoClose() {
  DCHECK(MessageLoop::current() == g_io_thread);
  if (!socket_)
    return;
  socket_->Close();
}

void WebSocketStreamHandleBridgeImpl::DoOnConnected(
    int max_pending_send_allowed) {
  DCHECK(MessageLoop::current() == message_loop_);
  --num_pending_tasks_;
  if (delegate_)
    delegate_->DidOpenStream(handle_, max_pending_send_allowed);
}

void WebSocketStreamHandleBridgeImpl::DoOnSentData(int amount_sent) {
  DCHECK(MessageLoop::current() == message_loop_);
  --num_pending_tasks_;
  if (delegate_)
    delegate_->DidSendData(handle_, amount_sent);
}

void WebSocketStreamHandleBridgeImpl::DoOnReceivedData(
    std::vector<char>* data) {
  DCHECK(MessageLoop::current() == message_loop_);
  --num_pending_tasks_;
  scoped_ptr<std::vector<char> > scoped_data(data);
  if (delegate_)
    delegate_->DidReceiveData(handle_, &(data->at(0)), data->size());
}

void WebSocketStreamHandleBridgeImpl::DoOnClose() {
  DCHECK(MessageLoop::current() == message_loop_);
  --num_pending_tasks_;
  // Don't handle OnClose if there are pending tasks.
  DCHECK_EQ(num_pending_tasks_, 0);
  DCHECK(!socket_);
  DCHECK_EQ(socket_id_, kNoSocketId);
  webkit_glue::WebSocketStreamHandleDelegate* delegate = delegate_;
  delegate_ = NULL;
  if (delegate)
    delegate->DidClose(handle_);
  Release();
}

}  // namespace

/* static */
void SimpleSocketStreamBridge::InitializeOnIOThread(
    URLRequestContext* request_context) {
  g_io_thread = MessageLoop::current();
  g_request_context = request_context;
}

void SimpleSocketStreamBridge::Cleanup() {
  g_io_thread = NULL;
  g_request_context = NULL;
}

namespace webkit_glue {

/* static */
WebSocketStreamHandleBridge* WebSocketStreamHandleBridge::Create(
    WebKit::WebSocketStreamHandle* handle,
    WebSocketStreamHandleDelegate* delegate) {
  return new WebSocketStreamHandleBridgeImpl(handle, delegate);
}

}  // namespace webkit_glue
<|endoftext|>