<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 "Defs.hpp"
#include "History.hpp"
#include "TerminalInfo.hpp"
#include "KeyHandlers.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 char arrowIndicator = 0;

using ReadSignature = ssize_t (*)(int, void*, size_t);

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, yb::arrowHandler1},
    {0x5b, arrowHandler2},
    {0x43, arrowHandler3},
    {0x7f, backspaceHandler}
};

static inline void deleteRows(int rows) {
    for (int i = 0; i < rows; i++)
        std::putchar(' ');
    for (int i = 0; i < rows; i++)
        cursor_backward(1);
    fflush(stdout);
}

void clearTerminalLine() {
    int pos, width;
    if (!(pos = TerminalInfo::getCursorPosition())) return;
    width = TerminalInfo::getWidth();
    deleteRows(width - pos);
}

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 {};
}

static inline void printColor(const char *buffer) {
    printf("\e[31m%s\e[0m", buffer);
}

void printCompletion(History::const_iterator startIterator, int offset) {
    std::string pattern(lineBuffer.data());
    auto completion = findCompletion(startIterator, pattern);
    if (!completion) {
        return;
    }
    if (pattern.length() == completion.value().length()) {
        return;
    }
    clearTerminalLine();
    if (offset)
        cursor_forward(offset);
    printColor(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 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];
    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) {
    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"));
    }
    auto 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>Add initializer function<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 "Defs.hpp"
#include "History.hpp"
#include "TerminalInfo.hpp"
#include "KeyHandlers.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 char arrowIndicator = 0;

using ReadSignature = ssize_t (*)(int, void*, size_t);
static thread_local ReadSignature realRead = nullptr;

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, yb::arrowHandler1},
    {0x5b, arrowHandler2},
    {0x43, arrowHandler3},
    {0x7f, backspaceHandler}
};

static inline void deleteRows(int rows) {
    for (int i = 0; i < rows; i++)
        std::putchar(' ');
    for (int i = 0; i < rows; i++)
        cursor_backward(1);
    fflush(stdout);
}

void clearTerminalLine() {
    int pos, width;
    if (!(pos = TerminalInfo::getCursorPosition())) return;
    width = TerminalInfo::getWidth();
    deleteRows(width - pos);
}

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 {};
}

static inline void printColor(const char *buffer) {
    printf("\e[31m%s\e[0m", buffer);
}

void printCompletion(History::const_iterator startIterator, int offset) {
    std::string pattern(lineBuffer.data());
    auto completion = findCompletion(startIterator, pattern);
    if (!completion) {
        return;
    }
    if (pattern.length() == completion.value().length()) {
        return;
    }
    clearTerminalLine();
    if (offset)
        cursor_forward(offset);
    printColor(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 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];
    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) {
    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;
        }
    }
    auto returnValue = realRead(fd, buf, count);
    if (is_terminal_input(fd)) {
        *reinterpret_cast<unsigned char *>(buf) = yebash(*reinterpret_cast<unsigned char *>(buf));
    }
    return returnValue;
}

__attribute__((constructor))
static void yebashInit()  {
    if (!realRead) {
        realRead = reinterpret_cast<ReadSignature>(dlsym(RTLD_NEXT, "read"));
    }
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/lib/pstates_pgpe.H $      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/// @file  pstates_pgpe.H
/// @brief Pstate structures and support routines for PGPE Hcode
///
// *HWP HW Owner        : Rahul Batra <rbatra@us.ibm.com>
// *HWP HW Owner        : Michael Floyd <mfloyd@us.ibm.com>
// *HWP Team            : PM
// *HWP Level           : 1
// *HWP Consumed by     : PGPE:HS

#ifndef __PSTATES_PGPE_H__
#define __PSTATES_PGPE_H__

#include <pstates_common.H>
// #include <pstates_qme.h>

/// PstateParmsBlock Magic Number
///
/// This magic number identifies a particular version of the
/// PstateParmsBlock and its substructures.  The version number should be
/// kept up to date as changes are made to the layout or contents of the
/// structure.

#define PSTATE_PARMSBLOCK_MAGIC 0x5053544154453030ull /* PSTATE00 */

#ifndef __ASSEMBLER__
#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

/// Control Attributes
typedef union
{
    uint8_t value[128];
    union
    {
        uint8_t pstates_enabled;
        uint8_t resclk_enabled;
        uint8_t wof_enabled;
        uint8_t dds_enabled;
        uint8_t ocs_enabled;
        uint8_t underv_enabled;
        uint8_t overv_enabled;
        uint8_t throttle_control_enabled;
    } fields;
} Attributes_t;

/// Resonant Clock Stepping Entry
///
/// @todo needs refinement for P10 yet.
typedef union
{
    uint16_t value;
    struct
    {
#ifdef _BIG_ENDIAN
        uint16_t    sector_buffer   : 4;
        uint16_t    spare1          : 1;
        uint16_t    pulse_enable    : 1;
        uint16_t    pulse_mode      : 2;
        uint16_t    resonant_switch : 4;
        uint16_t    spare4          : 4;
#else
        uint16_t    spare4          : 4;
        uint16_t    resonant_switch : 4;
        uint16_t    pulse_mode      : 2;
        uint16_t    pulse_enable    : 1;
        uint16_t    spare1          : 1;
        uint16_t    sector_buffer   : 4;
#endif // _BIG_ENDIAN
    } fields;
} ResClkStepEntry_t;

/// @todo needs refinement for P10 yet.
#define RESCLK_FREQ_REGIONS 8
#define RESCLK_STEPS        64
#define RESCLK_L3_STEPS     4

/// Resonant Clock Setup
typedef struct
{
    uint8_t             freq_mhz[RESCLK_FREQ_REGIONS];
    uint8_t             index[RESCLK_FREQ_REGIONS];
    ResClkStepEntry_t   steparray[RESCLK_STEPS];
    uint16_t            step_delay_ns;                   // Max delay: 65.536us
    uint8_t             l3_steparray[RESCLK_L3_STEPS];
    uint16_t            l3_threshold_mv;

} ResClkSetup_t;

/// #W Entry Data Points
typedef struct
{
    union
    {
        uint64_t value;
        struct
        {

#ifdef _BIG_ENDIAN
            uint64_t insrtn_dely   : 8;
            uint64_t spare1        : 2;
            uint64_t calb_adj      : 2;
            uint64_t spare2        : 1;
            uint64_t window_offset : 3;
            uint64_t mux_select    : 36;
            uint64_t dlt_time_set  : 8;
            uint64_t spare3        : 4;
#else
            uint64_t spare3        : 4;
            uint64_t dlt_time_set  : 8;
            uint64_t mux_select    : 36;
            uint64_t window_offset : 3;
            uint64_t spare2        : 1;
            uint64_t calb_adj      : 2;
            uint64_t spare1        : 2;
            uint64_t insrtn_dely   : 8;
#endif
        } fields;
    } digital_droop_sensor_config;
} PoundWEntry_t;

/// #W DPLL Settings
typedef struct
{
    union
    {
        uint16_t value;
        struct
        {
#ifdef _BIG_ENDIAN
            unit16_t N_S_drop_3p125pct   : 4;
            unit16_t N_L_drop_3p125pct   : 4;
            unit16_t L_S_return_3p125pct : 4;
            unit16_t S_N_return_3p125pct : 4;
#else
            unit16_t S_N_return_3p125pct : 4;
            unit16_t L_S_return_3p125pct : 4;
            unit16_t N_L_drop_3p125pct   : 4;
            unit16_t N_S_drop_3p125pct   : 4;
#endif // _BIG_ENDIAN                       /// #W Other Settings
        } fields;
    };
} PoundWDpllSettings_t;

/// #W Other Settings
typedef struct
{
    uint8_t              dds_calibration_version;
    PoundWDpllSettings_t dpll_settings;
    uint8_t              light_throttle_settings[10];
    uint8_t              harsh_throttle_settings[10];
    uint16_t             droop_freq_resp_reference;
    uint8_t              large_droop_mode_reg_setting[8];
    uint8_t              misc_droop_mode_reg_setting[8];
    uint8_t              spare[215];
} PoundWOther_t;

/// #W VPD Structure
///
/// Part specific data to manage the Digital Droop Sensor (DDS)
typedef struct
{
    PoundWEntry_t           entry[NUM_OP_POINTS];
    PoundWOther_t           other;
    uint8_t                 rsvd[256];
} PoundW_t;

/// Voltage Regulation Module (VRM) Control Settings
typedef struct
{
    /// The exponent of the exponential encoding of Pstate stepping delay
    uint8_t stepdelay_range;

    /// The significand of the exponential encoding of Pstate stepping delay
    uint8_t stepdelay_value;

    uint8_t spare[2];

    /// Time between ext VRM detects write voltage cmd and when voltage begins to move
    uint32_t transition_start_ns[RUNTIME_RAILS];

    /// Transition rate for an increasing voltage excursion
    uint32_t transition_rate_inc_uv_per_us[RUNTIME_RAILS];

    /// Transition rate for an decreasing voltage excursion
    uint32_t transition_rate_dec_uv_per_us[RUNTIME_RAILS];

    /// Delay to account for rail settling
    uint32_t stabilization_time_us[RUNTIME_RAILS];

    /// External VRM transition step size
    uint32_t step_size_mv[RUNTIME_RAILS];
} VRMParms_t;

/// These define the Run-time rails that are controlled by the PGPE during
/// Pstate operations.
#define RUNTIME_RAILS       2
#define RUNTIME_RAIL_VDD    0
#define RUNTIME_RAIL_VCS    1

/// @todo Need to define the DDS control block

/// Pstate Parameter consumed by PGPE
///
/// The GlobalPstateParameterBlock is an abstraction of a set of voltage/frequency
/// operating points along with hardware limits.
///
typedef struct
{

    union
    {
        uint64_t        value;
        struct
        {
            unit64_t    eye_catcher : 56;
            uint64_t    version     : 8 ;

        } fields;
    } magic;

    Attributes_t        attr;

    uint32_t            reference_frequency_khz;    // Pstate[0] frequency
    uint32_t            frequency_step_khz;
    uint32_t            occ_complex_frequency_mhz;  // Needed for FITs
    uint32_t            dpll_pstate0_mhz;  // @todo why this and reference_frequency_khz?

    /// VPD operating points are biased but without load-line correction.
    /// Frequencies are in MHz, voltages are specified in units of 1mV, currents
    /// are specified in units of 10mA, and temperatures are specified in 0.5
    /// degrees C.
    PoundVOpPoint_t     operating_points_set[NUM_VPD_PTS_SET][NUM_OP_POINTS];
    uint32_t            spare0[16];             // 128B word-aligned

    PoundVBias_t        poundv_biases_0p05pct[NUM_OP_POINTS];  // Values in 0.5%

    SysPowerDistParms_t vdd_sysparm;
    SysPowerDistParms_t vcs_sysparm;
    SysPowerDistParms_t vdn_sysparm;
    /// #W Other Settings
    VRMParms_t          ext_vrm_parms;

    uint32_t            safe_voltage_mv;
    uint32_t            safe_frequency_khz;

    /// DDS Data
    /// DDSParmBlock dds;
    /// @todo need to define the DDS parm block

    /// The following are needed to generated the Pstate Table to HOMER.
    ResClkSetup_t       resclk;

    /// Precalculated VPD Slopes
    /// All are in 4.12 decimal form into unit16_t integer value
    uint16_t            ps_voltage_slopes[RUNTIME_RAILS][NUM_VPD_PTS_SET][VPD_NUM_SLOPES_REGION];
    uint16_t            voltage_ps_slopes[RUNTIME_RAILS][NUM_VPD_PTS_SET][VPD_NUM_SLOPES_REGION];
    uint16_t            ps_current_slopes[RUNTIME_RAILS][NUM_VPD_PTS_SET][VPD_NUM_SLOPES_REGION];
    uint16_t            current_ps_slopes[RUNTIME_RAILS][NUM_VPD_PTS_SET][VPD_NUM_SLOPES_REGION];

    // Biased Compare VID operating points
    // CompareVIDPoints_t vid_point_set[NUM_OP_POINTS];

    // Biased Threshold operation points
    // uint8_t threshold_set[NUM_OP_POINTS][NUM_THRESHOLD_POINTS];

    // pstate-volt compare slopes
    // int16_t ps_vid_compare_slopes[VPD_NUM_SLOPES_REGION];

    // pstate-volt threshold slopes
    // int16_t ps_dds_thresh_slopes[VPD_NUM_SLOPES_REGION][NUM_THRESHOLD_POINTS];

    // Jump value operating points
    // uint8_t jump_value_set[NUM_OP_POINTS][NUM_JUMP_VALUES];

    // Jump-value slopes
    // int16_t ps_dds_jump_slopes[VPD_NUM_SLOPES_REGION][NUM_JUMP_VALUES];

} GlobalPstateParmBlock_t __attribute__((packed, aligned(1024)));

#ifdef __cplusplus
} // end extern C
#endif
#endif    /* __ASSEMBLER__ */
#endif    /* __PSTATES_PGPE_H__ */
<commit_msg>PGPE: Basic Pstates for P10<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/lib/pstates_pgpe.H $      */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/// @file  pstates_pgpe.H
/// @brief Pstate structures and support routines for PGPE Hcode
///
// *HWP HW Owner        : Rahul Batra <rbatra@us.ibm.com>
// *HWP HW Owner        : Michael Floyd <mfloyd@us.ibm.com>
// *HWP Team            : PM
// *HWP Level           : 1
// *HWP Consumed by     : PGPE:HS

#ifndef __PSTATES_PGPE_H__
#define __PSTATES_PGPE_H__

#include <pstates_common.H>
// #include <pstates_qme.h>

/// PstateParmsBlock Magic Number
///
/// This magic number identifies a particular version of the
/// PstateParmsBlock and its substructures.  The version number should be
/// kept up to date as changes are made to the layout or contents of the
/// structure.

#define PSTATE_PARMSBLOCK_MAGIC 0x5053544154453030ull /* PSTATE00 */

#ifndef __ASSEMBLER__
#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>

/// Control Attributes
typedef union
{
    uint8_t value[128];
    union
    {
        uint8_t pstates_enabled;
        uint8_t resclk_enabled;
        uint8_t wof_enabled;
        uint8_t dds_enabled;
        uint8_t ocs_enabled;
        uint8_t underv_enabled;
        uint8_t overv_enabled;
        uint8_t throttle_control_enabled;
    } fields;
} Attributes_t;

/// Resonant Clock Stepping Entry
///
/// @todo needs refinement for P10 yet.
typedef union
{
    uint16_t value;
    struct
    {
#ifdef _BIG_ENDIAN
        uint16_t    sector_buffer   : 4;
        uint16_t    spare1          : 1;
        uint16_t    pulse_enable    : 1;
        uint16_t    pulse_mode      : 2;
        uint16_t    resonant_switch : 4;
        uint16_t    spare4          : 4;
#else
        uint16_t    spare4          : 4;
        uint16_t    resonant_switch : 4;
        uint16_t    pulse_mode      : 2;
        uint16_t    pulse_enable    : 1;
        uint16_t    spare1          : 1;
        uint16_t    sector_buffer   : 4;
#endif // _BIG_ENDIAN
    } fields;
} ResClkStepEntry_t;

/// @todo needs refinement for P10 yet.
#define RESCLK_FREQ_REGIONS 8
#define RESCLK_STEPS        64
#define RESCLK_L3_STEPS     4

/// Resonant Clock Setup
typedef struct
{
    uint8_t             freq_mhz[RESCLK_FREQ_REGIONS];
    uint8_t             index[RESCLK_FREQ_REGIONS];
    ResClkStepEntry_t   steparray[RESCLK_STEPS];
    uint16_t            step_delay_ns;                   // Max delay: 65.536us
    uint8_t             l3_steparray[RESCLK_L3_STEPS];
    uint16_t            l3_threshold_mv;

} ResClkSetup_t;

/// #W Entry Data Points
typedef struct
{
    union
    {
        uint64_t value;
        struct
        {

#ifdef _BIG_ENDIAN
            uint64_t insrtn_dely   : 8;
            uint64_t spare1        : 2;
            uint64_t calb_adj      : 2;
            uint64_t spare2        : 1;
            uint64_t window_offset : 3;
            uint64_t mux_select    : 36;
            uint64_t dlt_time_set  : 8;
            uint64_t spare3        : 4;
#else
            uint64_t spare3        : 4;
            uint64_t dlt_time_set  : 8;
            uint64_t mux_select    : 36;
            uint64_t window_offset : 3;
            uint64_t spare2        : 1;
            uint64_t calb_adj      : 2;
            uint64_t spare1        : 2;
            uint64_t insrtn_dely   : 8;
#endif
        } fields;
    } digital_droop_sensor_config;
} PoundWEntry_t;

/// #W DPLL Settings
typedef struct
{
    union
    {
        uint16_t value;
        struct
        {
#ifdef _BIG_ENDIAN
            uint16_t N_S_drop_3p125pct   : 4;
            uint16_t N_L_drop_3p125pct   : 4;
            uint16_t L_S_return_3p125pct : 4;
            uint16_t S_N_return_3p125pct : 4;
#else
            uint16_t S_N_return_3p125pct : 4;
            uint16_t L_S_return_3p125pct : 4;
            uint16_t N_L_drop_3p125pct   : 4;
            uint16_t N_S_drop_3p125pct   : 4;
#endif // _BIG_ENDIAN                       /// #W Other Settings
        } fields;
    };
} PoundWDpllSettings_t;

/// #W Other Settings
typedef struct
{
    uint8_t              dds_calibration_version;
    PoundWDpllSettings_t dpll_settings;
    uint8_t              light_throttle_settings[10];
    uint8_t              harsh_throttle_settings[10];
    uint16_t             droop_freq_resp_reference;
    uint8_t              large_droop_mode_reg_setting[8];
    uint8_t              misc_droop_mode_reg_setting[8];
    uint8_t              spare[215];
} PoundWOther_t;

/// #W VPD Structure
///
/// Part specific data to manage the Digital Droop Sensor (DDS)
typedef struct
{
    PoundWEntry_t           entry[NUM_OP_POINTS];
    PoundWOther_t           other;
    uint8_t                 rsvd[256];
} PoundW_t;
/// These define the Run-time rails that are controlled by the PGPE during
/// Pstate operations.
#define RUNTIME_RAILS       2
#define RUNTIME_RAIL_VDD    0
#define RUNTIME_RAIL_VCS    1

/// Voltage Regulation Module (VRM) Control Settings
typedef struct
{
    /// The exponent of the exponential encoding of Pstate stepping delay
    uint8_t stepdelay_range;

    /// The significand of the exponential encoding of Pstate stepping delay
    uint8_t stepdelay_value;

    uint8_t spare[2];

    /// Time between ext VRM detects write voltage cmd and when voltage begins to move
    uint32_t transition_start_ns[RUNTIME_RAILS];

    /// Transition rate for an increasing voltage excursion
    uint32_t transition_rate_inc_uv_per_us[RUNTIME_RAILS];

    /// Transition rate for an decreasing voltage excursion
    uint32_t transition_rate_dec_uv_per_us[RUNTIME_RAILS];

    /// Delay to account for rail settling
    uint32_t stabilization_time_us[RUNTIME_RAILS];

    /// External VRM transition step size
    uint32_t step_size_mv[RUNTIME_RAILS];
} VRMParms_t;

/// @todo Need to define the DDS control block

/// Pstate Parameter consumed by PGPE
///
/// The GlobalPstateParameterBlock is an abstraction of a set of voltage/frequency
/// operating points along with hardware limits.
///
typedef struct
{

    union
    {
        uint64_t        value;
        struct
        {
            uint64_t    eye_catcher : 56;
            uint64_t    version     : 8 ;

        } fields;
    } magic;

    Attributes_t        attr;

    uint32_t            reference_frequency_khz;    // Pstate[0] frequency
    uint32_t            frequency_step_khz;
    uint32_t            occ_complex_frequency_mhz;  // Needed for FITs
    uint32_t            dpll_pstate0_value;  // @todo why this and reference_frequency_khz?
    uint32_t            nest_frequency_mhz;  // Needed for FITs

    /// VPD operating points are biased but without load-line correction.
    /// Frequencies are in MHz, voltages are specified in units of 1mV, currents
    /// are specified in units of 10mA, and temperatures are specified in 0.5
    /// degrees C.
    PoundVOpPoint_t     operating_points_set[NUM_VPD_PTS_SET][NUM_OP_POINTS];
    uint32_t            spare0[16];             // 128B word-aligned

    PoundVBias_t        poundv_biases_0p05pct[NUM_OP_POINTS];  // Values in 0.5%

    SysPowerDistParms_t vdd_sysparm;
    SysPowerDistParms_t vcs_sysparm;
    SysPowerDistParms_t vdn_sysparm;
    /// #W Other Settings
    VRMParms_t          ext_vrm_parms;

    uint32_t            safe_voltage_mv;
    uint32_t            safe_frequency_khz;

    /// DDS Data
    /// DDSParmBlock dds;
    /// @todo need to define the DDS parm block

    /// The following are needed to generated the Pstate Table to HOMER.
    ResClkSetup_t       resclk;

    /// Precalculated VPD Slopes
    /// All are in 4.12 decimal form into uint16_t integer value
    uint16_t            ps_voltage_slopes[RUNTIME_RAILS][NUM_VPD_PTS_SET][VPD_NUM_SLOPES_REGION];
    uint16_t            voltage_ps_slopes[RUNTIME_RAILS][NUM_VPD_PTS_SET][VPD_NUM_SLOPES_REGION];
    uint16_t            ps_current_slopes[RUNTIME_RAILS][NUM_VPD_PTS_SET][VPD_NUM_SLOPES_REGION];
    uint16_t            current_ps_slopes[RUNTIME_RAILS][NUM_VPD_PTS_SET][VPD_NUM_SLOPES_REGION];

    //AvsBusTopology
    AvsBusTopology_t avs_bus_topology;

    // Biased Compare VID operating points
    // CompareVIDPoints_t vid_point_set[NUM_OP_POINTS];

    // Biased Threshold operation points
    // uint8_t threshold_set[NUM_OP_POINTS][NUM_THRESHOLD_POINTS];

    // pstate-volt compare slopes
    // int16_t ps_vid_compare_slopes[VPD_NUM_SLOPES_REGION];

    // pstate-volt threshold slopes
    // int16_t ps_dds_thresh_slopes[VPD_NUM_SLOPES_REGION][NUM_THRESHOLD_POINTS];

    // Jump value operating points
    // uint8_t jump_value_set[NUM_OP_POINTS][NUM_JUMP_VALUES];

    // Jump-value slopes
    // int16_t ps_dds_jump_slopes[VPD_NUM_SLOPES_REGION][NUM_JUMP_VALUES];

//} GlobalPstateParmBlock_t __attribute__((packed, aligned(1024)));
} GlobalPstateParmBlock_t;

#ifdef __cplusplus
} // end extern C
#endif
#endif    /* __ASSEMBLER__ */
#endif    /* __PSTATES_PGPE_H__ */
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

/* interface header */
#include "OptionsMenu.h"

/* system implementation headers */
#include <vector>
#include <string>

/* common implementation headers */
#include "OpenGLTexFont.h"
#include "StateDatabase.h"
#include "BZDBCache.h"
#include "TextUtils.h"

/* local implementation headers */
#include "MainMenu.h"
#include "HUDDialogStack.h"
#include "ControlPanel.h"
#include "StartupInfo.h"

/* FIXME - from playing.h */
StartupInfo* getStartupInfo();
extern ControlPanel* controlPanel;

OptionsMenu::OptionsMenu() : guiOptionsMenu(NULL), saveWorldMenu(NULL),
			     inputMenu(NULL), audioMenu(NULL),
			     displayMenu(NULL)
{
  // add controls
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiList* option;
  std::vector<std::string>* options;

  HUDuiLabel* label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setString("Options");
  list.push_back(label);

  inputSetting = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Input Settings");
  list.push_back(label);

  audioSetting = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Audio Settings");
  list.push_back(label);

  displaySetting = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Display Settings");
  list.push_back(label);

  guiOptions = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("GUI Options");
  list.push_back(label);

  label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("");
  list.push_back(label);

  option = new HUDuiList;
  option->setFont(MainMenu::getFont());
  option->setLabel("UDP network connection:");
  option->setCallback(callback, (void*)"U");
  options = &option->getList();
  options->push_back(std::string("Off"));
  options->push_back(std::string("On"));
  option->update();
  list.push_back(option);

  option = new HUDuiList;
  option->setFont(MainMenu::getFont());
  option->setLabel("Server List Cache:");
  option->setCallback(callback, (void*)"S");
  options = &option->getList();
  options->push_back(std::string("Off / Backup Mode"));
  options->push_back(std::string("5 Minutes"));
  options->push_back(std::string("15 Minutes"));
  options->push_back(std::string("30 Minutes"));
  options->push_back(std::string("1 Hour"));
  options->push_back(std::string("5 Hours"));
  options->push_back(std::string("15 Hours"));
  options->push_back(std::string("1 day"));
  options->push_back(std::string("15 days"));
  options->push_back(std::string("30 days"));
  option->update();
  list.push_back(option);

  clearCache = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Clear Server List Cache");
  list.push_back(label);

  saveWorld = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Save World");
  list.push_back(label);

  initNavigation(list, 1,list.size()-1);
}

OptionsMenu::~OptionsMenu()
{
  delete guiOptionsMenu;
  delete saveWorldMenu;
  delete inputMenu;
  delete audioMenu;
  delete displayMenu;
}

void OptionsMenu::execute()
{
  HUDuiControl* focus = HUDui::getFocus();
  if (focus == guiOptions) {
    if (!guiOptionsMenu) guiOptionsMenu = new GUIOptionsMenu;
    HUDDialogStack::get()->push(guiOptionsMenu);
  } else if (focus == clearCache) {
    if ((ServerListCache::get())->clearCache()){
      controlPanel->addMessage("Cache Cleared");
    } else {
      // already cleared -- do nothing
    }
  } else if (focus == saveWorld) {
    if (!saveWorldMenu) saveWorldMenu = new SaveWorldMenu;
    HUDDialogStack::get()->push(saveWorldMenu);
  } else if (focus == inputSetting) {
    if (!inputMenu) inputMenu = new InputMenu;
    HUDDialogStack::get()->push(inputMenu);
  } else if (focus == audioSetting) {
    if (!audioMenu) audioMenu = new AudioMenu;
    HUDDialogStack::get()->push(audioMenu);
  } else if (focus == displaySetting) {
    if (!displayMenu) displayMenu = new DisplayMenu;
    HUDDialogStack::get()->push(displayMenu);
  }
}

void OptionsMenu::resize(int width, int height)
{
  int i;
  HUDDialog::resize(width, height);

  // use a big font for title, smaller font for the rest
  const float titleFontWidth = (float)height / 10.0f;
  const float titleFontHeight = (float)height / 10.0f;
  const float fontWidth = (float)height / 30.0f;
  const float fontHeight = (float)height / 30.0f;

  // reposition title
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontWidth, titleFontHeight);
  const OpenGLTexFont& titleFont = title->getFont();
  const float titleWidth = titleFont.getWidth(title->getString());
  float x = 0.5f * ((float)width - titleWidth);
  float y = (float)height - titleFont.getHeight();
  title->setPosition(x, y);

  // reposition options in two columns
  x = 0.5f * (float)width;
  y -= 0.6f * titleFont.getHeight();
  const int count = list.size();
  for (i = 1; i < count; i++) {
    list[i]->setFontSize(fontWidth, fontHeight);
    list[i]->setPosition(x, y);
    y -= 1.0f * list[i]->getFont().getHeight();
  }

  // load current settings
  {
    int i = 1;

    const StartupInfo* info = getStartupInfo();

    // mind the ++i !
    ((HUDuiList*)list[i++])->setIndex(info->useUDPconnection ? 1 : 0);

    // server cache age
    int index = 0;
    switch ((ServerListCache::get())->getMaxCacheAge()){
      case 0: index = 0; break;
      case 5: index = 1; break;
      case 15: index = 2; break;
      case 30: index = 3; break;
      case 60: index = 4; break;
      case 60*5: index = 5; break;
      case 60*15: index = 6; break;
      case 60*24: index = 7; break;
      case 60*24*15: index = 8; break;
      case 60*24*30: index = 9; break;
      default: index = 4;
    }
    ((HUDuiList*)list[i++])->setIndex(index);
    i++; // clear cache label
  }
}

void OptionsMenu::callback(HUDuiControl* w, void* data)
{
  HUDuiList* list = (HUDuiList*)w;

  switch (((const char*)data)[0]) {
    case 'U': {
      StartupInfo* info = getStartupInfo();
      info->useUDPconnection = (list->getIndex() != 0);
      break;
    }

    case 'S': { // server cache
      time_t minutes = 0;
      int index = list->getIndex();
      switch (index){
	case 0: minutes = 0; break;
	case 1: minutes = 5; break;
	case 2: minutes = 15; break;
	case 3: minutes = 30; break;
	case 4: minutes = 60; break;
	case 5: minutes = 60*5; break;
	case 6: minutes = 60*15; break;
	case 7: minutes = 60*24; break;
	case 8: minutes = 60*24*15; break;
	case 9: minutes = 60*24*30; break;
      }
      (ServerListCache::get())->setMaxCacheAge(minutes);
      break;
    }
  }
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Setting menu items fixed<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"

/* interface header */
#include "OptionsMenu.h"

/* system implementation headers */
#include <vector>
#include <string>

/* common implementation headers */
#include "OpenGLTexFont.h"
#include "StateDatabase.h"
#include "BZDBCache.h"
#include "TextUtils.h"

/* local implementation headers */
#include "MainMenu.h"
#include "HUDDialogStack.h"
#include "ControlPanel.h"
#include "StartupInfo.h"

/* FIXME - from playing.h */
StartupInfo* getStartupInfo();
extern ControlPanel* controlPanel;

OptionsMenu::OptionsMenu() : guiOptionsMenu(NULL), saveWorldMenu(NULL),
			     inputMenu(NULL), audioMenu(NULL),
			     displayMenu(NULL)
{
  // add controls
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiList* option;
  std::vector<std::string>* options;

  HUDuiLabel* label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setString("Options");
  list.push_back(label);

  inputSetting = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Input Settings");
  list.push_back(label);

  audioSetting = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Audio Settings");
  list.push_back(label);

  displaySetting = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Display Settings");
  list.push_back(label);

  guiOptions = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("GUI Options");
  list.push_back(label);

  label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("");
  list.push_back(label);

  option = new HUDuiList;
  option->setFont(MainMenu::getFont());
  option->setLabel("UDP network connection:");
  option->setCallback(callback, (void*)"U");
  options = &option->getList();
  options->push_back(std::string("Off"));
  options->push_back(std::string("On"));
  option->update();
  list.push_back(option);

  option = new HUDuiList;
  option->setFont(MainMenu::getFont());
  option->setLabel("Server List Cache:");
  option->setCallback(callback, (void*)"S");
  options = &option->getList();
  options->push_back(std::string("Off / Backup Mode"));
  options->push_back(std::string("5 Minutes"));
  options->push_back(std::string("15 Minutes"));
  options->push_back(std::string("30 Minutes"));
  options->push_back(std::string("1 Hour"));
  options->push_back(std::string("5 Hours"));
  options->push_back(std::string("15 Hours"));
  options->push_back(std::string("1 day"));
  options->push_back(std::string("15 days"));
  options->push_back(std::string("30 days"));
  option->update();
  list.push_back(option);

  clearCache = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Clear Server List Cache");
  list.push_back(label);

  saveWorld = label = new HUDuiLabel;
  label->setFont(MainMenu::getFont());
  label->setLabel("Save World");
  list.push_back(label);

  initNavigation(list, 1,list.size()-1);
}

OptionsMenu::~OptionsMenu()
{
  delete guiOptionsMenu;
  delete saveWorldMenu;
  delete inputMenu;
  delete audioMenu;
  delete displayMenu;
}

void OptionsMenu::execute()
{
  HUDuiControl* focus = HUDui::getFocus();
  if (focus == guiOptions) {
    if (!guiOptionsMenu) guiOptionsMenu = new GUIOptionsMenu;
    HUDDialogStack::get()->push(guiOptionsMenu);
  } else if (focus == clearCache) {
    if ((ServerListCache::get())->clearCache()){
      controlPanel->addMessage("Cache Cleared");
    } else {
      // already cleared -- do nothing
    }
  } else if (focus == saveWorld) {
    if (!saveWorldMenu) saveWorldMenu = new SaveWorldMenu;
    HUDDialogStack::get()->push(saveWorldMenu);
  } else if (focus == inputSetting) {
    if (!inputMenu) inputMenu = new InputMenu;
    HUDDialogStack::get()->push(inputMenu);
  } else if (focus == audioSetting) {
    if (!audioMenu) audioMenu = new AudioMenu;
    HUDDialogStack::get()->push(audioMenu);
  } else if (focus == displaySetting) {
    if (!displayMenu) displayMenu = new DisplayMenu;
    HUDDialogStack::get()->push(displayMenu);
  }
}

void OptionsMenu::resize(int width, int height)
{
  int i;
  HUDDialog::resize(width, height);

  // use a big font for title, smaller font for the rest
  const float titleFontWidth = (float)height / 10.0f;
  const float titleFontHeight = (float)height / 10.0f;
  const float fontWidth = (float)height / 30.0f;
  const float fontHeight = (float)height / 30.0f;

  // reposition title
  std::vector<HUDuiControl*>& list = getControls();
  HUDuiLabel* title = (HUDuiLabel*)list[0];
  title->setFontSize(titleFontWidth, titleFontHeight);
  const OpenGLTexFont& titleFont = title->getFont();
  const float titleWidth = titleFont.getWidth(title->getString());
  float x = 0.5f * ((float)width - titleWidth);
  float y = (float)height - titleFont.getHeight();
  title->setPosition(x, y);

  // reposition options in two columns
  x = 0.5f * (float)width;
  y -= 0.6f * titleFont.getHeight();
  const int count = list.size();
  for (i = 1; i < count; i++) {
    list[i]->setFontSize(fontWidth, fontHeight);
    list[i]->setPosition(x, y);
    y -= 1.0f * list[i]->getFont().getHeight();
  }

  // load current settings
  {
    int i = 6;

    const StartupInfo* info = getStartupInfo();

    // mind the ++i !
    ((HUDuiList*)list[i++])->setIndex(info->useUDPconnection ? 1 : 0);

    // server cache age
    int index = 0;
    switch ((ServerListCache::get())->getMaxCacheAge()){
      case 0: index = 0; break;
      case 5: index = 1; break;
      case 15: index = 2; break;
      case 30: index = 3; break;
      case 60: index = 4; break;
      case 60*5: index = 5; break;
      case 60*15: index = 6; break;
      case 60*24: index = 7; break;
      case 60*24*15: index = 8; break;
      case 60*24*30: index = 9; break;
      default: index = 4;
    }
    ((HUDuiList*)list[i++])->setIndex(index);
    i++; // clear cache label
  }
}

void OptionsMenu::callback(HUDuiControl* w, void* data)
{
  HUDuiList* list = (HUDuiList*)w;

  switch (((const char*)data)[0]) {
    case 'U': {
      StartupInfo* info = getStartupInfo();
      info->useUDPconnection = (list->getIndex() != 0);
      break;
    }

    case 'S': { // server cache
      time_t minutes = 0;
      int index = list->getIndex();
      switch (index){
	case 0: minutes = 0; break;
	case 1: minutes = 5; break;
	case 2: minutes = 15; break;
	case 3: minutes = 30; break;
	case 4: minutes = 60; break;
	case 5: minutes = 60*5; break;
	case 6: minutes = 60*15; break;
	case 7: minutes = 60*24; break;
	case 8: minutes = 60*24*15; break;
	case 9: minutes = 60*24*30; break;
      }
      (ServerListCache::get())->setMaxCacheAge(minutes);
      break;
    }
  }
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

#include "sys.hpp"
#include <ch.hpp>
#include <unistd.h>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdarg>

#if !CH_CFG_USE_REGISTRY
# pragma message "CH_CFG_USE_REGISTRY is disabled, panic reports will be incomplete"
#endif

namespace os
{

extern void emergencyPrint(const char* str);

void panic(const char* msg)
{
    chSysHalt(msg);
    while (1) { }
}

__attribute__((weak))
void applicationHaltHook(void) { }

void sleepUntilChTime(systime_t sleep_until)
{
    chSysLock();
    sleep_until -= chVTGetSystemTime();
    if (((int)sleep_until) > 0)
    {
        chThdSleepS(sleep_until);
    }
    chSysUnlock();

#if defined(DEBUG_BUILD) && DEBUG_BUILD
    if (((int)sleep_until) < 0)
    {
#if CH_CFG_USE_REGISTRY
        const char* const name = chThdGetSelfX()->p_name;
#else
        const char* const name = "<?>";
#endif
        lowsyslog("%s: Lag %d ts\n", name, (int)sleep_until);
    }
#endif
}

} // namespace os

extern "C"
{

__attribute__((weak))
void *__dso_handle;

__attribute__((weak))
int __errno;

void zchSysHaltHook(const char* msg)
{
    using namespace os;

    applicationHaltHook();

    port_disable();
    emergencyPrint("\nPANIC [");
#if CH_CFG_USE_REGISTRY
    const thread_t *pthread = chThdGetSelfX();
    if (pthread && pthread->p_name)
    {
        emergencyPrint(pthread->p_name);
    }
#endif
    emergencyPrint("] ");

    if (msg != NULL)
    {
        emergencyPrint(msg);
    }
    emergencyPrint("\n");

#if defined(DEBUG_BUILD) && DEBUG_BUILD && defined(CoreDebug_DHCSR_C_DEBUGEN_Msk)
    if (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk)
    {
        __asm volatile ("bkpt #0\n"); // Break into the debugger
    }
#endif
}

static void reverse(char* s)
{
    for (int i = 0, j = strlen(s) - 1; i < j; i++, j--)
    {
        const char c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

char* itoa(int n, char* pbuf)
{
    const int sign = n;
    if (sign < 0)
    {
        n = -n;
    }
    unsigned i = 0;
    do
    {
        pbuf[i++] = n % 10 + '0';
    }
    while ((n /= 10) > 0);
    if (sign < 0)
    {
        pbuf[i++] = '-';
    }
    pbuf[i] = '\0';
    reverse(pbuf);
    return pbuf;
}

void __assert_func(const char* file, int line, const char* func, const char* expr)
{
    (void)file;
    (void)line;
    (void)func;
    (void)expr;
    port_disable();

    char line_buf[11];
    itoa(line, line_buf);

    char buf[256]; // We don't care about possible stack overflow because we're going to die anyway
    char* ptr = buf;
    const unsigned size = sizeof(buf);
    unsigned pos = 0;

#define APPEND_MSG(text) { \
        (void)std::strncpy(ptr + pos, text, (size > pos) ? (size - pos) : 0); \
        pos += strlen(text); \
    }

    APPEND_MSG(file);
    APPEND_MSG(":");
    APPEND_MSG(line_buf);
    if (func != NULL)
    {
        APPEND_MSG(" ");
        APPEND_MSG(func);
    }
    APPEND_MSG(": ");
    APPEND_MSG(expr);

#undef APPEND_MSG

    chSysHalt(buf);
    while (1) { }
}

/// From unistd
int usleep(useconds_t useconds)
{
    chThdSleepMicroseconds(useconds);
    return 0;
}

/// From unistd
unsigned sleep(unsigned int seconds)
{
    chThdSleepSeconds(seconds);
    return 0;
}

void* malloc(size_t sz)
{
    return chCoreAlloc(sz);
}

void* calloc(size_t, size_t)
{
    os::panic("calloc");
    return nullptr;
}

void* realloc(void*, size_t)
{
    os::panic("realloc");
    return nullptr;
}

void free(void*)
{
    os::panic("free");
}

}
<commit_msg>Using correct OS API class in sleepUntilChTime()<commit_after>/*
 * Copyright (c) 2014 Zubax, zubax.com
 * Distributed under the MIT License, available in the file LICENSE.
 * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
 */

#include "sys.hpp"
#include <ch.hpp>
#include <unistd.h>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cstdarg>

#if !CH_CFG_USE_REGISTRY
# pragma message "CH_CFG_USE_REGISTRY is disabled, panic reports will be incomplete"
#endif

namespace os
{

extern void emergencyPrint(const char* str);

void panic(const char* msg)
{
    chSysHalt(msg);
    while (1) { }
}

__attribute__((weak))
void applicationHaltHook(void) { }

void sleepUntilChTime(systime_t sleep_until)
{
    chSysLock();
    sleep_until -= chVTGetSystemTimeX();
    if (((int)sleep_until) > 0)
    {
        chThdSleepS(sleep_until);
    }
    chSysUnlock();

#if defined(DEBUG_BUILD) && DEBUG_BUILD
    if (((int)sleep_until) < 0)
    {
#if CH_CFG_USE_REGISTRY
        const char* const name = chThdGetSelfX()->p_name;
#else
        const char* const name = "<?>";
#endif
        lowsyslog("%s: Lag %d ts\n", name, (int)sleep_until);
    }
#endif
}

} // namespace os

extern "C"
{

__attribute__((weak))
void *__dso_handle;

__attribute__((weak))
int __errno;

void zchSysHaltHook(const char* msg)
{
    using namespace os;

    applicationHaltHook();

    port_disable();
    emergencyPrint("\nPANIC [");
#if CH_CFG_USE_REGISTRY
    const thread_t *pthread = chThdGetSelfX();
    if (pthread && pthread->p_name)
    {
        emergencyPrint(pthread->p_name);
    }
#endif
    emergencyPrint("] ");

    if (msg != NULL)
    {
        emergencyPrint(msg);
    }
    emergencyPrint("\n");

#if defined(DEBUG_BUILD) && DEBUG_BUILD && defined(CoreDebug_DHCSR_C_DEBUGEN_Msk)
    if (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk)
    {
        __asm volatile ("bkpt #0\n"); // Break into the debugger
    }
#endif
}

static void reverse(char* s)
{
    for (int i = 0, j = strlen(s) - 1; i < j; i++, j--)
    {
        const char c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

char* itoa(int n, char* pbuf)
{
    const int sign = n;
    if (sign < 0)
    {
        n = -n;
    }
    unsigned i = 0;
    do
    {
        pbuf[i++] = n % 10 + '0';
    }
    while ((n /= 10) > 0);
    if (sign < 0)
    {
        pbuf[i++] = '-';
    }
    pbuf[i] = '\0';
    reverse(pbuf);
    return pbuf;
}

void __assert_func(const char* file, int line, const char* func, const char* expr)
{
    (void)file;
    (void)line;
    (void)func;
    (void)expr;
    port_disable();

    char line_buf[11];
    itoa(line, line_buf);

    char buf[256]; // We don't care about possible stack overflow because we're going to die anyway
    char* ptr = buf;
    const unsigned size = sizeof(buf);
    unsigned pos = 0;

#define APPEND_MSG(text) { \
        (void)std::strncpy(ptr + pos, text, (size > pos) ? (size - pos) : 0); \
        pos += strlen(text); \
    }

    APPEND_MSG(file);
    APPEND_MSG(":");
    APPEND_MSG(line_buf);
    if (func != NULL)
    {
        APPEND_MSG(" ");
        APPEND_MSG(func);
    }
    APPEND_MSG(": ");
    APPEND_MSG(expr);

#undef APPEND_MSG

    chSysHalt(buf);
    while (1) { }
}

/// From unistd
int usleep(useconds_t useconds)
{
    chThdSleepMicroseconds(useconds);
    return 0;
}

/// From unistd
unsigned sleep(unsigned int seconds)
{
    chThdSleepSeconds(seconds);
    return 0;
}

void* malloc(size_t sz)
{
    return chCoreAlloc(sz);
}

void* calloc(size_t, size_t)
{
    os::panic("calloc");
    return nullptr;
}

void* realloc(void*, size_t)
{
    os::panic("realloc");
    return nullptr;
}

void free(void*)
{
    os::panic("free");
}

}
<|endoftext|>


<commit_before>#ifndef _C4_MEMORY_RESOURCE_HPP_
#define _C4_MEMORY_RESOURCE_HPP_

/** @file memory_resource.hpp Provides facilities to allocate memory, via
 *  the memory resource model consecrated with C++17. */

/** @defgroup raw_memory_alloc Raw memory allocation
 *
 */

/** @defgroup memory_resources Memory resources
 *
 */

#include "c4/config.hpp"
#include "c4/error.hpp"

C4_BEGIN_NAMESPACE(c4)

// need these forward decls here
struct MemoryResource;
struct MemoryResourceMalloc;
MemoryResourceMalloc* get_memory_resource_malloc();
namespace detail { MemoryResource*& get_memory_resource(); };

// c-style allocation ---------------------------------------------------------

// this API provides unaligned as well as aligned allocation functions.
// These functions forward the call to a modifiable function.

// aligned allocation.
void* aalloc(size_t sz, size_t alignment);
void afree(void* ptr);
void* arealloc(void* ptr, size_t oldsz, size_t newsz, size_t alignment);

// classic, unaligned allocation.
void* alloc(size_t sz);
void free(void* ptr);
void* realloc(void* ptr, size_t oldsz, size_t newsz);

// allocation setup facilities
using aalloc_type   = void* (*)(size_t size, size_t alignment);
using afree_type    = void  (*)(void *ptr);
using arealloc_type = void* (*)(void *ptr, size_t oldsz, size_t newsz, size_t alignment);

using alloc_type   = void* (*)(size_t size);
using free_type    = void  (*)(void *ptr);
using realloc_type = void* (*)(void *ptr, size_t oldsz, size_t newsz);

// set the function to be called
void set_aalloc  (aalloc_type   fn);
void set_afree   (afree_type    fn);
void set_arealloc(arealloc_type fn);

void set_alloc  (alloc_type   fn);
void set_free   (free_type    fn);
void set_realloc(realloc_type fn);

// get the function which will be called
alloc_type   get_alloc();
free_type    get_free();
realloc_type get_realloc();

aalloc_type   get_aalloc();
free_type     get_afree();
arealloc_type get_arealloc();

// c++-style allocation -------------------------------------------------------

/** C++17-style memory_resource base class. See http://en.cppreference.com/w/cpp/experimental/memory_resource
 * @ingroup memory_resources */
struct MemoryResource
{
    const char *name = nullptr;
    virtual ~MemoryResource() {}

    void* allocate(size_t sz, size_t alignment = alignof(max_align_t))
    {
        void *mem = this->do_allocate(sz, alignment);
        C4_CHECK_MSG(mem != nullptr, "could not allocate %lu bytes", sz);
        return mem;
    }
    void* reallocate(void* ptr, size_t oldsz, size_t newsz, size_t alignment = alignof(max_align_t))
    {
        void *mem = this->do_reallocate(ptr, oldsz, newsz, alignment);
        C4_CHECK_MSG(mem != nullptr, "could not reallocate from %lu to %lu bytes", oldsz, newsz);
        return mem;
    }
    void deallocate(void* ptr, size_t sz, size_t alignment = alignof(max_align_t))
    {
        this->do_deallocate(ptr, sz, alignment);
    }

protected:

    virtual void* do_allocate(size_t sz, size_t alignment) = 0;
    virtual void* do_reallocate(void* ptr, size_t oldsz, size_t newsz, size_t alignment) = 0;
    virtual void  do_deallocate(void* ptr, size_t sz, size_t alignment) = 0;

};

/** get the current global memory resource. To avoid static initialization
 * order problems, this is implemented using a function call to ensure
 * that it is available on when first used.
 * @ingroup memory_resources */
C4_ALWAYS_INLINE MemoryResource* get_memory_resource()
{
    /* T */
    return detail::get_memory_resource();
}

/** set the global memory resource
 * @ingroup memory_resources */
C4_ALWAYS_INLINE void set_memory_resource(MemoryResource* mr)
{
    C4_ASSERT(mr != nullptr);
    detail::get_memory_resource() = mr;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A c4::aalloc-based memory resource. Thread-safe if the implementation called by
 * c4::aalloc() is safe.
 * @ingroup memory_resources */
struct MemoryResourceMalloc : public MemoryResource
{

    MemoryResourceMalloc() { name = "malloc"; }
    virtual ~MemoryResourceMalloc() {}

protected:

    virtual void* do_allocate(size_t sz, size_t alignment) override
    {
        return c4::aalloc(sz, alignment);
    }

    virtual void  do_deallocate(void* ptr, size_t sz, size_t alignment) override
    {
        C4_UNUSED(sz);
        C4_UNUSED(alignment);
        c4::afree(ptr);
    }

    virtual void* do_reallocate(void* ptr, size_t oldsz, size_t newsz, size_t alignment) override
    {
        return c4::arealloc(ptr, oldsz, newsz, alignment);
    }

};

/** returns a malloc-based memory resource
 *  @ingroup memory_resources */
C4_ALWAYS_INLINE MemoryResourceMalloc* get_memory_resource_malloc()
{
    static MemoryResourceMalloc mr;
    return &mr;
}

C4_BEGIN_NAMESPACE(detail)
C4_ALWAYS_INLINE MemoryResource* & get_memory_resource()
{
    static MemoryResource* mr = get_memory_resource_malloc();
    return mr;
}
C4_END_NAMESPACE(detail)

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
struct AllocationCounts
{
    struct Item
    {
        ssize_t allocs;
        ssize_t size;

        void add(size_t sz)
        {
            ++allocs;
            size += sz;
        }
        void rem(size_t sz)
        {
            --allocs;
            size -= sz;
        }
        Item max(Item const& that) const
        {
            Item r(*this);
            r.allocs = r.allocs > that.allocs ? r.allocs : that.allocs;
            r.size = r.size > that.size ? r.size : that.size;
            return r;
        }
    };

    Item curr  = {0, 0};
    Item total = {0, 0};
    Item max   = {0, 0};

    void clear_counts()
    {
        curr  = {0, 0};
        total = {0, 0};
        max   = {0, 0};
    }

    void update(AllocationCounts const& that)
    {
        curr.allocs += that.curr.allocs;
        curr.size += that.curr.size;
        total.allocs += that.total.allocs;
        total.size += that.total.size;
        max.allocs += that.max.allocs;
        max.size += that.max.size;
    }

    void add_counts(void* ptr, size_t sz)
    {
        if(ptr == nullptr) return;
        curr.add(sz);
        total.add(sz);
        max = max.max(curr);
    }

    void rem_counts(void *ptr, size_t sz)
    {
        if(ptr == nullptr) return;
        curr.rem(sz);
    }

    AllocationCounts operator- (AllocationCounts const& that) const
    {
        AllocationCounts r(*this);
        r.curr.allocs -= that.curr.allocs;
        r.curr.size -= that.curr.size;
        r.total.allocs -= that.total.allocs;
        r.total.size -= that.total.size;
        r.max.allocs -= that.max.allocs;
        r.max.size -= that.max.size;
        return r;
    }

    AllocationCounts operator+ (AllocationCounts const& that) const
    {
        AllocationCounts r(*this);
        r.curr.allocs += that.curr.allocs;
        r.curr.size += that.curr.size;
        r.total.allocs += that.total.allocs;
        r.total.size += that.total.size;
        r.max.allocs += that.max.allocs;
        r.max.size += that.max.size;
        return r;
    }
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** a MemoryResource which latches onto another MemoryResource
 * and counts allocations and sizes.
 * @ingroup memory_resources */
class MemoryResourceCounts : public MemoryResource
{
public:

    MemoryResourceCounts() : m_resource(get_memory_resource())
    {
        C4_ASSERT(m_resource != this);
        name = "MemoryResourceCounts";
    }
    MemoryResourceCounts(MemoryResource *res) : m_resource(res)
    {
        C4_ASSERT(m_resource != this);
        name = "MemoryResourceCounts";
    }
    virtual ~MemoryResourceCounts()
    {
        s_counts.update(m_counts);
    }

    MemoryResource *resource() { return m_resource; }
    AllocationCounts const& counts() const { return m_counts; }

protected:

    MemoryResource *m_resource;
    AllocationCounts m_counts;
    static thread_local AllocationCounts s_counts;

protected:

    virtual void* do_allocate(size_t sz, size_t alignment) override
    {
        void *ptr = m_resource->allocate(sz, alignment);
        m_counts.add_counts(ptr, sz);
        return ptr;
    }

    virtual void  do_deallocate(void* ptr, size_t sz, size_t alignment) override
    {
        m_counts.rem_counts(ptr, sz);
        m_resource->deallocate(ptr, sz, alignment);
    }

    virtual void* do_reallocate(void* ptr, size_t oldsz, size_t newsz, size_t alignment) override
    {
        m_counts.rem_counts(ptr, oldsz);
        void* nptr = m_resource->reallocate(ptr, oldsz, newsz, alignment);
        m_counts.add_counts(nptr, newsz);
        return nptr;
    }

};

//-----------------------------------------------------------------------------
/** RAII class which binds a memory resource with a scope duration.
 * @ingroup memory_resources */
struct ScopedMemoryResource
{
    MemoryResource *m_original;

    ScopedMemoryResource(MemoryResource *r)
    :
        m_original(get_memory_resource())
    {
        set_memory_resource(r);
    }

    ~ScopedMemoryResource()
    {
        set_memory_resource(m_original);
    }
};

//-----------------------------------------------------------------------------
/** RAII class which counts allocations and frees inside a scope. Can
 * optionally set also the memory resource to be used.
 * @ingroup memory_resources */
struct ScopedMemoryResourceCounts
{
    MemoryResourceCounts mr;

    ScopedMemoryResourceCounts() : mr()
    {
        set_memory_resource(&mr);
    }
    ScopedMemoryResourceCounts(MemoryResource *m) : mr(m)
    {
        set_memory_resource(&mr);
    }
    ~ScopedMemoryResourceCounts()
    {
        set_memory_resource(mr.resource());
    }
};

C4_END_NAMESPACE(c4)

#endif /* _C4_MEMORY_RESOURCE_HPP_ */
<commit_msg>remove dangling semicolon<commit_after>#ifndef _C4_MEMORY_RESOURCE_HPP_
#define _C4_MEMORY_RESOURCE_HPP_

/** @file memory_resource.hpp Provides facilities to allocate memory, via
 *  the memory resource model consecrated with C++17. */

/** @defgroup raw_memory_alloc Raw memory allocation
 *
 */

/** @defgroup memory_resources Memory resources
 *
 */

#include "c4/config.hpp"
#include "c4/error.hpp"

C4_BEGIN_NAMESPACE(c4)

// need these forward decls here
struct MemoryResource;
struct MemoryResourceMalloc;
MemoryResourceMalloc* get_memory_resource_malloc();
namespace detail { MemoryResource*& get_memory_resource(); }

// c-style allocation ---------------------------------------------------------

// this API provides unaligned as well as aligned allocation functions.
// These functions forward the call to a modifiable function.

// aligned allocation.
void* aalloc(size_t sz, size_t alignment);
void afree(void* ptr);
void* arealloc(void* ptr, size_t oldsz, size_t newsz, size_t alignment);

// classic, unaligned allocation.
void* alloc(size_t sz);
void free(void* ptr);
void* realloc(void* ptr, size_t oldsz, size_t newsz);

// allocation setup facilities
using aalloc_type   = void* (*)(size_t size, size_t alignment);
using afree_type    = void  (*)(void *ptr);
using arealloc_type = void* (*)(void *ptr, size_t oldsz, size_t newsz, size_t alignment);

using alloc_type   = void* (*)(size_t size);
using free_type    = void  (*)(void *ptr);
using realloc_type = void* (*)(void *ptr, size_t oldsz, size_t newsz);

// set the function to be called
void set_aalloc  (aalloc_type   fn);
void set_afree   (afree_type    fn);
void set_arealloc(arealloc_type fn);

void set_alloc  (alloc_type   fn);
void set_free   (free_type    fn);
void set_realloc(realloc_type fn);

// get the function which will be called
alloc_type   get_alloc();
free_type    get_free();
realloc_type get_realloc();

aalloc_type   get_aalloc();
free_type     get_afree();
arealloc_type get_arealloc();

// c++-style allocation -------------------------------------------------------

/** C++17-style memory_resource base class. See http://en.cppreference.com/w/cpp/experimental/memory_resource
 * @ingroup memory_resources */
struct MemoryResource
{
    const char *name = nullptr;
    virtual ~MemoryResource() {}

    void* allocate(size_t sz, size_t alignment = alignof(max_align_t))
    {
        void *mem = this->do_allocate(sz, alignment);
        C4_CHECK_MSG(mem != nullptr, "could not allocate %lu bytes", sz);
        return mem;
    }
    void* reallocate(void* ptr, size_t oldsz, size_t newsz, size_t alignment = alignof(max_align_t))
    {
        void *mem = this->do_reallocate(ptr, oldsz, newsz, alignment);
        C4_CHECK_MSG(mem != nullptr, "could not reallocate from %lu to %lu bytes", oldsz, newsz);
        return mem;
    }
    void deallocate(void* ptr, size_t sz, size_t alignment = alignof(max_align_t))
    {
        this->do_deallocate(ptr, sz, alignment);
    }

protected:

    virtual void* do_allocate(size_t sz, size_t alignment) = 0;
    virtual void* do_reallocate(void* ptr, size_t oldsz, size_t newsz, size_t alignment) = 0;
    virtual void  do_deallocate(void* ptr, size_t sz, size_t alignment) = 0;

};

/** get the current global memory resource. To avoid static initialization
 * order problems, this is implemented using a function call to ensure
 * that it is available on when first used.
 * @ingroup memory_resources */
C4_ALWAYS_INLINE MemoryResource* get_memory_resource()
{
    /* T */
    return detail::get_memory_resource();
}

/** set the global memory resource
 * @ingroup memory_resources */
C4_ALWAYS_INLINE void set_memory_resource(MemoryResource* mr)
{
    C4_ASSERT(mr != nullptr);
    detail::get_memory_resource() = mr;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** A c4::aalloc-based memory resource. Thread-safe if the implementation called by
 * c4::aalloc() is safe.
 * @ingroup memory_resources */
struct MemoryResourceMalloc : public MemoryResource
{

    MemoryResourceMalloc() { name = "malloc"; }
    virtual ~MemoryResourceMalloc() {}

protected:

    virtual void* do_allocate(size_t sz, size_t alignment) override
    {
        return c4::aalloc(sz, alignment);
    }

    virtual void  do_deallocate(void* ptr, size_t sz, size_t alignment) override
    {
        C4_UNUSED(sz);
        C4_UNUSED(alignment);
        c4::afree(ptr);
    }

    virtual void* do_reallocate(void* ptr, size_t oldsz, size_t newsz, size_t alignment) override
    {
        return c4::arealloc(ptr, oldsz, newsz, alignment);
    }

};

/** returns a malloc-based memory resource
 *  @ingroup memory_resources */
C4_ALWAYS_INLINE MemoryResourceMalloc* get_memory_resource_malloc()
{
    static MemoryResourceMalloc mr;
    return &mr;
}

C4_BEGIN_NAMESPACE(detail)
C4_ALWAYS_INLINE MemoryResource* & get_memory_resource()
{
    static MemoryResource* mr = get_memory_resource_malloc();
    return mr;
}
C4_END_NAMESPACE(detail)

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
struct AllocationCounts
{
    struct Item
    {
        ssize_t allocs;
        ssize_t size;

        void add(size_t sz)
        {
            ++allocs;
            size += sz;
        }
        void rem(size_t sz)
        {
            --allocs;
            size -= sz;
        }
        Item max(Item const& that) const
        {
            Item r(*this);
            r.allocs = r.allocs > that.allocs ? r.allocs : that.allocs;
            r.size = r.size > that.size ? r.size : that.size;
            return r;
        }
    };

    Item curr  = {0, 0};
    Item total = {0, 0};
    Item max   = {0, 0};

    void clear_counts()
    {
        curr  = {0, 0};
        total = {0, 0};
        max   = {0, 0};
    }

    void update(AllocationCounts const& that)
    {
        curr.allocs += that.curr.allocs;
        curr.size += that.curr.size;
        total.allocs += that.total.allocs;
        total.size += that.total.size;
        max.allocs += that.max.allocs;
        max.size += that.max.size;
    }

    void add_counts(void* ptr, size_t sz)
    {
        if(ptr == nullptr) return;
        curr.add(sz);
        total.add(sz);
        max = max.max(curr);
    }

    void rem_counts(void *ptr, size_t sz)
    {
        if(ptr == nullptr) return;
        curr.rem(sz);
    }

    AllocationCounts operator- (AllocationCounts const& that) const
    {
        AllocationCounts r(*this);
        r.curr.allocs -= that.curr.allocs;
        r.curr.size -= that.curr.size;
        r.total.allocs -= that.total.allocs;
        r.total.size -= that.total.size;
        r.max.allocs -= that.max.allocs;
        r.max.size -= that.max.size;
        return r;
    }

    AllocationCounts operator+ (AllocationCounts const& that) const
    {
        AllocationCounts r(*this);
        r.curr.allocs += that.curr.allocs;
        r.curr.size += that.curr.size;
        r.total.allocs += that.total.allocs;
        r.total.size += that.total.size;
        r.max.allocs += that.max.allocs;
        r.max.size += that.max.size;
        return r;
    }
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/** a MemoryResource which latches onto another MemoryResource
 * and counts allocations and sizes.
 * @ingroup memory_resources */
class MemoryResourceCounts : public MemoryResource
{
public:

    MemoryResourceCounts() : m_resource(get_memory_resource())
    {
        C4_ASSERT(m_resource != this);
        name = "MemoryResourceCounts";
    }
    MemoryResourceCounts(MemoryResource *res) : m_resource(res)
    {
        C4_ASSERT(m_resource != this);
        name = "MemoryResourceCounts";
    }
    virtual ~MemoryResourceCounts()
    {
        s_counts.update(m_counts);
    }

    MemoryResource *resource() { return m_resource; }
    AllocationCounts const& counts() const { return m_counts; }

protected:

    MemoryResource *m_resource;
    AllocationCounts m_counts;
    static thread_local AllocationCounts s_counts;

protected:

    virtual void* do_allocate(size_t sz, size_t alignment) override
    {
        void *ptr = m_resource->allocate(sz, alignment);
        m_counts.add_counts(ptr, sz);
        return ptr;
    }

    virtual void  do_deallocate(void* ptr, size_t sz, size_t alignment) override
    {
        m_counts.rem_counts(ptr, sz);
        m_resource->deallocate(ptr, sz, alignment);
    }

    virtual void* do_reallocate(void* ptr, size_t oldsz, size_t newsz, size_t alignment) override
    {
        m_counts.rem_counts(ptr, oldsz);
        void* nptr = m_resource->reallocate(ptr, oldsz, newsz, alignment);
        m_counts.add_counts(nptr, newsz);
        return nptr;
    }

};

//-----------------------------------------------------------------------------
/** RAII class which binds a memory resource with a scope duration.
 * @ingroup memory_resources */
struct ScopedMemoryResource
{
    MemoryResource *m_original;

    ScopedMemoryResource(MemoryResource *r)
    :
        m_original(get_memory_resource())
    {
        set_memory_resource(r);
    }

    ~ScopedMemoryResource()
    {
        set_memory_resource(m_original);
    }
};

//-----------------------------------------------------------------------------
/** RAII class which counts allocations and frees inside a scope. Can
 * optionally set also the memory resource to be used.
 * @ingroup memory_resources */
struct ScopedMemoryResourceCounts
{
    MemoryResourceCounts mr;

    ScopedMemoryResourceCounts() : mr()
    {
        set_memory_resource(&mr);
    }
    ScopedMemoryResourceCounts(MemoryResource *m) : mr(m)
    {
        set_memory_resource(&mr);
    }
    ~ScopedMemoryResourceCounts()
    {
        set_memory_resource(mr.resource());
    }
};

C4_END_NAMESPACE(c4)

#endif /* _C4_MEMORY_RESOURCE_HPP_ */
<|endoftext|>


<commit_before>#include "polylineStyle.h"

#include "tangram.h"
#include "platform.h"
#include "material.h"
#include "gl/shaderProgram.h"
#include "gl/typedMesh.h"
#include "scene/stops.h"
#include "scene/drawRule.h"
#include "tile/tile.h"
#include "util/mapProjection.h"
#include "glm/vec3.hpp"

namespace Tangram {

struct PolylineVertex {
    glm::vec3 pos;
    glm::vec2 texcoord;
    glm::vec4 extrude;
    GLuint abgr;
    GLfloat layer;
};

using Mesh = TypedMesh<PolylineVertex>;

PolylineStyle::PolylineStyle(std::string _name, Blending _blendMode, GLenum _drawMode)
    : Style(_name, _blendMode, _drawMode) {
}

void PolylineStyle::constructVertexLayout() {

    // TODO: Ideally this would be in the same location as the struct that it basically describes
    m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
        {"a_position", 3, GL_FLOAT, false, 0},
        {"a_texcoord", 2, GL_FLOAT, false, 0},
        {"a_extrude", 4, GL_FLOAT, false, 0},
        {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
        {"a_layer", 1, GL_FLOAT, false, 0}
    }));

}

void PolylineStyle::constructShaderProgram() {

    std::string vertShaderSrcStr = stringFromFile("shaders/polyline.vs", PathType::internal);
    std::string fragShaderSrcStr = stringFromFile("shaders/polyline.fs", PathType::internal);

    m_shaderProgram->setSourceStrings(fragShaderSrcStr, vertShaderSrcStr);
}

VboMesh* PolylineStyle::newMesh() const {
    return new Mesh(m_vertexLayout, m_drawMode);
}

PolylineStyle::Parameters PolylineStyle::parseRule(const DrawRule& _rule) const {
    Parameters p;

    uint32_t cap = 0, join = 0;

    _rule.get(StyleParamKey::extrude, p.extrude);
    _rule.get(StyleParamKey::color, p.color);
    _rule.get(StyleParamKey::cap, cap);
    _rule.get(StyleParamKey::join, join);
    _rule.get(StyleParamKey::order, p.order);

    p.cap = static_cast<CapTypes>(cap);
    p.join = static_cast<JoinTypes>(join);

    p.outlineOrder = p.order; // will offset from fill later

    if (_rule.get(StyleParamKey::outline_color, p.outlineColor) |
        _rule.get(StyleParamKey::outline_order, p.outlineOrder) |
        _rule.contains(StyleParamKey::outline_width) |
        _rule.get(StyleParamKey::outline_cap, cap) |
        _rule.get(StyleParamKey::outline_join, join)) {
        p.outlineOn = true;
        p.outlineCap = static_cast<CapTypes>(cap);
        p.outlineJoin = static_cast<JoinTypes>(join);
    }

    return p;
}

void PolylineStyle::buildPolygon(const Polygon& _poly, const DrawRule& _rule, const Properties& _props,
                                 VboMesh& _mesh, Tile& _tile) const {

    for (const auto& line : _poly) {
        buildLine(line, _rule, _props, _mesh, _tile);
    }
}

double widthMeterToPixel(int _zoom, double _tileSize, double _width) {
    // pixel per meter at z == 0
    double meterRes = _tileSize / (2.0 * MapProjection::HALF_CIRCUMFERENCE);
    // pixel per meter at zoom
    meterRes *= exp2(_zoom);

    return _width * meterRes;
}

bool evalStyleParamWidth(StyleParamKey _key, const DrawRule& _rule, const Tile& _tile,
                         float& width, float& dWdZ){

    int zoom  = _tile.getID().z;
    double tileSize = _tile.getProjection()->TileSize();

    // NB: 0.5 because 'width' will be extruded in both directions
    double tileRes = 0.5 / tileSize;

    auto& styleParam = _rule.findParameter(_key);
    if (styleParam.stops) {

        width = styleParam.stops->evalWidth(zoom);
        width *= tileRes;

        dWdZ = styleParam.stops->evalWidth(zoom + 1);
        dWdZ *= tileRes;
        // NB: Multiply by 2 for the outline to get the expected stroke pixel width.
        if (_key == StyleParamKey::outline_width) {
            width *= 2;
            dWdZ *= 2;
        }

        dWdZ -= width;

        return true;
    }

    if (styleParam.value.is<StyleParam::Width>()) {
        auto& widthParam = styleParam.value.get<StyleParam::Width>();

        width = widthParam.value;

        if (widthParam.isMeter()) {
            width = widthMeterToPixel(zoom, tileSize, width);
            width *= tileRes;
            dWdZ = width * 2;
        } else {
            width *= tileRes;
            dWdZ = width;
        }

        if (_key == StyleParamKey::outline_width) {
            width *= 2;
            dWdZ *= 2;
        }

        dWdZ -= width;

        return true;
    }

    LOGD("Invalid type for Width '%d'\n", styleParam.value.which());
    return false;
}

void PolylineStyle::buildLine(const Line& _line, const DrawRule& _rule, const Properties& _props,
                              VboMesh& _mesh, Tile& _tile) const {

    std::vector<PolylineVertex> vertices;

    Parameters params = parseRule(_rule);
    GLuint abgr = params.color;

    float dWdZ = 0.f;
    float width = 0.f;

    if (!evalStyleParamWidth(StyleParamKey::width, _rule, _tile, width, dWdZ)) {
        return;
    }

    // Make sure main line width is not zero
    if (width == 0.0f) { return; }

    if (Tangram::getDebugFlag(Tangram::DebugFlags::proxy_colors)) {
        abgr = abgr << (_tile.getID().z % 6);
    }

    float height = 0.0f;
    auto& extrude = params.extrude;

    if (extrude[0] != 0.0f || extrude[1] != 0.0f) {
        const static std::string key_height("height");

        height = _props.getNumeric(key_height) * _tile.getInverseScale();
        if (std::isnan(extrude[1])) {
            if (!std::isnan(extrude[0])) {
                height = extrude[0];
            }
        } else { height = extrude[1]; }
    }

    PolyLineBuilder builder {
        [&](const glm::vec3& coord, const glm::vec2& normal, const glm::vec2& uv) {
            glm::vec4 extrude = { normal.x, normal.y, width, dWdZ };
            vertices.push_back({ {coord.x, coord.y, height}, uv, extrude, abgr, (float)params.order });
        },
        [&](size_t sizeHint){ vertices.reserve(sizeHint); },
        params.cap,
        params.join
    };

    Builders::buildPolyLine(_line, builder);

    if (params.outlineOn) {

        GLuint abgrOutline = params.outlineColor;
        float outlineOrder = std::min(params.outlineOrder, params.order) - .5f;

        float widthOutline = 0.f;
        float dWdZOutline = 0.f;

        if (!evalStyleParamWidth(StyleParamKey::outline_width, _rule, _tile,
                                 widthOutline, dWdZOutline)) {
            return;
        }

        widthOutline += width;
        dWdZOutline += dWdZ;

        if (params.outlineCap != params.cap || params.outlineJoin != params.join) {
            // need to re-triangulate with different cap and/or join
            builder.cap = params.outlineCap;
            builder.join = params.outlineJoin;
            Builders::buildPolyLine(_line, builder);
        } else {
            // re-use indices from original line
            size_t oldSize = builder.indices.size();
            size_t offset = vertices.size();
            builder.indices.reserve(2 * oldSize);

            for(size_t i = 0; i < oldSize; i++) {
                 builder.indices.push_back(offset + builder.indices[i]);
            }
            for (size_t i = 0; i < offset; i++) {
                const auto& v = vertices[i];
                glm::vec4 extrudeOutline = { v.extrude.x, v.extrude.y, widthOutline, dWdZOutline };
                vertices.push_back({ v.pos, v.texcoord, extrudeOutline, abgrOutline, outlineOrder });
            }
        }
    }

    auto& mesh = static_cast<Mesh&>(_mesh);
    mesh.addVertices(std::move(vertices), std::move(builder.indices));
}

}
<commit_msg>More early return width checks<commit_after>#include "polylineStyle.h"

#include "tangram.h"
#include "platform.h"
#include "material.h"
#include "gl/shaderProgram.h"
#include "gl/typedMesh.h"
#include "scene/stops.h"
#include "scene/drawRule.h"
#include "tile/tile.h"
#include "util/mapProjection.h"
#include "glm/vec3.hpp"

namespace Tangram {

struct PolylineVertex {
    glm::vec3 pos;
    glm::vec2 texcoord;
    glm::vec4 extrude;
    GLuint abgr;
    GLfloat layer;
};

using Mesh = TypedMesh<PolylineVertex>;

PolylineStyle::PolylineStyle(std::string _name, Blending _blendMode, GLenum _drawMode)
    : Style(_name, _blendMode, _drawMode) {
}

void PolylineStyle::constructVertexLayout() {

    // TODO: Ideally this would be in the same location as the struct that it basically describes
    m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
        {"a_position", 3, GL_FLOAT, false, 0},
        {"a_texcoord", 2, GL_FLOAT, false, 0},
        {"a_extrude", 4, GL_FLOAT, false, 0},
        {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
        {"a_layer", 1, GL_FLOAT, false, 0}
    }));

}

void PolylineStyle::constructShaderProgram() {

    std::string vertShaderSrcStr = stringFromFile("shaders/polyline.vs", PathType::internal);
    std::string fragShaderSrcStr = stringFromFile("shaders/polyline.fs", PathType::internal);

    m_shaderProgram->setSourceStrings(fragShaderSrcStr, vertShaderSrcStr);
}

VboMesh* PolylineStyle::newMesh() const {
    return new Mesh(m_vertexLayout, m_drawMode);
}

PolylineStyle::Parameters PolylineStyle::parseRule(const DrawRule& _rule) const {
    Parameters p;

    uint32_t cap = 0, join = 0;

    _rule.get(StyleParamKey::extrude, p.extrude);
    _rule.get(StyleParamKey::color, p.color);
    _rule.get(StyleParamKey::cap, cap);
    _rule.get(StyleParamKey::join, join);
    _rule.get(StyleParamKey::order, p.order);

    p.cap = static_cast<CapTypes>(cap);
    p.join = static_cast<JoinTypes>(join);

    p.outlineOrder = p.order; // will offset from fill later

    if (_rule.get(StyleParamKey::outline_color, p.outlineColor) |
        _rule.get(StyleParamKey::outline_order, p.outlineOrder) |
        _rule.contains(StyleParamKey::outline_width) |
        _rule.get(StyleParamKey::outline_cap, cap) |
        _rule.get(StyleParamKey::outline_join, join)) {
        p.outlineOn = true;
        p.outlineCap = static_cast<CapTypes>(cap);
        p.outlineJoin = static_cast<JoinTypes>(join);
    }

    return p;
}

void PolylineStyle::buildPolygon(const Polygon& _poly, const DrawRule& _rule, const Properties& _props,
                                 VboMesh& _mesh, Tile& _tile) const {

    for (const auto& line : _poly) {
        buildLine(line, _rule, _props, _mesh, _tile);
    }
}

double widthMeterToPixel(int _zoom, double _tileSize, double _width) {
    // pixel per meter at z == 0
    double meterRes = _tileSize / (2.0 * MapProjection::HALF_CIRCUMFERENCE);
    // pixel per meter at zoom
    meterRes *= exp2(_zoom);

    return _width * meterRes;
}

bool evalStyleParamWidth(StyleParamKey _key, const DrawRule& _rule, const Tile& _tile,
                         float& width, float& dWdZ){

    int zoom  = _tile.getID().z;
    double tileSize = _tile.getProjection()->TileSize();

    // NB: 0.5 because 'width' will be extruded in both directions
    double tileRes = 0.5 / tileSize;

    auto& styleParam = _rule.findParameter(_key);
    if (styleParam.stops) {

        width = styleParam.stops->evalWidth(zoom);
        width *= tileRes;

        dWdZ = styleParam.stops->evalWidth(zoom + 1);
        dWdZ *= tileRes;
        // NB: Multiply by 2 for the outline to get the expected stroke pixel width.
        if (_key == StyleParamKey::outline_width) {
            width *= 2;
            dWdZ *= 2;
        }

        dWdZ -= width;

        return true;
    }

    if (styleParam.value.is<StyleParam::Width>()) {
        auto& widthParam = styleParam.value.get<StyleParam::Width>();

        width = widthParam.value;

        if (widthParam.isMeter()) {
            width = widthMeterToPixel(zoom, tileSize, width);
            width *= tileRes;
            dWdZ = width * 2;
        } else {
            width *= tileRes;
            dWdZ = width;
        }

        if (_key == StyleParamKey::outline_width) {
            width *= 2;
            dWdZ *= 2;
        }

        dWdZ -= width;

        return true;
    }

    LOGD("Invalid type for Width '%d'\n", styleParam.value.which());
    return false;
}

void PolylineStyle::buildLine(const Line& _line, const DrawRule& _rule, const Properties& _props,
                              VboMesh& _mesh, Tile& _tile) const {

    std::vector<PolylineVertex> vertices;

    Parameters params = parseRule(_rule);
    GLuint abgr = params.color;

    float dWdZ = 0.f;
    float width = 0.f;

    if (!evalStyleParamWidth(StyleParamKey::width, _rule, _tile, width, dWdZ)) {
        return;
    }

    if ( (width > -FLT_EPSILON && width < FLT_EPSILON) &&
         (dWdZ > -FLT_EPSILON && dWdZ < FLT_EPSILON) ) { return; }

    if (Tangram::getDebugFlag(Tangram::DebugFlags::proxy_colors)) {
        abgr = abgr << (_tile.getID().z % 6);
    }

    float height = 0.0f;
    auto& extrude = params.extrude;

    if (extrude[0] != 0.0f || extrude[1] != 0.0f) {
        const static std::string key_height("height");

        height = _props.getNumeric(key_height) * _tile.getInverseScale();
        if (std::isnan(extrude[1])) {
            if (!std::isnan(extrude[0])) {
                height = extrude[0];
            }
        } else { height = extrude[1]; }
    }

    PolyLineBuilder builder {
        [&](const glm::vec3& coord, const glm::vec2& normal, const glm::vec2& uv) {
            glm::vec4 extrude = { normal.x, normal.y, width, dWdZ };
            vertices.push_back({ {coord.x, coord.y, height}, uv, extrude, abgr, (float)params.order });
        },
        [&](size_t sizeHint){ vertices.reserve(sizeHint); },
        params.cap,
        params.join
    };

    Builders::buildPolyLine(_line, builder);

    if (params.outlineOn) {

        GLuint abgrOutline = params.outlineColor;
        float outlineOrder = std::min(params.outlineOrder, params.order) - .5f;

        float widthOutline = 0.f;
        float dWdZOutline = 0.f;

        if (evalStyleParamWidth(StyleParamKey::outline_width, _rule, _tile, widthOutline, dWdZOutline) &&
           ((widthOutline < -FLT_EPSILON || widthOutline > FLT_EPSILON) ||
           (dWdZOutline < -FLT_EPSILON || dWdZOutline > FLT_EPSILON)) ) {

            widthOutline += width;
            dWdZOutline += dWdZ;

            if (params.outlineCap != params.cap || params.outlineJoin != params.join) {
                // need to re-triangulate with different cap and/or join
                builder.cap = params.outlineCap;
                builder.join = params.outlineJoin;
                Builders::buildPolyLine(_line, builder);
            } else {
                // re-use indices from original line
                size_t oldSize = builder.indices.size();
                size_t offset = vertices.size();
                builder.indices.reserve(2 * oldSize);

                for(size_t i = 0; i < oldSize; i++) {
                    builder.indices.push_back(offset + builder.indices[i]);
                }
                for (size_t i = 0; i < offset; i++) {
                    const auto& v = vertices[i];
                    glm::vec4 extrudeOutline = { v.extrude.x, v.extrude.y, widthOutline, dWdZOutline };
                    vertices.push_back({ v.pos, v.texcoord, extrudeOutline, abgrOutline, outlineOrder });
                }
            }
        }
    }

    auto& mesh = static_cast<Mesh&>(_mesh);
    mesh.addVertices(std::move(vertices), std::move(builder.indices));
}

}
<|endoftext|>


<commit_before>#include "async_game.h"

#include "../event/event.h"
#include "../action/simple_card.h"

#include <string>
#include <stdexcept>

#include <iostream>

namespace Casino { namespace Uno { namespace Game {

namespace Event = ::Casino::Uno::Event;
using ::Casino::Uno::Action::SimpleCard;

AsyncGame::AsyncGame(int max_player_count)
	:Casino::Uno::Game::Game(max_player_count)
{

}

void AsyncGame::start() {
	// prepare deck
	deck.shuffleDeck();
	deck.playOutFirstCard();

	// deal initial hands
	std::list<Player *>::iterator player;
	for (int card_idx = 0; card_idx < config.initial_hand_size; card_idx++) {
		players.reset();
		for (int i = 0; i < players.size(); i++, players.next()) {
			players.getCurrentPlayer()->addAction(deck.drawCard());
		}
	}

	{   // send game start event
		Event::game_start event;
		SimpleCard first_card(
			deck.last_played_color,
			deck.last_played_value
		);
		event.first_card = &first_card;
		players.notifyAll(
			Event::EVENT_GAME_START,
			reinterpret_cast<void*>(&event)
		);
	}

	{   // start the first turn
		players.reset();
		Event::players_turn event;
		event.player = players.getCurrentPlayer();
		players.notifyAll(
			Event::EVENT_PLAYERS_TURN,
			reinterpret_cast<void*>(&event)
		);
	}
}

/**
 * @todo use enum status instead of string,
 * tweak takeAction to it after
 */
bool AsyncGame::isValidMove(Player* player, Action* action, std::string &message) {
	if (action == getDrawAction() && player == players.getCurrentPlayer()) {
		return true;
	}

	Card *card = static_cast<Card*>(action);

	// current player or same card
	if (
		deck.last_played_color == card->getColor()
	&&  deck.last_played_value == card->getValue()
	) {
		return true;
	} else if (player != players.getCurrentPlayer()) {
		message = "Not your turn";
		return false;
	}

	if (isPenalty()) {
		if (deck.last_played_value == CARD_VALUE_PLUSFOUR) {
			if (card->getValue() == CARD_VALUE_PLUSFOUR) {
				return true;
			} else {
				message = "Must play +4 or draw";
				return false;
			}
		} else {
			if (
				card->getValue() == CARD_VALUE_PLUSFOUR ||
				card->getValue() == CARD_VALUE_PLUSTWO
			) {
				return true;
			} else {
				message = "Must play +4 or +2 or draw";
				return false;
			}
		}
	} else {
		if (card->getColor() == CARD_COLOR_BLACK) {
			return true;
		}

		if (deck.last_played_color == card->getColor()) {
			return true;
		}

		if (deck.last_played_value == card->getValue()) {
			return true;
		}

		message = "The color or the figure must match";
		return false;
	}
}

void AsyncGame::takeAction(Player* player, Action* action) {
	std::string message;
	bool is_valid = false;
	is_valid = isValidMove(player, action, message);

	if (!is_valid) {
		throw std::invalid_argument(message.c_str());
	}

	if (action->isDisposeable()) {
		player->removeAction(action);

		Card* played_card = static_cast<Card*>(action);
		deck.last_played_color = played_card->getColor();
		deck.last_played_value = played_card->getValue();
		deck.addCardToPlayed(played_card);

		{ //notify about played card
			Event::card_played event;
			SimpleCard played_card(
				deck.last_played_color,
				deck.last_played_value
			);
			event.played_card = &played_card;
			event.played_by = player;
			players.notifyOthers(
				Event::EVENT_CARD_PLAYED,
				reinterpret_cast<void*>(&event),
				player
			);
		}
	}

	// call actions action
	action->takeAction(this);

	// check for forgotten uno
	/** @todo implement this */
	//checkUno();

	// determine next player
	Player* next_player;
	do {
		std::cout << ".";
		players.next();
		next_player = players.getCurrentPlayer();
	} while (next_player->isBlocked() == true);

	{   // notify about the next player
		Event::players_turn event;
		event.player = players.getCurrentPlayer();
		players.notifyAll(
			Event::EVENT_PLAYERS_TURN,
			reinterpret_cast<void*>(&event)
		);
	}
}

void AsyncGame::drawCards() {
	//player draws the current penalty or a single card
	int card_count = (isPenalty()) ? current_penalty : 1;

	Game::drawCards();

	Event::draw_card event;
	event.player = players.getCurrentPlayer();
	event.card_count = card_count;
	players.notifyOthers(
		Event::EVENT_DRAW_CARD,
		reinterpret_cast<void*>(&event),
		players.getCurrentPlayer()
	);
}

}}} //namespace
<commit_msg>handle blocked players. Still serious bugs present around +4 card those I can't fix in the precise moment<commit_after>#include "async_game.h"

#include "../event/event.h"
#include "../action/simple_card.h"

#include <string>
#include <stdexcept>

#include <iostream>

namespace Casino { namespace Uno { namespace Game {

namespace Event = ::Casino::Uno::Event;
using ::Casino::Uno::Action::SimpleCard;

AsyncGame::AsyncGame(int max_player_count)
	:Casino::Uno::Game::Game(max_player_count)
{

}

void AsyncGame::start() {
	// prepare deck
	deck.shuffleDeck();
	deck.playOutFirstCard();

	// deal initial hands
	std::list<Player *>::iterator player;
	for (int card_idx = 0; card_idx < config.initial_hand_size; card_idx++) {
		players.reset();
		for (int i = 0; i < players.size(); i++, players.next()) {
			players.getCurrentPlayer()->addAction(deck.drawCard());
		}
	}

	{   // send game start event
		Event::game_start event;
		SimpleCard first_card(
			deck.last_played_color,
			deck.last_played_value
		);
		event.first_card = &first_card;
		players.notifyAll(
			Event::EVENT_GAME_START,
			reinterpret_cast<void*>(&event)
		);
	}

	{   // start the first turn
		players.reset();
		Event::players_turn event;
		event.player = players.getCurrentPlayer();
		players.notifyAll(
			Event::EVENT_PLAYERS_TURN,
			reinterpret_cast<void*>(&event)
		);
	}
}

/**
 * @todo use enum status instead of string,
 * tweak takeAction to it after
 */
bool AsyncGame::isValidMove(Player* player, Action* action, std::string &message) {
	if (action == getDrawAction() && player == players.getCurrentPlayer()) {
		return true;
	}

	Card *card = static_cast<Card*>(action);

	// current player or same card
	if (
		deck.last_played_color == card->getColor()
	&&  deck.last_played_value == card->getValue()
	) {
		return true;
	} else if (player != players.getCurrentPlayer()) {
		message = "Not your turn";
		return false;
	}

	if (isPenalty()) {
		if (deck.last_played_value == CARD_VALUE_PLUSFOUR) {
			if (card->getValue() == CARD_VALUE_PLUSFOUR) {
				return true;
			} else {
				message = "Must play +4 or draw";
				return false;
			}
		} else {
			if (
				card->getValue() == CARD_VALUE_PLUSFOUR ||
				card->getValue() == CARD_VALUE_PLUSTWO
			) {
				return true;
			} else {
				message = "Must play +4 or +2 or draw";
				return false;
			}
		}
	} else {
		if (card->getColor() == CARD_COLOR_BLACK) {
			return true;
		}

		if (deck.last_played_color == card->getColor()) {
			return true;
		}

		if (deck.last_played_value == card->getValue()) {
			return true;
		}

		message = "The color or the figure must match";
		return false;
	}
}

void AsyncGame::takeAction(Player* player, Action* action) {
	std::string message;
	bool is_valid = false;
	is_valid = isValidMove(player, action, message);

	if (!is_valid) {
		throw std::invalid_argument(message.c_str());
	}

	if (action->isDisposeable()) {
		player->removeAction(action);

		Card* played_card = static_cast<Card*>(action);
		deck.last_played_color = played_card->getColor();
		deck.last_played_value = played_card->getValue();
		deck.addCardToPlayed(played_card);

		{ //notify about played card
			Event::card_played event;
			SimpleCard played_card(
				deck.last_played_color,
				deck.last_played_value
			);
			event.played_card = &played_card;
			event.played_by = player;
			players.notifyOthers(
				Event::EVENT_CARD_PLAYED,
				reinterpret_cast<void*>(&event),
				player
			);
		}
	}

	// call actions action
	action->takeAction(this);

	// check for forgotten uno
	/** @todo implement this */
	//checkUno();

	// determine next player
	Player* next_player;
	bool next_player_found = false;

	while (!next_player_found) {
		std::cout << ".";
		players.next();
		next_player = players.getCurrentPlayer();
		if (next_player->isBlocked() == true) {
			next_player->unblock();
		} else {
			next_player_found = true;
		}
	}

	{   // notify about the next player
		Event::players_turn event;
		event.player = players.getCurrentPlayer();
		players.notifyAll(
			Event::EVENT_PLAYERS_TURN,
			reinterpret_cast<void*>(&event)
		);
	}
}

void AsyncGame::drawCards() {
	//player draws the current penalty or a single card
	int card_count = (isPenalty()) ? current_penalty : 1;

	Game::drawCards();

	Event::draw_card event;
	event.player = players.getCurrentPlayer();
	event.card_count = card_count;
	players.notifyOthers(
		Event::EVENT_DRAW_CARD,
		reinterpret_cast<void*>(&event),
		players.getCurrentPlayer()
	);
}

}}} //namespace
<|endoftext|>