<commit_before>// CoolPropMathcad.cpp : Defines the exported functions for the DLL Add-in.
//

#include <string>

#ifndef NOMINMAX; // Kill window's horrible min() and max() macros
#include "mcadincl.h"
#undef NOMINMAX;

enum { MC_STRING = STRING };  // substitute enumeration variable MC_STRING for STRING, use MC_STRING below
#undef STRING                 // undefine STRING as it conflicts with STRING enum in cppformat/format.h

#include "CoolProp.h"
#include "HumidAirProp.h"

enum EC { INTERRUPTED, INSUFFICIENT_MEMORY, MUST_BE_REAL, NUMBER_OF_ERRORS = MUST_BE_REAL };   // Mathcad Error Codes

    // table of error messages
    // if user function never returns an
    // error -- you do not need to create this
    // table
    char * myErrorMessageTable[NUMBER_OF_ERRORS] =
    {
        "Interrupted"
        "Insufficient Memory"
        "Argument must be real"
    };

    // this code executes the user function CP_get_global_param_string, which is a wrapper for
    // the CoolProp.get_global_param_string() function, used to get a global string parameter from CoolProp
    LRESULT  CP_get_global_param_string(
                            LPMCSTRING ParamValue,   // output (value of parameter)
                            LPCMCSTRING ParamName )  // name of parameter (string) to retrieve
    {
        // Invoke the std::string form of get_global_param_string() function, save result to a new string s
        std::string s = CoolProp::get_global_param_string(ParamName->str);
        char * c = new char [s.size()+1]; // creat a c-string (pointer) c with the same size as s
        // copy s into c, this process avoids the const-cast type which would result from instead
        // converting the string using s.c_str()
        std::copy(s.begin(), s.end(), c);
        c[s.size()] = '\0';
        // assign the string to the function's output parameter
        ParamValue->str = c;

        // normal return
        return 0;
    }

    // this code executes the user function CP_get_fluid_param_string, which is a wrapper for
    // the CoolProp.get_fluid_param_string() function, used to get a fluid string parameter from CoolProp
    LRESULT  CP_get_fluid_param_string(
                            LPMCSTRING ParamValue,   // output (value of parameter)
                            LPCMCSTRING FluidName,  // name of fluidr (string) to retrieve
                            LPCMCSTRING ParamName )  // name of parameter (string) to retrieve
    {
        // Invoke the std::string form of get_fluid_param_string() function, save result to a new string s
        std::string s = CoolProp::get_fluid_param_string(FluidName->str, ParamName->str);
        char * c = new char [s.size()+1]; // creat a c-string (pointer) c with the same size as s
        // copy s into c, this process avoids the const-cast type which would result from instead
        // converting the string using s.c_str()
        std::copy(s.begin(), s.end(), c);
        c[s.size()] = '\0';
        // assign the string to the function's output parameter
        ParamValue->str = c;

        // normal return
        return 0;
    }

    // this code executes the user function CP_set_reference_state, which is a wrapper for
    // the CoolProp.set_reference_stateS() function, used to set the H/S reference states
    // based on a standard state string of "IIR", "ASHRAE", "NBP", or "DEF".
    LRESULT  CP_set_reference_state(
                            LPCOMPLEXSCALAR  Conf,     // output (dummy value)
                            LPCMCSTRING FluidName,     // name of fluidr (string) to retrieve
                            LPCMCSTRING StateStr )     // name of standard state (string) to set
    {
        // Invoke the set_reference_stateS() function, no result from this void function.
        CoolProp::set_reference_stateS(FluidName->str, StateStr->str);
        // assign the dummy return value
        Conf->real = 0;

        // normal return
        return 0;
    }

    // this code executes the user function CP_Props1SI, which is a wrapper for
    // the CoolProp.PropsSI() function, used to simply extract a
    // fluid-specific parameter that is not dependent on the state
    LRESULT  CP_Props1SI(
                            LPCOMPLEXSCALAR Prop,   // pointer to the result
                            LPCMCSTRING Fluid,      // string with a valid CoolProp fluid name
                            LPCMCSTRING PropName )  // a fluid property
    {
        // pass the arguments to the CoolProp.Props1() function
        Prop->real = CoolProp::Props1SI(Fluid->str, PropName->str);

        // normal return
        return 0;
    }

    // this code executes the user function CP_PropsSI, which is a wrapper for
    // the CoolProp.PropsSI() function, used to extract a fluid-specific parameter that is dependent on the state
    LRESULT  CP_PropsSI(
                            LPCOMPLEXSCALAR  Prop,       // pointer to the result
                            LPCMCSTRING      OutputName, // string with a valid CoolProp OutputName
                            LPCMCSTRING      InputName1, // CoolProp InputName1
                            LPCCOMPLEXSCALAR InputProp1, // CoolProp InputProp1
                            LPCMCSTRING      InputName2, // CoolProp InputName2
                            LPCCOMPLEXSCALAR InputProp2, // CoolProp InputProp2
                            LPCMCSTRING      FluidName ) // CoolProp Fluid
    {
        // check that the first scalar argument is real
        if (InputProp1->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 3);    // if not, display "Argument must be real" under scalar argument

        // check that the second scalar argument is real
        if (InputProp2->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 6);    // if not, display "Argument must be real" under scalar argument

        // pass the arguments to the CoolProp.Props() function
        Prop->real = CoolProp::PropsSI(OutputName->str, InputName1->str, InputProp1->real, InputName2->str, InputProp2->real, FluidName->str);

        // normal return
        return 0;
    }

    // this code executes the user function CP_HAPropsSI, which is a wrapper for
    // the CoolProp.HAPropsSI() function, used to extract humid air properties in base-SI units
    LRESULT  CP_HAPropsSI(
                            LPCOMPLEXSCALAR    Prop,       // pointer to the result
                            LPCMCSTRING        OutputName, // string with a valid CoolProp Output Name
                            LPCMCSTRING        InputName1, // CoolProp InputName1
                            LPCCOMPLEXSCALAR   InputProp1, // CoolProp InputProp1
                            LPCMCSTRING        InputName2, // CoolProp InputName2
                            LPCCOMPLEXSCALAR   InputProp2, // CoolProp InputProp2
                            LPCMCSTRING        InputName3, // CoolProp InputName3
                            LPCCOMPLEXSCALAR   InputProp3) // CoolProp InputProp3
    {
        // check that the first scalar argument is real
        if (InputProp1->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 3);  // if not, display "must be real" under scalar argument

        // check that the second scalar argument is real
        if (InputProp2->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 5);  // if not, display "must be real" under scalar argument

        // check that the third scalar argument is real
        if (InputProp3->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 7);  // if not, display "must be real" under scalar argument

        // pass the arguments to the HumidAirProp.HAProps() function
        Prop->real = HumidAir::HAPropsSI(OutputName->str, InputName1->str, InputProp1->real, InputName2->str, InputProp2->real, InputName3->str, InputProp3->real);

        // normal return
        return 0;
    }

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO PropsParam =
    {
    "get_global_param_string", // Name by which MathCAD will recognize the function
    "Name of the parameter to retrieve", // Description of input parameters
    "Returns the value of the requested CoolProps parameter", // description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_get_global_param_string, // Pointer to the function code.
    MC_STRING, // Returns a MathCAD string
    1, // Number of arguments
    {MC_STRING} // Argument types
    };

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO FluidParam =
    {
    "get_fluid_param_string", // Name by which MathCAD will recognize the function
    "Fluid, Name of the parameter to retrieve", // Description of input parameters
    "Returns the value of the requested CoolProps parameter", // description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_get_fluid_param_string, // Pointer to the function code.
    MC_STRING, // Returns a MathCAD string
    2, // Number of arguments
    {MC_STRING, MC_STRING} // Argument types
    };

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO RefState =
    {
    "set_reference_state", // Name by which MathCAD will recognize the function
    "Fluid, Reference State String", // Description of input parameters
    "Sets the reference state to either IIR, ASHRAE, NBP, or DEF.", // description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_set_reference_state, // Pointer to the function code.
    COMPLEX_SCALAR, // Returns a MathCAD complex scalar
    2, // Number of arguments
    {MC_STRING, MC_STRING} // Argument types
    };

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO Props1SI =
    {
    "Props1SI", // Name by which MathCAD will recognize the function
    "Fluid, Property Name", // Description of input parameters
    "Returns a fluid-specific parameter, where the parameter is not dependent on the fluid state", // Description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_Props1SI, // Pointer to the function code.
    COMPLEX_SCALAR, // Returns a MathCAD complex scalar
    2,    // Number of arguments
    {MC_STRING, MC_STRING}  // Argument types
    };

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO PropsSI =
    {
    "PropsSI", // Name by which MathCAD will recognize the function
    "Output Name, Input Name 1, Input Property 1, Input Name 2, Input Property 2, Fluid Name", // Description of input parameters
    "Returns a fluid-specific parameter, where the parameter is dependent on the fluid state", // Description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_PropsSI,  // Pointer to the function code.
    COMPLEX_SCALAR, // Returns a MathCAD complex scalar
    6, // Number of arguments
    {MC_STRING, MC_STRING, COMPLEX_SCALAR, MC_STRING, COMPLEX_SCALAR, MC_STRING} // Argument types
    };

    FUNCTIONINFO HAPropsSI =
    {
    "HAPropsSI",  // Name by which MathCAD will recognize the function
    "Output Name, Input Name 1, Input Property 1, Input Name 2, Input Property 2, Input Name 3, Input Property 3",  // Description of input parameters
    "Returns a parameter of humid air, where the parameter is dependent on the fluid state", // Description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_HAPropsSI,  // Pointer to the function code.
    COMPLEX_SCALAR, // Returns a MathCAD complex scalar
    7,  // Number of arguments
    {MC_STRING, MC_STRING, COMPLEX_SCALAR, MC_STRING, COMPLEX_SCALAR, MC_STRING, COMPLEX_SCALAR} // Argument types
    };

    // ************************************************************************************
    // DLL entry point code.
    // ************************************************************************************
    // The _CRT_INIT function is needed if you are using Microsoft's 32 bit compiler
#ifdef _WIN32
    extern "C" BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved);
#endif

    extern "C" BOOL WINAPI  DllEntryPoint (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
    {
        switch (dwReason)
        {
                case DLL_PROCESS_ATTACH:
                    //
                    // DLL is attaching to the address space of
                    // the current process.
                    //
                    if (!_CRT_INIT(hDLL, dwReason, lpReserved))
                        return FALSE;

                    // register the error message table
                    // Note, that if your function never returns
                    // an error -- you do not need to
                    // register an error message table
                    if ( !CreateUserErrorMessageTable( hDLL, NUMBER_OF_ERRORS, myErrorMessageTable ) )
                        break;

                    // and if the errors register OK
                    // go ahead and
                    // register user function
                    CreateUserFunction( hDLL, &PropsParam);
                    CreateUserFunction( hDLL, &FluidParam);
                    CreateUserFunction( hDLL, &RefState);
                    CreateUserFunction( hDLL, &Props1SI );
                    CreateUserFunction( hDLL, &PropsSI );
                    CreateUserFunction( hDLL, &HAPropsSI );
                    break;

                case DLL_THREAD_ATTACH:
                case DLL_THREAD_DETACH:
                case DLL_PROCESS_DETACH:

                    if (!_CRT_INIT(hDLL, dwReason, lpReserved))
                    {
                        Sleep(1000);   // Attempt to keep CRT_INIT from detaching before all threads are closed
                        return FALSE;
                    }
                    break;
        }
        return TRUE;
    }

<commit_msg>Another try at MathCAD<commit_after>// CoolPropMathcad.cpp : Defines the exported functions for the DLL Add-in.
//

#include <string>

#ifndef NOMINMAX // Kill windows' horrible min() and max() macros
#define NOMINMAX
#endif
#include "mcadincl.h"
#undef NOMINMAX;

enum { MC_STRING = STRING };  // substitute enumeration variable MC_STRING for STRING, use MC_STRING below
#undef STRING                 // undefine STRING as it conflicts with STRING enum in cppformat/format.h

#include "CoolProp.h"
#include "HumidAirProp.h"

enum EC { INTERRUPTED, INSUFFICIENT_MEMORY, MUST_BE_REAL, NUMBER_OF_ERRORS = MUST_BE_REAL };   // Mathcad Error Codes

    // table of error messages
    // if user function never returns an
    // error -- you do not need to create this
    // table
    char * myErrorMessageTable[NUMBER_OF_ERRORS] =
    {
        "Interrupted"
        "Insufficient Memory"
        "Argument must be real"
    };

    // this code executes the user function CP_get_global_param_string, which is a wrapper for
    // the CoolProp.get_global_param_string() function, used to get a global string parameter from CoolProp
    LRESULT  CP_get_global_param_string(
                            LPMCSTRING ParamValue,   // output (value of parameter)
                            LPCMCSTRING ParamName )  // name of parameter (string) to retrieve
    {
        // Invoke the std::string form of get_global_param_string() function, save result to a new string s
        std::string s = CoolProp::get_global_param_string(ParamName->str);
        char * c = new char [s.size()+1]; // creat a c-string (pointer) c with the same size as s
        // copy s into c, this process avoids the const-cast type which would result from instead
        // converting the string using s.c_str()
        std::copy(s.begin(), s.end(), c);
        c[s.size()] = '\0';
        // assign the string to the function's output parameter
        ParamValue->str = c;

        // normal return
        return 0;
    }

    // this code executes the user function CP_get_fluid_param_string, which is a wrapper for
    // the CoolProp.get_fluid_param_string() function, used to get a fluid string parameter from CoolProp
    LRESULT  CP_get_fluid_param_string(
                            LPMCSTRING ParamValue,   // output (value of parameter)
                            LPCMCSTRING FluidName,  // name of fluidr (string) to retrieve
                            LPCMCSTRING ParamName )  // name of parameter (string) to retrieve
    {
        // Invoke the std::string form of get_fluid_param_string() function, save result to a new string s
        std::string s = CoolProp::get_fluid_param_string(FluidName->str, ParamName->str);
        char * c = new char [s.size()+1]; // creat a c-string (pointer) c with the same size as s
        // copy s into c, this process avoids the const-cast type which would result from instead
        // converting the string using s.c_str()
        std::copy(s.begin(), s.end(), c);
        c[s.size()] = '\0';
        // assign the string to the function's output parameter
        ParamValue->str = c;

        // normal return
        return 0;
    }

    // this code executes the user function CP_set_reference_state, which is a wrapper for
    // the CoolProp.set_reference_stateS() function, used to set the H/S reference states
    // based on a standard state string of "IIR", "ASHRAE", "NBP", or "DEF".
    LRESULT  CP_set_reference_state(
                            LPCOMPLEXSCALAR  Conf,     // output (dummy value)
                            LPCMCSTRING FluidName,     // name of fluidr (string) to retrieve
                            LPCMCSTRING StateStr )     // name of standard state (string) to set
    {
        // Invoke the set_reference_stateS() function, no result from this void function.
        CoolProp::set_reference_stateS(FluidName->str, StateStr->str);
        // assign the dummy return value
        Conf->real = 0;

        // normal return
        return 0;
    }

    // this code executes the user function CP_Props1SI, which is a wrapper for
    // the CoolProp.PropsSI() function, used to simply extract a
    // fluid-specific parameter that is not dependent on the state
    LRESULT  CP_Props1SI(
                            LPCOMPLEXSCALAR Prop,   // pointer to the result
                            LPCMCSTRING Fluid,      // string with a valid CoolProp fluid name
                            LPCMCSTRING PropName )  // a fluid property
    {
        // pass the arguments to the CoolProp.Props1() function
        Prop->real = CoolProp::Props1SI(Fluid->str, PropName->str);

        // normal return
        return 0;
    }

    // this code executes the user function CP_PropsSI, which is a wrapper for
    // the CoolProp.PropsSI() function, used to extract a fluid-specific parameter that is dependent on the state
    LRESULT  CP_PropsSI(
                            LPCOMPLEXSCALAR  Prop,       // pointer to the result
                            LPCMCSTRING      OutputName, // string with a valid CoolProp OutputName
                            LPCMCSTRING      InputName1, // CoolProp InputName1
                            LPCCOMPLEXSCALAR InputProp1, // CoolProp InputProp1
                            LPCMCSTRING      InputName2, // CoolProp InputName2
                            LPCCOMPLEXSCALAR InputProp2, // CoolProp InputProp2
                            LPCMCSTRING      FluidName ) // CoolProp Fluid
    {
        // check that the first scalar argument is real
        if (InputProp1->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 3);    // if not, display "Argument must be real" under scalar argument

        // check that the second scalar argument is real
        if (InputProp2->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 6);    // if not, display "Argument must be real" under scalar argument

        // pass the arguments to the CoolProp.Props() function
        Prop->real = CoolProp::PropsSI(OutputName->str, InputName1->str, InputProp1->real, InputName2->str, InputProp2->real, FluidName->str);

        // normal return
        return 0;
    }

    // this code executes the user function CP_HAPropsSI, which is a wrapper for
    // the CoolProp.HAPropsSI() function, used to extract humid air properties in base-SI units
    LRESULT  CP_HAPropsSI(
                            LPCOMPLEXSCALAR    Prop,       // pointer to the result
                            LPCMCSTRING        OutputName, // string with a valid CoolProp Output Name
                            LPCMCSTRING        InputName1, // CoolProp InputName1
                            LPCCOMPLEXSCALAR   InputProp1, // CoolProp InputProp1
                            LPCMCSTRING        InputName2, // CoolProp InputName2
                            LPCCOMPLEXSCALAR   InputProp2, // CoolProp InputProp2
                            LPCMCSTRING        InputName3, // CoolProp InputName3
                            LPCCOMPLEXSCALAR   InputProp3) // CoolProp InputProp3
    {
        // check that the first scalar argument is real
        if (InputProp1->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 3);  // if not, display "must be real" under scalar argument

        // check that the second scalar argument is real
        if (InputProp2->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 5);  // if not, display "must be real" under scalar argument

        // check that the third scalar argument is real
        if (InputProp3->imag != 0.0)
            return MAKELRESULT( MUST_BE_REAL, 7);  // if not, display "must be real" under scalar argument

        // pass the arguments to the HumidAirProp.HAProps() function
        Prop->real = HumidAir::HAPropsSI(OutputName->str, InputName1->str, InputProp1->real, InputName2->str, InputProp2->real, InputName3->str, InputProp3->real);

        // normal return
        return 0;
    }

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO PropsParam =
    {
    "get_global_param_string", // Name by which MathCAD will recognize the function
    "Name of the parameter to retrieve", // Description of input parameters
    "Returns the value of the requested CoolProps parameter", // description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_get_global_param_string, // Pointer to the function code.
    MC_STRING, // Returns a MathCAD string
    1, // Number of arguments
    {MC_STRING} // Argument types
    };

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO FluidParam =
    {
    "get_fluid_param_string", // Name by which MathCAD will recognize the function
    "Fluid, Name of the parameter to retrieve", // Description of input parameters
    "Returns the value of the requested CoolProps parameter", // description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_get_fluid_param_string, // Pointer to the function code.
    MC_STRING, // Returns a MathCAD string
    2, // Number of arguments
    {MC_STRING, MC_STRING} // Argument types
    };

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO RefState =
    {
    "set_reference_state", // Name by which MathCAD will recognize the function
    "Fluid, Reference State String", // Description of input parameters
    "Sets the reference state to either IIR, ASHRAE, NBP, or DEF.", // description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_set_reference_state, // Pointer to the function code.
    COMPLEX_SCALAR, // Returns a MathCAD complex scalar
    2, // Number of arguments
    {MC_STRING, MC_STRING} // Argument types
    };

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO Props1SI =
    {
    "Props1SI", // Name by which MathCAD will recognize the function
    "Fluid, Property Name", // Description of input parameters
    "Returns a fluid-specific parameter, where the parameter is not dependent on the fluid state", // Description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_Props1SI, // Pointer to the function code.
    COMPLEX_SCALAR, // Returns a MathCAD complex scalar
    2,    // Number of arguments
    {MC_STRING, MC_STRING}  // Argument types
    };

    // fill out a FUNCTIONINFO structure with the information needed for registering the function with Mathcad
    FUNCTIONINFO PropsSI =
    {
    "PropsSI", // Name by which MathCAD will recognize the function
    "Output Name, Input Name 1, Input Property 1, Input Name 2, Input Property 2, Fluid Name", // Description of input parameters
    "Returns a fluid-specific parameter, where the parameter is dependent on the fluid state", // Description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_PropsSI,  // Pointer to the function code.
    COMPLEX_SCALAR, // Returns a MathCAD complex scalar
    6, // Number of arguments
    {MC_STRING, MC_STRING, COMPLEX_SCALAR, MC_STRING, COMPLEX_SCALAR, MC_STRING} // Argument types
    };

    FUNCTIONINFO HAPropsSI =
    {
    "HAPropsSI",  // Name by which MathCAD will recognize the function
    "Output Name, Input Name 1, Input Property 1, Input Name 2, Input Property 2, Input Name 3, Input Property 3",  // Description of input parameters
    "Returns a parameter of humid air, where the parameter is dependent on the fluid state", // Description of the function for the Insert Function dialog box
    (LPCFUNCTION)CP_HAPropsSI,  // Pointer to the function code.
    COMPLEX_SCALAR, // Returns a MathCAD complex scalar
    7,  // Number of arguments
    {MC_STRING, MC_STRING, COMPLEX_SCALAR, MC_STRING, COMPLEX_SCALAR, MC_STRING, COMPLEX_SCALAR} // Argument types
    };

    // ************************************************************************************
    // DLL entry point code.
    // ************************************************************************************
    // The _CRT_INIT function is needed if you are using Microsoft's 32 bit compiler
#ifdef _WIN32
    extern "C" BOOL WINAPI _CRT_INIT(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved);
#endif

    extern "C" BOOL WINAPI  DllEntryPoint (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
    {
        switch (dwReason)
        {
                case DLL_PROCESS_ATTACH:
                    //
                    // DLL is attaching to the address space of
                    // the current process.
                    //
                    if (!_CRT_INIT(hDLL, dwReason, lpReserved))
                        return FALSE;

                    // register the error message table
                    // Note, that if your function never returns
                    // an error -- you do not need to
                    // register an error message table
                    if ( !CreateUserErrorMessageTable( hDLL, NUMBER_OF_ERRORS, myErrorMessageTable ) )
                        break;

                    // and if the errors register OK
                    // go ahead and
                    // register user function
                    CreateUserFunction( hDLL, &PropsParam);
                    CreateUserFunction( hDLL, &FluidParam);
                    CreateUserFunction( hDLL, &RefState);
                    CreateUserFunction( hDLL, &Props1SI );
                    CreateUserFunction( hDLL, &PropsSI );
                    CreateUserFunction( hDLL, &HAPropsSI );
                    break;

                case DLL_THREAD_ATTACH:
                case DLL_THREAD_DETACH:
                case DLL_PROCESS_DETACH:

                    if (!_CRT_INIT(hDLL, dwReason, lpReserved))
                    {
                        Sleep(1000);   // Attempt to keep CRT_INIT from detaching before all threads are closed
                        return FALSE;
                    }
                    break;
        }
        return TRUE;
    }

<|endoftext|>


<commit_before>/*
 * ====================================================================
 * Copyright (c) 2002-2005 The RapidSvn Group.  All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library (in the file LGPL.txt); if not,
 * write to the Free Software Foundation, Inc., 51 Franklin St,
 * Fifth Floor, Boston, MA  02110-1301  USA
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://rapidsvn.tigris.org/.
 * ====================================================================
 */
#if defined( _MSC_VER) && _MSC_VER <= 1200
#pragma warning( disable: 4786 )// debug symbol truncated
#endif
// svncpp
#include "client_impl.hpp"

// Subversion api
#include "svn_client.h"
//#include "svn_io.h"

#include "exception.hpp"
#include "pool.hpp"
#include "status.hpp"
#include "svncpp_defines.hpp"

namespace svn
{
  QByteArray
  Client_impl::cat(const Path & path,
                const Revision & revision,
                const Revision & peg_revision) throw (ClientException)
  {
    Pool pool;

    svn_stringbuf_t * stringbuf = svn_stringbuf_create ("", pool);
    svn_stream_t * stream = svn_stream_from_stringbuf (stringbuf, pool);

    svn_error_t * error;
    error = svn_client_cat2 (stream,
                             path.path().TOUTF8(),
                             peg_revision.revision (),
                             revision.revision (),
                             *m_context,
                             pool);

    if (error != 0)
      throw ClientException (error);
#if QT_VERSION < 0x040000
    QByteArray res;
    /// @todo check if realy dup or just assign!
    res.duplicate(stringbuf->data,stringbuf->len);
#else
    QByteArray res( stringbuf->data, stringbuf->len );
#endif
    return res;
  }

  /**
   * Create a new temporary file in @a dstPath. If @a dstPath
   * is empty (""), then construct the temporary filename
   * from the temporary directory and the filename component
   * of @a path. The file-extension of @a path will be transformed
   * to @a dstPath and @a dstPath will be a unique filename
   *
   * @param dstPath path to temporary file. Will be constructed
   *                from @a path and temporary dir (and unique elements)
   *                if empty string
   * @param path existing filename. Necessary only for construction
   *             of @a dstPath
   * @param pool pool to use
   * @return open file
   */
  static apr_file_t *
  openTempFile (Path & dstPath, const Path & path,
                const Revision & revision, Pool & pool)
    throw (ClientException)
  {
    apr_file_t * file = 0;

    if (dstPath.length () > 0)
    {
      apr_status_t status =
        apr_file_open (&file,
                       dstPath.path().TOUTF8(),
                       APR_WRITE | APR_CREATE |
                       APR_TRUNCATE | APR_BINARY,
                       APR_OS_DEFAULT,
                       pool);
      if (status != 0)
        throw ClientException (status);
    }
    else
    {
      // split the path into its components
      QString dir, filename, ext;
      path.split (dir, filename, ext);

      // add the revision number to the filename
      char revstring[20];
      if (revision.kind () == revision.HEAD)
        strcpy (revstring, "HEAD");
      else
        sprintf (revstring, "%" SVN_REVNUM_T_FMT, revision.revnum ());
      filename += "-";
      filename += revstring;

      // replace the dir component with tempdir
      Path tempPath = Path::getTempDir ();
      tempPath.addComponent (filename);

      const char * unique_name;
      svn_error_t * error =
        svn_io_open_unique_file (
          &file, &unique_name,
          tempPath.path().TOUTF8(), // path
          ext.TOUTF8(), // suffix
          0, // dont delete on close
          pool);

      if (error != 0)
        throw ClientException (error);

      dstPath = unique_name;
    }

    return file;
  }

  void
  Client_impl::get (Path & dstPath,
               const Path & path,
               const Revision & revision) throw (ClientException)
  {
    Pool pool;

    // create a new file and suppose we only want
    // this users to be able to read and write the file

    apr_file_t * file = openTempFile (dstPath, path, revision, pool);

    // now create a stream and let svn_client_cat write to the
    // stream
    svn_stream_t * stream = svn_stream_from_aprfile (file, pool);
    if (stream != 0)
    {
      svn_error_t * error = svn_client_cat (
        stream,
        path.path().TOUTF8(),
        revision.revision (),
        *m_context, pool);
      if (error != 0)
        throw ClientException (error);

      svn_stream_close (stream);
    }

    // finalize stuff
    apr_file_close (file);
  }
}

/* -----------------------------------------------------------------
 * local variables:
 * eval: (load-file "../../rapidsvn-dev.el")
 * end:
 */
<commit_msg>removed a uncontrolled sprintf into a char-array (I hate possible buffer overflows)<commit_after>/*
 * ====================================================================
 * Copyright (c) 2002-2005 The RapidSvn Group.  All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library (in the file LGPL.txt); if not,
 * write to the Free Software Foundation, Inc., 51 Franklin St,
 * Fifth Floor, Boston, MA  02110-1301  USA
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://rapidsvn.tigris.org/.
 * ====================================================================
 */
#if defined( _MSC_VER) && _MSC_VER <= 1200
#pragma warning( disable: 4786 )// debug symbol truncated
#endif
// svncpp
#include "client_impl.hpp"

// Subversion api
#include "svn_client.h"
//#include "svn_io.h"

#include "exception.hpp"
#include "pool.hpp"
#include "status.hpp"
#include "svncpp_defines.hpp"

namespace svn
{
  QByteArray
  Client_impl::cat(const Path & path,
                const Revision & revision,
                const Revision & peg_revision) throw (ClientException)
  {
    Pool pool;

    svn_stringbuf_t * stringbuf = svn_stringbuf_create ("", pool);
    svn_stream_t * stream = svn_stream_from_stringbuf (stringbuf, pool);

    svn_error_t * error;
    error = svn_client_cat2 (stream,
                             path.path().TOUTF8(),
                             peg_revision.revision (),
                             revision.revision (),
                             *m_context,
                             pool);

    if (error != 0)
      throw ClientException (error);
#if QT_VERSION < 0x040000
    QByteArray res;
    /// @todo check if realy dup or just assign!
    res.duplicate(stringbuf->data,stringbuf->len);
#else
    QByteArray res( stringbuf->data, stringbuf->len );
#endif
    return res;
  }

  /**
   * Create a new temporary file in @a dstPath. If @a dstPath
   * is empty (""), then construct the temporary filename
   * from the temporary directory and the filename component
   * of @a path. The file-extension of @a path will be transformed
   * to @a dstPath and @a dstPath will be a unique filename
   *
   * @param dstPath path to temporary file. Will be constructed
   *                from @a path and temporary dir (and unique elements)
   *                if empty string
   * @param path existing filename. Necessary only for construction
   *             of @a dstPath
   * @param pool pool to use
   * @return open file
   */
  static apr_file_t *
  openTempFile (Path & dstPath, const Path & path,
                const Revision & revision, Pool & pool)
    throw (ClientException)
  {
    apr_file_t * file = 0;

    if (dstPath.length () > 0)
    {
      apr_status_t status =
        apr_file_open (&file,
                       dstPath.path().TOUTF8(),
                       APR_WRITE | APR_CREATE |
                       APR_TRUNCATE | APR_BINARY,
                       APR_OS_DEFAULT,
                       pool);
      if (status != 0)
        throw ClientException (status);
    }
    else
    {
      // split the path into its components
      QString dir, filename, ext;
      path.split (dir, filename, ext);

      // add the revision number to the filename
      QString revstring;
      if (revision.kind () == revision.HEAD)
        revstring="HEAD";
      else
        revstring.sprintf("%"SVN_REVNUM_T_FMT,revision.revnum ());
      filename += "-";
      filename += revstring;

      // replace the dir component with tempdir
      Path tempPath = Path::getTempDir ();
      tempPath.addComponent (filename);

      const char * unique_name;
      svn_error_t * error =
        svn_io_open_unique_file (
          &file, &unique_name,
          tempPath.path().TOUTF8(), // path
          ext.TOUTF8(), // suffix
          0, // dont delete on close
          pool);

      if (error != 0)
        throw ClientException (error);

      dstPath = unique_name;
    }

    return file;
  }

  void
  Client_impl::get (Path & dstPath,
               const Path & path,
               const Revision & revision) throw (ClientException)
  {
    Pool pool;

    // create a new file and suppose we only want
    // this users to be able to read and write the file

    apr_file_t * file = openTempFile (dstPath, path, revision, pool);

    // now create a stream and let svn_client_cat write to the
    // stream
    svn_stream_t * stream = svn_stream_from_aprfile (file, pool);
    if (stream != 0)
    {
      svn_error_t * error = svn_client_cat (
        stream,
        path.path().TOUTF8(),
        revision.revision (),
        *m_context, pool);
      if (error != 0)
        throw ClientException (error);

      svn_stream_close (stream);
    }

    // finalize stuff
    apr_file_close (file);
  }
}

/* -----------------------------------------------------------------
 * local variables:
 * eval: (load-file "../../rapidsvn-dev.el")
 * end:
 */
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS pchfix02 (1.7.36); FILE MERGED 2006/09/01 17:24:10 kaib 1.7.36.1: #i68856# Added header markers and pch files<commit_after><|endoftext|>


<commit_before>#include "xchainer/native/native_device.h"

#include <cassert>
#include <cstdint>

#include "xchainer/array.h"
#include "xchainer/device.h"
#include "xchainer/dtype.h"
#include "xchainer/indexable_array.h"
#include "xchainer/native/elementwise.h"
#include "xchainer/shape.h"

namespace xchainer {
namespace native {

namespace {

void DotCheckNdim(int8_t ndim) {
    // TODO(sonots): Support ndim >= 2
    if (ndim != 2) {
        throw DimensionError{"XChainer dot supports only 2-dimensional arrays."};
    }
}

}  // namespace
void NativeDevice::Dot(const Array& a, const Array& b, const Array& out) {
    CheckDevicesCompatible(a, b, out);
    VisitDtype(out.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;
        IndexableArray<const T> a_iarray{a};
        IndexableArray<const T> b_iarray{b};
        IndexableArray<T> out_iarray{out};

        // We have to check iarray ndim, otherwise clang-tidy fails bound-checking.
        DotCheckNdim(a_iarray.ndim());
        DotCheckNdim(b_iarray.ndim());
        DotCheckNdim(out_iarray.ndim());

        int64_t m = a.shape()[0];
        int64_t k = a.shape()[1];
        int64_t n = b.shape()[1];
        assert(b.shape()[0] == k);
        assert(out.shape()[0] == m);
        assert(out.shape()[1] == n);

        // TODO(beam2d): Use BLAS.
        for (int64_t i = 0; i < m; ++i) {
            for (int64_t j = 0; j < n; ++j) {
                int64_t out_i[] = {i, j};
                T& out_value = out_iarray[out_i];
                out_value = 0;
                for (int64_t l = 0; l < k; ++l) {
                    int64_t a_i[] = {i, l};
                    int64_t b_i[] = {l, j};
                    out_value += a_iarray[a_i] * b_iarray[b_i];
                }
            }
        }
    });
}

}  // namespace native
}  // namespace xchainer
<commit_msg>Improve performance of Native Dot<commit_after>#include "xchainer/native/native_device.h"

#include <cassert>
#include <cstdint>

#include "xchainer/array.h"
#include "xchainer/device.h"
#include "xchainer/dtype.h"
#include "xchainer/indexable_array.h"
#include "xchainer/native/elementwise.h"
#include "xchainer/shape.h"

namespace xchainer {
namespace native {

namespace {

void DotCheckNdim(int8_t ndim) {
    // TODO(sonots): Support ndim >= 2
    if (ndim != 2) {
        throw DimensionError{"XChainer dot supports only 2-dimensional arrays."};
    }
}

}  // namespace
void NativeDevice::Dot(const Array& a, const Array& b, const Array& out) {
    CheckDevicesCompatible(a, b, out);
    out.Fill(0);
    VisitDtype(out.dtype(), [&](auto pt) {
        using T = typename decltype(pt)::type;
        IndexableArray<const T> a_iarray{a};
        IndexableArray<const T> b_iarray{b};
        IndexableArray<T> out_iarray{out};

        // We have to check iarray ndim, otherwise clang-tidy fails bound-checking.
        DotCheckNdim(a_iarray.ndim());
        DotCheckNdim(b_iarray.ndim());
        DotCheckNdim(out_iarray.ndim());

        int64_t m = a.shape()[0];
        int64_t k = a.shape()[1];
        int64_t n = b.shape()[1];
        assert(b.shape()[0] == k);
        assert(out.shape()[0] == m);
        assert(out.shape()[1] == n);

        // TODO(beam2d): Use BLAS.
        for (int64_t i = 0; i < m; ++i) {
            for (int64_t l = 0; l < k; ++l) {
                int64_t a_i_l[] = {i, l};
                T a_value = a_iarray[a_i_l];
                for (int64_t j = 0; j < n; ++j) {
                    int64_t out_i_j[] = {i, j};
                    int64_t b_l_j[] = {l, j};
                    out_iarray[out_i_j] += a_value * b_iarray[b_l_j];
                }
            }
        }
    });
}

}  // namespace native
}  // namespace xchainer
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- test modules used --------------------------------------------------------
#include "TestSuite.h"

//--- module under test --------------------------------------------------------
#include "ITOStorage.h"

//--- interface include --------------------------------------------------------
#include "StorageTest.h"

//--- standard modules used ----------------------------------------------------
#include "Anything.h"
#include "DiffTimer.h"
#include "PoolAllocator.h"

//--- c-library modules used ---------------------------------------------------

//---- StorageTest ----------------------------------------------------------------
StorageTest::StorageTest(TString tname) : TestCaseType(tname)
{
}

StorageTest::~StorageTest()
{
}

void StorageTest::SimpleCallocSetsToZeroTest()
{
	GlobalAllocator ga;
	const long sz = 3000;
	char *ptr[sz];
	long i = 0;
	for ( i = 0 ; i < sz ; i++ ) {
		ptr[i] = (char *)ga.Malloc(i + 1); // add one otherwise we do not alloc something in the first step
		*ptr[i] = '\xA5';
		assertEqual('\xA5', *ptr[i]);
	}
	for ( i = 0 ; i < sz ; i++ ) {
		ga.Free(ptr[i]);
	}
	for ( i = 0 ; i < sz ; i++ ) {
		ptr[i] = (char *)ga.Calloc(i + 1, 1); // add one otherwise we do not alloc something in the first step
		TString msg("i = ");
		msg << i;
		assertEqualm((long)'\0', (long)*ptr[i], msg);
	}
	for ( i = 0 ; i < sz ; i++ ) {
		ga.Free(ptr[i]);
	}
}

void StorageTest::LeakTest()
{
	// watch the sequence of declaration
	MemChecker mc("Test Global", Storage::Global());
	String str;
	{
		StartTraceMem(StorageTest.LeakTest);
		str = "Test a leak";
	}
	//PS: we now have a different measurement
	//assertEqual(12, mc.CheckDelta());
	t_assertm(mc.CheckDelta() >= 12, "memory leaked as expected");
}

void StorageTest::SimpleAllocTest(TString allocatorName, Allocator *pAllocator)
{
	MemChecker mc(allocatorName, pAllocator);
	const long sz = 3000;
	char *ptr[sz];
	long i = 0;
	for ( i = 0 ; i < sz ; i++ ) {
		ptr[i] = (char *)pAllocator->Malloc(i);
	}
	assertEqual(4498500, mc.CheckDelta());
	for ( i = 0 ; i < sz ; i++ ) {
		pAllocator->Free(ptr[i]);
	}
	pAllocator->PrintStatistic();
	assertEqual(0, mc.CheckDelta());
}
void StorageTest::SimpleSizeHintTest(TString allocatorName, Allocator *pAllocator)
{
	const size_t sz = 3000;
	size_t i = 0;
	for ( i = 0 ; i < sz ; i++ ) {
		t_assert(pAllocator->SizeHint(i) >= i);
	}
}

void StorageTest::PoolSizeHintTest()
{
	PoolAllocator pa(1, 1024, 9);
	SimpleSizeHintTest("PoolAllocator", &pa);
	const size_t maxbucketsize = 0x2000;
	// test some significant values
	// must be adjusted if implementation of pool allocator is changed

	const u_long lMinimumSize = 16 + MemoryHeader::AlignedSize();
	assertEqual(lMinimumSize, pa.SizeHint(0));
	assertEqual(lMinimumSize, pa.SizeHint(1));
	assertEqual(lMinimumSize, pa.SizeHint(32));
	assertEqual(lMinimumSize << 1, pa.SizeHint(33));
	assertEqual(lMinimumSize << 1, pa.SizeHint(64));
	assertEqual(0x2000, pa.SizeHint(0x1fff));
	assertEqual(0x2fff, pa.SizeHint(0x2fff));
	{
		for (size_t s = 0, expected = lMinimumSize; s < 0x7fff; s += 8 ) {
			if (expected < s) {
				expected <<= 1;
			}
			if (expected <= maxbucketsize) {
				assertEqual(expected, pa.SizeHint(s));
			} else {
				assertEqual(s, pa.SizeHint(s));
			}
		}
	}
	{
		for (size_t s = 1, expected = lMinimumSize; s < 0x7fff; s += 8 ) {
			if (expected < s) {
				expected <<= 1;
			}
			if (expected <= maxbucketsize) {
				assertEqual(expected, pa.SizeHint(s));
			} else {
				assertEqual(s, pa.SizeHint(s));
			}
		}
	}
}

void StorageTest::AllocatorTest()
{
	GlobalAllocator ga;
	SimpleSizeHintTest("GlobalAllocator",  &ga);
	SimpleAllocTest("GlobalAllocator",  &ga);
}

void StorageTest::AllocatorTiming()
{
	PoolAllocator pa(1, 8 * 1024, 21);
	DoTimingWith("PoolAllocator", &pa);
	GlobalAllocator ga;
	DoTimingWith("GlobalAllocator", &ga);
}

void StorageTest::DoTimingWith(TString allocatorName, Allocator *pAllocator)
{
	{
		StartTraceMem1(StorageTest.DoTimingWith, pAllocator);
		MemChecker mc("StorageTest.DoTimingWith", pAllocator);
		const int cAllocSz = 5;
		long allocSzArr[cAllocSz];
		void *allocPtr[cAllocSz];
		long allocSz = 16;
		const int cRunSize = 10000;
		l_long t;
		long i;
		for (i = 0; i < cAllocSz; i++) {
			// generate some alloc sizes
			allocSzArr[i] = allocSz;
			allocSz *= 2;
		}

		DiffTimer dt;
		dt.Start();
		for ( long lrun = cRunSize - 1; lrun >= 0; lrun--) {
			if ( lrun < (cRunSize - cAllocSz) ) {
				pAllocator->Free(allocPtr[(lrun + cAllocSz) % cAllocSz]);
			}
			allocPtr[lrun % cAllocSz] = pAllocator->Malloc(allocSzArr[lrun % cAllocSz]);
		}
		for (i = 0; i < cAllocSz; i++) {
			pAllocator->Free(allocPtr[i]);
		}
		t = dt.Reset();
		pAllocator->PrintStatistic();
		assertEqual(0, mc.CheckDelta());
	}
}

void StorageTest::AnyStorageGlobalAssignment()
{
	// test assignment with Storage::Global
	Anything a;
	Anything b;

	t_assert(a.GetAllocator() == Storage::Global());
	t_assert(b.GetAllocator() == Storage::Global());

	a = b;
	t_assert(a.GetAllocator() == Storage::Global());
	t_assert(b.GetAllocator() == Storage::Global());

	b = 1;
	t_assert(b.GetAllocator() == Storage::Global());
	a = b;
	t_assert(a.GetAllocator() == Storage::Global());
	t_assert(b.GetAllocator() == Storage::Global());
}

void StorageTest::AnyEqualAllocatorAssignment()
{
	GlobalAllocator ga;
	Anything a(&ga);
	Anything b(&ga);

	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &ga);

	a = b;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &ga);

	b = 1;
	t_assert(b.GetAllocator() == &ga);
	a = b;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &ga);

}

void StorageTest::AnyEqualPoolAllocatorAssignment()
{
	PoolAllocator pa(100, 10);
	Anything a(&pa);
	Anything b(&pa);

	t_assert(a.GetAllocator() == &pa);
	t_assert(b.GetAllocator() == &pa);

	a = b;
	t_assert(a.GetAllocator() == &pa);
	t_assert(b.GetAllocator() == &pa);

	b = 1;
	t_assert(b.GetAllocator() == &pa);
	a = b;
	t_assert(a.GetAllocator() == &pa);
	t_assert(b.GetAllocator() == &pa);

}

void StorageTest::AnyDifferentAllocatorAssignment()
{
	GlobalAllocator ga;
	PoolAllocator pa(100, 10);
	Anything a(&ga);
	Anything b(&pa);

	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &pa);

	a = b;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &pa);

	b = 1;
	t_assert(b.GetAllocator() == &pa);

	a = b;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &pa);

	b = a;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &pa);
}

void StorageTest::AnyPathology()
{
	//try to force a null allocator with SetAllocator
	Anything a;
	t_assert(a.GetAllocator() == Storage::Global());
	t_assert(!a.SetAllocator(0));
	t_assert(a.GetAllocator() == Storage::Global());
	a = "what a fool";
	t_assert(Storage::Global() == a.GetAllocator());
	assertEqual("what a fool", a.AsCharPtr());

	//try to force a null allocator in constructor
	Anything a1((Allocator *)0);
	t_assert(a1.GetAllocator() == Storage::Global());
	a1 = "what a fool";
	t_assert(Storage::Global() == a1.GetAllocator());
	assertEqual("what a fool", a1.AsCharPtr());
}

void StorageTest::AnyAssignment()
{
	AnyStorageGlobalAssignment();
	AnyEqualAllocatorAssignment();
	AnyEqualPoolAllocatorAssignment();
	AnyDifferentAllocatorAssignment();
	AnyPathology();
}

Test *StorageTest::suite ()
{
	TestSuite *testSuite = new TestSuite;
	ADD_CASE(testSuite, StorageTest, PoolSizeHintTest);
	ADD_CASE(testSuite, StorageTest, SimpleCallocSetsToZeroTest);
	ADD_CASE(testSuite, StorageTest, AllocatorTest);
	ADD_CASE(testSuite, StorageTest, AllocatorTiming);
	ADD_CASE(testSuite, StorageTest, LeakTest);
	ADD_CASE(testSuite, StorageTest, AnyAssignment);
	return testSuite;
}
<commit_msg>adjusted tests which use MemTracker specific knowledge  - some of them work only if TRACE_STORAGE is set to a certain level<commit_after>/*
 * Copyright (c) 2005, Peter Sommerlad and IFS Institute for Software at HSR Rapperswil, Switzerland
 * All rights reserved.
 *
 * This library/application is free software; you can redistribute and/or modify it under the terms of
 * the license that is included with this library/application in the file license.txt.
 */

//--- test modules used --------------------------------------------------------
#include "TestSuite.h"

//--- module under test --------------------------------------------------------
#include "ITOStorage.h"

//--- interface include --------------------------------------------------------
#include "StorageTest.h"

//--- standard modules used ----------------------------------------------------
#include "Anything.h"
#include "DiffTimer.h"
#include "PoolAllocator.h"

//--- c-library modules used ---------------------------------------------------

//---- StorageTest ----------------------------------------------------------------
StorageTest::StorageTest(TString tname) : TestCaseType(tname)
{
}

StorageTest::~StorageTest()
{
}

void StorageTest::SimpleCallocSetsToZeroTest()
{
	GlobalAllocator ga;
	const long sz = 3000;
	char *ptr[sz];
	long i = 0;
	for ( i = 0 ; i < sz ; i++ ) {
		ptr[i] = (char *)ga.Malloc(i + 1); // add one otherwise we do not alloc something in the first step
		*ptr[i] = '\xA5';
		assertEqual('\xA5', *ptr[i]);
	}
	for ( i = 0 ; i < sz ; i++ ) {
		ga.Free(ptr[i]);
	}
	for ( i = 0 ; i < sz ; i++ ) {
		ptr[i] = (char *)ga.Calloc(i + 1, 1); // add one otherwise we do not alloc something in the first step
		TString msg("i = ");
		msg << i;
		assertEqualm((long)'\0', (long)*ptr[i], msg);
	}
	for ( i = 0 ; i < sz ; i++ ) {
		ga.Free(ptr[i]);
	}
}

void StorageTest::LeakTest()
{
	// the current implementation allows size testing, eg. tracking of allocated and freed memory only in Storage::GetStatisticLevel() >= 1
	if ( Storage::GetStatisticLevel() >= 1 ) {
		// watch the sequence of declaration
		MemChecker mc("Test Global", Storage::Global());
		String str(Storage::Global());
		{
			StartTraceMem(StorageTest.LeakTest);
			str = "Test a leak by allocating some more memory than was reserved initially";
		}
		assertCompare(str.Length(), equal_to, 70L);
		//PS: we now have a different measurement
		//assertEqual(12, mc.CheckDelta());
		assertComparem(mc.CheckDelta(), greater_equal, 12LL, "memory leaked as expected");
	}
}

void StorageTest::SimpleAllocTest(TString allocatorName, Allocator *pAllocator)
{
	// the current implementation allows size testing, eg. tracking of allocated and freed memory only in Storage::GetStatisticLevel() >= 1
	if ( Storage::GetStatisticLevel() >= 1 ) {
		MemChecker mc(allocatorName, pAllocator);
		const long sz = 3000;
		char *ptr[sz];
		long i = 0;
		for ( i = 0 ; i < sz ; i++ ) {
			ptr[i] = (char *)pAllocator->Malloc(i);
		}
		assertEqual(4498500, mc.CheckDelta());
		for ( i = 0 ; i < sz ; i++ ) {
			pAllocator->Free(ptr[i]);
		}
		pAllocator->PrintStatistic();
		assertEqual(0, mc.CheckDelta());
	}
}

void StorageTest::SimpleSizeHintTest(TString allocatorName, Allocator *pAllocator)
{
	const size_t sz = 3000;
	size_t i = 0;
	for ( i = 0 ; i < sz ; i++ ) {
		t_assert(pAllocator->SizeHint(i) >= i);
	}
}

void StorageTest::PoolSizeHintTest()
{
	PoolAllocator pa(1, 1022, 10);
	SimpleSizeHintTest("PoolAllocator", &pa);
	const size_t maxbucketsize = 0x2000;
	// test some significant values
	// must be adjusted if implementation of pool allocator is changed

	const u_long lMinimumSize = 16;
	assertEqual(lMinimumSize, pa.SizeHint(0));
	assertEqual(lMinimumSize, pa.SizeHint(1));
	assertEqual(lMinimumSize, pa.SizeHint(lMinimumSize));
	assertEqual(lMinimumSize << 1, pa.SizeHint(lMinimumSize + 1));
	assertEqual(lMinimumSize << 1, pa.SizeHint(lMinimumSize << 1));
	assertEqual(lMinimumSize << 2, pa.SizeHint((lMinimumSize << 1) + 1));
	assertEqual(0x2000, pa.SizeHint(0x1fff));
	assertEqual(0x2fff, pa.SizeHint(0x2fff));
	{
		for (size_t s = 0, expected = lMinimumSize; s < 0x7fff; s += 8 ) {
			if (expected < s) {
				expected <<= 1;
			}
			if (expected <= maxbucketsize) {
				assertEqual(expected, pa.SizeHint(s));
			} else {
				assertEqual(s, pa.SizeHint(s));
			}
		}
	}
	{
		for (size_t s = 1, expected = lMinimumSize; s < 0x7fff; s += 8 ) {
			if (expected < s) {
				expected <<= 1;
			}
			if (expected <= maxbucketsize) {
				assertEqual(expected, pa.SizeHint(s));
			} else {
				assertEqual(s, pa.SizeHint(s));
			}
		}
	}
}

void StorageTest::AllocatorTest()
{
	GlobalAllocator ga;
	SimpleSizeHintTest("GlobalAllocator",  &ga);
	SimpleAllocTest("GlobalAllocator",  &ga);
}

void StorageTest::AllocatorTiming()
{
	PoolAllocator pa(1, 8 * 1024, 21);
	DoTimingWith("PoolAllocator", &pa);
	GlobalAllocator ga;
	DoTimingWith("GlobalAllocator", &ga);
}

void StorageTest::DoTimingWith(TString allocatorName, Allocator *pAllocator)
{
	{
		StartTraceMem1(StorageTest.DoTimingWith, pAllocator);
		MemChecker mc("StorageTest.DoTimingWith", pAllocator);
		const int cAllocSz = 5;
		long allocSzArr[cAllocSz];
		void *allocPtr[cAllocSz];
		long allocSz = 16;
		const int cRunSize = 10000;
		l_long t;
		long i;
		for (i = 0; i < cAllocSz; i++) {
			// generate some alloc sizes
			allocSzArr[i] = allocSz;
			allocSz *= 2;
		}

		DiffTimer dt;
		dt.Start();
		for ( long lrun = cRunSize - 1; lrun >= 0; lrun--) {
			if ( lrun < (cRunSize - cAllocSz) ) {
				pAllocator->Free(allocPtr[(lrun + cAllocSz) % cAllocSz]);
			}
			allocPtr[lrun % cAllocSz] = pAllocator->Malloc(allocSzArr[lrun % cAllocSz]);
		}
		for (i = 0; i < cAllocSz; i++) {
			pAllocator->Free(allocPtr[i]);
		}
		t = dt.Reset();
		pAllocator->PrintStatistic();
		assertEqual(0, mc.CheckDelta());
	}
}

void StorageTest::AnyStorageGlobalAssignment()
{
	// test assignment with Storage::Global
	Anything a;
	Anything b;

	t_assert(a.GetAllocator() == Storage::Global());
	t_assert(b.GetAllocator() == Storage::Global());

	a = b;
	t_assert(a.GetAllocator() == Storage::Global());
	t_assert(b.GetAllocator() == Storage::Global());

	b = 1;
	t_assert(b.GetAllocator() == Storage::Global());
	a = b;
	t_assert(a.GetAllocator() == Storage::Global());
	t_assert(b.GetAllocator() == Storage::Global());
}

void StorageTest::AnyEqualAllocatorAssignment()
{
	GlobalAllocator ga;
	Anything a(&ga);
	Anything b(&ga);

	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &ga);

	a = b;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &ga);

	b = 1;
	t_assert(b.GetAllocator() == &ga);
	a = b;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &ga);

}

void StorageTest::AnyEqualPoolAllocatorAssignment()
{
	PoolAllocator pa(100, 10);
	Anything a(&pa);
	Anything b(&pa);

	t_assert(a.GetAllocator() == &pa);
	t_assert(b.GetAllocator() == &pa);

	a = b;
	t_assert(a.GetAllocator() == &pa);
	t_assert(b.GetAllocator() == &pa);

	b = 1;
	t_assert(b.GetAllocator() == &pa);
	a = b;
	t_assert(a.GetAllocator() == &pa);
	t_assert(b.GetAllocator() == &pa);

}

void StorageTest::AnyDifferentAllocatorAssignment()
{
	GlobalAllocator ga;
	PoolAllocator pa(100, 10);
	Anything a(&ga);
	Anything b(&pa);

	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &pa);

	a = b;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &pa);

	b = 1;
	t_assert(b.GetAllocator() == &pa);

	a = b;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &pa);

	b = a;
	t_assert(a.GetAllocator() == &ga);
	t_assert(b.GetAllocator() == &pa);
}

void StorageTest::AnyPathology()
{
	//try to force a null allocator with SetAllocator
	Anything a;
	t_assert(a.GetAllocator() == Storage::Global());
	t_assert(!a.SetAllocator(0));
	t_assert(a.GetAllocator() == Storage::Global());
	a = "what a fool";
	t_assert(Storage::Global() == a.GetAllocator());
	assertEqual("what a fool", a.AsCharPtr());

	//try to force a null allocator in constructor
	Anything a1((Allocator *)0);
	t_assert(a1.GetAllocator() == Storage::Global());
	a1 = "what a fool";
	t_assert(Storage::Global() == a1.GetAllocator());
	assertEqual("what a fool", a1.AsCharPtr());
}

void StorageTest::AnyAssignment()
{
	AnyStorageGlobalAssignment();
	AnyEqualAllocatorAssignment();
	AnyEqualPoolAllocatorAssignment();
	AnyDifferentAllocatorAssignment();
	AnyPathology();
}

Test *StorageTest::suite ()
{
	TestSuite *testSuite = new TestSuite;
	ADD_CASE(testSuite, StorageTest, PoolSizeHintTest);
	ADD_CASE(testSuite, StorageTest, SimpleCallocSetsToZeroTest);
	ADD_CASE(testSuite, StorageTest, AllocatorTest);
	ADD_CASE(testSuite, StorageTest, AllocatorTiming);
	ADD_CASE(testSuite, StorageTest, LeakTest);
	ADD_CASE(testSuite, StorageTest, AnyAssignment);
	return testSuite;
}
<|endoftext|>


<commit_before><commit_msg>`Holobiont`: `generic_master_module` -> `brain_master`.<commit_after><|endoftext|>


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

#include "chrome/browser/views/tabs/tab.h"

#include "app/gfx/canvas.h"
#include "app/gfx/font.h"
#include "app/gfx/path.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/gfx/size.h"
#include "grit/generated_resources.h"
#include "views/controls/menu/chrome_menu.h"
#if defined(OS_WIN)
#include "views/widget/tooltip_manager.h"
#endif
#include "views/widget/widget.h"

const std::string Tab::kTabClassName = "browser/tabs/Tab";

static const SkScalar kTabCapWidth = 15;
static const SkScalar kTabTopCurveWidth = 4;
static const SkScalar kTabBottomCurveWidth = 3;

class Tab::ContextMenuController : public views::MenuDelegate {
 public:
  explicit ContextMenuController(Tab* tab)
      : tab_(tab),
        last_command_(TabStripModel::CommandFirst) {
    menu_.reset(new views::MenuItemView(this));
    menu_->AppendMenuItemWithLabel(TabStripModel::CommandNewTab,
                                   l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB));
    menu_->AppendSeparator();
    menu_->AppendMenuItemWithLabel(TabStripModel::CommandReload,
                                   l10n_util::GetString(IDS_TAB_CXMENU_RELOAD));
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandDuplicate,
        l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE));
    menu_->AppendSeparator();
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandCloseTab,
        l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB));
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandCloseOtherTabs,
        l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS));
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandCloseTabsToRight,
        l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSTORIGHT));
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandCloseTabsOpenedBy,
        l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSOPENEDBY));
    menu_->AppendMenuItemWithLabel(
      TabStripModel::CommandRestoreTab, l10n_util::GetString(IDS_RESTORE_TAB));
  }

  void RunMenuAt(int x, int y) {
    views::MenuItemView::AnchorPosition anchor =
        (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
        views::MenuItemView::TOPRIGHT : views::MenuItemView::TOPLEFT;
    menu_->RunMenuAt(tab_->GetWidget()->GetNativeView(), gfx::Rect(x, y, 0, 0),
                     anchor, true);
    if (tab_)
      tab_->ContextMenuClosed();
    delete this;
  }

  void Cancel() {
    tab_ = NULL;
    menu_->Cancel();
  }

 private:
  virtual ~ContextMenuController() {
  }

  // views::MenuDelegate implementation:
  virtual bool IsCommandEnabled(int id) const {
    // The MenuItemView used to contain the contents of the Context Menu itself
    // has a command id of 0, and it will check to see if it's enabled for
    // some reason during its construction. The TabStripModel can't handle
    // command indices it doesn't know about, so we need to filter this out
    // here.
    if (id == 0 || !tab_)
      return false;
    return tab_->delegate()->IsCommandEnabledForTab(
        static_cast<TabStripModel::ContextMenuCommand>(id),
        tab_);
  }

  virtual void ExecuteCommand(int id) {
    if (!tab_)
      return;

    tab_->delegate()->ExecuteCommandForTab(
        static_cast<TabStripModel::ContextMenuCommand>(id),
        tab_);
  }

  virtual void SelectionChanged(views::MenuItemView* menu) {
    if (!tab_)
      return;

    TabStripModel::ContextMenuCommand command =
        static_cast<TabStripModel::ContextMenuCommand>(menu->GetCommand());
    tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_);
    last_command_ = command;
    tab_->delegate()->StartHighlightTabsForCommand(command, tab_);
  }

 private:
  // The context menu.
  scoped_ptr<views::MenuItemView> menu_;

  // The Tab the context menu was brought up for. Set to NULL when the menu
  // is canceled.
  Tab* tab_;

  // The last command that was selected, so that we can start/stop highlighting
  // appropriately as the user moves through the menu.
  TabStripModel::ContextMenuCommand last_command_;

  DISALLOW_COPY_AND_ASSIGN(ContextMenuController);
};

///////////////////////////////////////////////////////////////////////////////
// Tab, public:

Tab::Tab(TabDelegate* delegate)
    : TabRenderer(),
      delegate_(delegate),
      closing_(false),
      menu_controller_(NULL) {
  close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
  close_button()->SetAnimationDuration(0);
  SetContextMenuController(this);
}

Tab::~Tab() {
  if (menu_controller_) {
    // The menu is showing. Close the menu.
    menu_controller_->Cancel();

    // Invoke this so that we hide the highlight.
    ContextMenuClosed();
  }
}

///////////////////////////////////////////////////////////////////////////////
// Tab, TabRenderer overrides:

bool Tab::IsSelected() const {
  return delegate_->IsTabSelected(this);
}

///////////////////////////////////////////////////////////////////////////////
// Tab, views::View overrides:

bool Tab::HasHitTestMask() const {
  return true;
}

void Tab::GetHitTestMask(gfx::Path* mask) const {
  MakePathForTab(mask);
}

bool Tab::OnMousePressed(const views::MouseEvent& event) {
  if (event.IsOnlyLeftMouseButton()) {
    // Store whether or not we were selected just now... we only want to be
    // able to drag foreground tabs, so we don't start dragging the tab if
    // it was in the background.
    bool just_selected = !IsSelected();
    if (just_selected)
      delegate_->SelectTab(this);
    delegate_->MaybeStartDrag(this, event);
  }
  return true;
}

bool Tab::OnMouseDragged(const views::MouseEvent& event) {
  delegate_->ContinueDrag(event);
  return true;
}

void Tab::OnMouseReleased(const views::MouseEvent& event, bool canceled) {
  // Notify the drag helper that we're done with any potential drag operations.
  // Clean up the drag helper, which is re-created on the next mouse press.
  // In some cases, ending the drag will schedule the tab for destruction; if
  // so, bail immediately, since our members are already dead and we shouldn't
  // do anything else except drop the tab where it is.
  if (delegate_->EndDrag(canceled))
    return;

  // Close tab on middle click, but only if the button is released over the tab
  // (normal windows behavior is to discard presses of a UI element where the
  // releases happen off the element).
  if (event.IsMiddleMouseButton() && HitTest(event.location()))
    delegate_->CloseTab(this);
}

bool Tab::GetTooltipText(int x, int y, std::wstring* tooltip) {
  std::wstring title = GetTitle();
  if (!title.empty()) {
    // Only show the tooltip if the title is truncated.
    gfx::Font font;
    if (font.GetStringWidth(title) > title_bounds().width()) {
      *tooltip = title;
      return true;
    }
  }
  return false;
}

bool Tab::GetTooltipTextOrigin(int x, int y, gfx::Point* origin) {
  gfx::Font font;
  origin->set_x(title_bounds().x() + 10);
  origin->set_y(-views::TooltipManager::GetTooltipHeight() - 4);
  return true;
}

bool Tab::GetAccessibleRole(AccessibilityTypes::Role* role) {
  DCHECK(role);

  *role = AccessibilityTypes::ROLE_PAGETAB;
  return true;
}

bool Tab::GetAccessibleName(std::wstring* name) {
  *name = GetTitle();
  return !name->empty();
}

///////////////////////////////////////////////////////////////////////////////
// Tab, views::ContextMenuController implementation:

void Tab::ShowContextMenu(views::View* source, int x, int y,
                          bool is_mouse_gesture) {
  if (menu_controller_)
    return;
  menu_controller_ = new ContextMenuController(this);
  menu_controller_->RunMenuAt(x, y);
  // ContextMenuController takes care of deleting itself.
}

///////////////////////////////////////////////////////////////////////////////
// views::ButtonListener implementation:

void Tab::ButtonPressed(views::Button* sender) {
  if (sender == close_button())
    delegate_->CloseTab(this);
}

///////////////////////////////////////////////////////////////////////////////
// Tab, private:

void Tab::MakePathForTab(gfx::Path* path) const {
  DCHECK(path);

  SkScalar h = SkIntToScalar(height());
  SkScalar w = SkIntToScalar(width());

  path->moveTo(0, h);

  // Left end cap.
  path->lineTo(kTabBottomCurveWidth, h - kTabBottomCurveWidth);
  path->lineTo(kTabCapWidth - kTabTopCurveWidth, kTabTopCurveWidth);
  path->lineTo(kTabCapWidth, 0);

  // Connect to the right cap.
  path->lineTo(w - kTabCapWidth, 0);

  // Right end cap.
  path->lineTo(w - kTabCapWidth + kTabTopCurveWidth, kTabTopCurveWidth);
  path->lineTo(w - kTabBottomCurveWidth, h - kTabBottomCurveWidth);
  path->lineTo(w, h);

  // Close out the path.
  path->lineTo(0, h);
  path->close();
}

void Tab::ContextMenuClosed() {
  delegate()->StopAllHighlighting();
  menu_controller_ = NULL;
}
<commit_msg>Removes ifdef around include of tooltip_manager now that it's been ported.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/tabs/tab.h"

#include "app/gfx/canvas.h"
#include "app/gfx/font.h"
#include "app/gfx/path.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/gfx/size.h"
#include "grit/generated_resources.h"
#include "views/controls/menu/chrome_menu.h"
#include "views/widget/tooltip_manager.h"
#include "views/widget/widget.h"

const std::string Tab::kTabClassName = "browser/tabs/Tab";

static const SkScalar kTabCapWidth = 15;
static const SkScalar kTabTopCurveWidth = 4;
static const SkScalar kTabBottomCurveWidth = 3;

class Tab::ContextMenuController : public views::MenuDelegate {
 public:
  explicit ContextMenuController(Tab* tab)
      : tab_(tab),
        last_command_(TabStripModel::CommandFirst) {
    menu_.reset(new views::MenuItemView(this));
    menu_->AppendMenuItemWithLabel(TabStripModel::CommandNewTab,
                                   l10n_util::GetString(IDS_TAB_CXMENU_NEWTAB));
    menu_->AppendSeparator();
    menu_->AppendMenuItemWithLabel(TabStripModel::CommandReload,
                                   l10n_util::GetString(IDS_TAB_CXMENU_RELOAD));
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandDuplicate,
        l10n_util::GetString(IDS_TAB_CXMENU_DUPLICATE));
    menu_->AppendSeparator();
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandCloseTab,
        l10n_util::GetString(IDS_TAB_CXMENU_CLOSETAB));
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandCloseOtherTabs,
        l10n_util::GetString(IDS_TAB_CXMENU_CLOSEOTHERTABS));
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandCloseTabsToRight,
        l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSTORIGHT));
    menu_->AppendMenuItemWithLabel(
        TabStripModel::CommandCloseTabsOpenedBy,
        l10n_util::GetString(IDS_TAB_CXMENU_CLOSETABSOPENEDBY));
    menu_->AppendMenuItemWithLabel(
      TabStripModel::CommandRestoreTab, l10n_util::GetString(IDS_RESTORE_TAB));
  }

  void RunMenuAt(int x, int y) {
    views::MenuItemView::AnchorPosition anchor =
        (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
        views::MenuItemView::TOPRIGHT : views::MenuItemView::TOPLEFT;
    menu_->RunMenuAt(tab_->GetWidget()->GetNativeView(), gfx::Rect(x, y, 0, 0),
                     anchor, true);
    if (tab_)
      tab_->ContextMenuClosed();
    delete this;
  }

  void Cancel() {
    tab_ = NULL;
    menu_->Cancel();
  }

 private:
  virtual ~ContextMenuController() {
  }

  // views::MenuDelegate implementation:
  virtual bool IsCommandEnabled(int id) const {
    // The MenuItemView used to contain the contents of the Context Menu itself
    // has a command id of 0, and it will check to see if it's enabled for
    // some reason during its construction. The TabStripModel can't handle
    // command indices it doesn't know about, so we need to filter this out
    // here.
    if (id == 0 || !tab_)
      return false;
    return tab_->delegate()->IsCommandEnabledForTab(
        static_cast<TabStripModel::ContextMenuCommand>(id),
        tab_);
  }

  virtual void ExecuteCommand(int id) {
    if (!tab_)
      return;

    tab_->delegate()->ExecuteCommandForTab(
        static_cast<TabStripModel::ContextMenuCommand>(id),
        tab_);
  }

  virtual void SelectionChanged(views::MenuItemView* menu) {
    if (!tab_)
      return;

    TabStripModel::ContextMenuCommand command =
        static_cast<TabStripModel::ContextMenuCommand>(menu->GetCommand());
    tab_->delegate()->StopHighlightTabsForCommand(last_command_, tab_);
    last_command_ = command;
    tab_->delegate()->StartHighlightTabsForCommand(command, tab_);
  }

 private:
  // The context menu.
  scoped_ptr<views::MenuItemView> menu_;

  // The Tab the context menu was brought up for. Set to NULL when the menu
  // is canceled.
  Tab* tab_;

  // The last command that was selected, so that we can start/stop highlighting
  // appropriately as the user moves through the menu.
  TabStripModel::ContextMenuCommand last_command_;

  DISALLOW_COPY_AND_ASSIGN(ContextMenuController);
};

///////////////////////////////////////////////////////////////////////////////
// Tab, public:

Tab::Tab(TabDelegate* delegate)
    : TabRenderer(),
      delegate_(delegate),
      closing_(false),
      menu_controller_(NULL) {
  close_button()->SetAccessibleName(l10n_util::GetString(IDS_ACCNAME_CLOSE));
  close_button()->SetAnimationDuration(0);
  SetContextMenuController(this);
}

Tab::~Tab() {
  if (menu_controller_) {
    // The menu is showing. Close the menu.
    menu_controller_->Cancel();

    // Invoke this so that we hide the highlight.
    ContextMenuClosed();
  }
}

///////////////////////////////////////////////////////////////////////////////
// Tab, TabRenderer overrides:

bool Tab::IsSelected() const {
  return delegate_->IsTabSelected(this);
}

///////////////////////////////////////////////////////////////////////////////
// Tab, views::View overrides:

bool Tab::HasHitTestMask() const {
  return true;
}

void Tab::GetHitTestMask(gfx::Path* mask) const {
  MakePathForTab(mask);
}

bool Tab::OnMousePressed(const views::MouseEvent& event) {
  if (event.IsOnlyLeftMouseButton()) {
    // Store whether or not we were selected just now... we only want to be
    // able to drag foreground tabs, so we don't start dragging the tab if
    // it was in the background.
    bool just_selected = !IsSelected();
    if (just_selected)
      delegate_->SelectTab(this);
    delegate_->MaybeStartDrag(this, event);
  }
  return true;
}

bool Tab::OnMouseDragged(const views::MouseEvent& event) {
  delegate_->ContinueDrag(event);
  return true;
}

void Tab::OnMouseReleased(const views::MouseEvent& event, bool canceled) {
  // Notify the drag helper that we're done with any potential drag operations.
  // Clean up the drag helper, which is re-created on the next mouse press.
  // In some cases, ending the drag will schedule the tab for destruction; if
  // so, bail immediately, since our members are already dead and we shouldn't
  // do anything else except drop the tab where it is.
  if (delegate_->EndDrag(canceled))
    return;

  // Close tab on middle click, but only if the button is released over the tab
  // (normal windows behavior is to discard presses of a UI element where the
  // releases happen off the element).
  if (event.IsMiddleMouseButton() && HitTest(event.location()))
    delegate_->CloseTab(this);
}

bool Tab::GetTooltipText(int x, int y, std::wstring* tooltip) {
  std::wstring title = GetTitle();
  if (!title.empty()) {
    // Only show the tooltip if the title is truncated.
    gfx::Font font;
    if (font.GetStringWidth(title) > title_bounds().width()) {
      *tooltip = title;
      return true;
    }
  }
  return false;
}

bool Tab::GetTooltipTextOrigin(int x, int y, gfx::Point* origin) {
  gfx::Font font;
  origin->set_x(title_bounds().x() + 10);
  origin->set_y(-views::TooltipManager::GetTooltipHeight() - 4);
  return true;
}

bool Tab::GetAccessibleRole(AccessibilityTypes::Role* role) {
  DCHECK(role);

  *role = AccessibilityTypes::ROLE_PAGETAB;
  return true;
}

bool Tab::GetAccessibleName(std::wstring* name) {
  *name = GetTitle();
  return !name->empty();
}

///////////////////////////////////////////////////////////////////////////////
// Tab, views::ContextMenuController implementation:

void Tab::ShowContextMenu(views::View* source, int x, int y,
                          bool is_mouse_gesture) {
  if (menu_controller_)
    return;
  menu_controller_ = new ContextMenuController(this);
  menu_controller_->RunMenuAt(x, y);
  // ContextMenuController takes care of deleting itself.
}

///////////////////////////////////////////////////////////////////////////////
// views::ButtonListener implementation:

void Tab::ButtonPressed(views::Button* sender) {
  if (sender == close_button())
    delegate_->CloseTab(this);
}

///////////////////////////////////////////////////////////////////////////////
// Tab, private:

void Tab::MakePathForTab(gfx::Path* path) const {
  DCHECK(path);

  SkScalar h = SkIntToScalar(height());
  SkScalar w = SkIntToScalar(width());

  path->moveTo(0, h);

  // Left end cap.
  path->lineTo(kTabBottomCurveWidth, h - kTabBottomCurveWidth);
  path->lineTo(kTabCapWidth - kTabTopCurveWidth, kTabTopCurveWidth);
  path->lineTo(kTabCapWidth, 0);

  // Connect to the right cap.
  path->lineTo(w - kTabCapWidth, 0);

  // Right end cap.
  path->lineTo(w - kTabCapWidth + kTabTopCurveWidth, kTabTopCurveWidth);
  path->lineTo(w - kTabBottomCurveWidth, h - kTabBottomCurveWidth);
  path->lineTo(w, h);

  // Close out the path.
  path->lineTo(0, h);
  path->close();
}

void Tab::ContextMenuClosed() {
  delegate()->StopAllHighlighting();
  menu_controller_ = NULL;
}
<|endoftext|>


<commit_before>#include "generator.h"
#include "opcodes.h"
#include "sections.h"

#include <iostream>
#include <iomanip>

namespace ceos {
  std::stringstream &Generator::generate() {
    generateProgram(m_ast);
    emitOpcode(Opcode::exit);
    m_output.seekg(0);
    return m_output;
  }

  void Generator::generateNode(std::shared_ptr<AST> node) {
    switch (node->type) {
      case AST::Type::Call:
        generateCall(std::static_pointer_cast<AST::Call>(node));
        break;
      case AST::Type::Number:
        generateNumber(std::static_pointer_cast<AST::Number>(node));
        break;
      case AST::Type::ID:
        generateID(std::static_pointer_cast<AST::ID>(node));
        break;
      case AST::Type::String:
        generateString(std::static_pointer_cast<AST::String>(node));
        break;
      case AST::Type::FunctionArgument:
        generateFunctionArgument(std::static_pointer_cast<AST::FunctionArgument>(node));
        break;
      case AST::Type::Function:
        generateFunctionDefinition(AST::asFunction(node));
        break;
      case AST::Type::If:
        generateIf(AST::asIf(node));
        break;
      case AST::Type::TypeInfo:
        // TODO: use type info
        break;
      default:
        std::cerr <<  "Unhandled node: `" << AST::typeName(node->type) << "`\n";
        throw;
    }
  }

  void Generator::write(int data) {
    m_output.write(reinterpret_cast<char *>(&data), sizeof(data));
  }

  void Generator::write(const std::string &data) {
    m_output << data;
    m_output.put('\0');
  }

  void Generator::emitOpcode(Opcode::Type opcode) {
    m_output.put(opcode);
  }

  void Generator::emitJmp(Opcode::Type jmpType, std::vector<std::shared_ptr<AST>> &body)  {
    emitJmp(jmpType, body, false);
  }

  void Generator::emitJmp(Opcode::Type jmpType, std::vector<std::shared_ptr<AST>> &body, bool skipNextJump)  {
    emitOpcode(jmpType);
    unsigned beforePos = m_output.tellp();
    write(0); // placeholder

    for (auto node : body) {
      generateNode(node);
    }

    unsigned afterPos = m_output.tellp();
    m_output.seekp(beforePos);
    write((afterPos - beforePos)
        + (skipNextJump ? 6 : 1) // special case for if with else
    );
    m_output.seekp(afterPos);
  }

  void Generator::generateCall(std::shared_ptr<AST::Call> call) {
    for (unsigned i = call->arguments.size(); i > 0;) {
      generateNode(call->arguments[--i]);
    }

    generateNode(call->callee);

    emitOpcode(Opcode::call);
    write(call->arguments.size());
  }

  void Generator::generateNumber(std::shared_ptr<AST::Number> number) {
    emitOpcode(Opcode::push);
    write(number->value);
  }

  void Generator::generateID(std::shared_ptr<AST::ID> id) {
    auto v = m_scope->get(id->name);
    if (v.get()) {
      generateNode(v);
    } else {
      emitOpcode(Opcode::lookup);
      write(id->uid);
    }
  }

  void Generator::generateString(std::shared_ptr<AST::String> str) {
    emitOpcode(Opcode::load_string);
    write(str->uid);
  }

  void Generator::generateFunctionArgument(std::shared_ptr<AST::FunctionArgument> arg) {
    emitOpcode(Opcode::push_arg);
    write(arg->index);
  }

  void Generator::generateFunctionDefinition(std::shared_ptr<AST::Function> fn) {
    emitOpcode(Opcode::create_closure);
    write(m_ast->functions.size());
    if (fn->name->name != "_") {
      emitOpcode(Opcode::bind);
    }
    m_ast->functions.push_back(fn);
  }

  void Generator::generateFunctionSource(std::shared_ptr<AST::Function> fn) {
    std::string fnName = fn->name->name;
    if (fnName == "_") {
      static unsigned id = 0;
      fnName = "_" + std::to_string(id++);
      m_ast->strings.push_back(fnName);
    }
    write(INDEX_OF(m_ast->strings, fnName));
    write(fn->arguments.size());

    m_scope = m_scope->create();

    int i = 0;
    for (auto arg : fn->arguments) {
      std::string &name = AST::asID(arg)->name;
      m_scope->set(name, std::make_shared<AST::FunctionArgument>(i++));
      write(INDEX_OF(m_ast->strings, name));
    }

    for (auto node : fn->body) {
      generateNode(node);
    }

    m_scope = m_scope->restore();

    emitOpcode(Opcode::ret);
  }

  void Generator::generateIf(std::shared_ptr<AST::If> iff) {
    generateNode(iff->condition);

    emitJmp(Opcode::jz, iff->ifBody, iff->elseBody.size() > 0);

    if (iff->elseBody.size()) {
      emitJmp(Opcode::jmp, iff->elseBody);
    }
  }

  void Generator::generateProgram(std::shared_ptr<AST::Program> program) {
    for (auto node : program->nodes()) {
      generateNode(node);
    }

    auto text = m_output.str();
    m_output = std::stringstream();

    if (program->functions.size()) {
      for (unsigned i = 0; i < program->functions.size(); i++) {
        write(Section::FunctionHeader);
        generateFunctionSource(program->functions[i]);
      }
    }

    auto functions = m_output.str();
    m_output = std::stringstream();

    if (program->strings.size()) {
      write(Section::Header);
      write(Section::Strings);

      for (auto string : program->strings) {
        write(string);
      }
    }

    if (functions.length()) {
      write(Section::Header);
      write(Section::Functions);
      m_output << functions;
    }

    write(Section::Header);
    write(Section::Text);
    m_output << text;
  }

  static std::vector<std::string> strings;
  static std::vector<std::string> functions;
  static size_t width;
  static std::string padding("  ");
  void Generator::disassemble(std::stringstream &bytecode) {
    size_t size = bytecode.str().length();
    width = std::ceil(std::log10(size + 1)) + 1;

#define WRITE(OFFSET, ...) \
    std::cout << "[" \
    <<  std::setfill(' ') << std::setw(width) << ((int)bytecode.tellg() - (OFFSET)) \
    << "] " << padding << __VA_ARGS__ << "\n"

read_section:
    READ_INT(bytecode, ceos);
    assert(ceos == 0xCE05);

    READ_INT(bytecode, section);

    switch (section) {
      case Section::Strings:
        padding = "";
        WRITE(8, "STRINGS:");
        padding = "  ";
        goto section_strings;
        break;
      case Section::Functions: {
        padding = "";
        WRITE(8, "FUNCTIONS:");
        padding = "  ";
        auto offset = bytecode.tellg();
        while (true) {
          READ_INT(bytecode, header);
          if (header == Section::FunctionHeader) {
            READ_INT(bytecode, fnID);
            functions.push_back(strings[fnID]);
            continue;
          } else if (header == Section::Header) {
            break;
          }
        }
        bytecode.seekg(offset);
        goto section_functions;
        break;
      }
      case Section::Text:
        padding = "";
        WRITE(8, "TEXT:");
        padding = "  ";
        goto section_code;
        break;
    }

section_strings:
    while (true) {
      READ_INT(bytecode, ceos);
      bytecode.seekg(-sizeof(ceos), bytecode.cur);
      if (ceos == Section::Header)  {
        goto read_section;
      }
      static unsigned str_index = 0;
      READ_STR(bytecode, str);
      strings.push_back(str);
      WRITE(str.length() + 1, "$" << str_index++ << ": " << str);
    }

section_functions: {
      READ_INT(bytecode, fn_header);
      assert(fn_header == Section::FunctionHeader);

      READ_INT(bytecode, fn_id);
      READ_INT(bytecode, arg_count);

      std::stringstream args;
      for (int i = 0; i < arg_count; i++) {
        READ_INT(bytecode, argID);
        args << "$" << i << ": " << strings[argID];
        if (i < arg_count - 1) args << ", ";
      }

      padding = "";
      WRITE(8, strings[fn_id] << "(" << args.str() << "):");
      padding = "  ";

      while (true) {
        READ_INT(bytecode, header);
        bytecode.seekg(-sizeof(header), bytecode.cur);
        if (header == Section::FunctionHeader) {
          goto section_functions;
        } else if (header == Section::Header) {
          goto read_section;
        }

        char opcode = bytecode.get();
        printOpcode(bytecode, static_cast<Opcode::Type>(opcode));
      }
    }

section_code:
    while (true) {
      char opcode = bytecode.get();
      if (bytecode.eof() || bytecode.fail()) {
        return;
      }
      printOpcode(bytecode, static_cast<Opcode::Type>(opcode));
    }
    goto read_section;
  }

  void Generator::printOpcode(std::stringstream &bytecode, Opcode::Type opcode) {
    size_t size = bytecode.str().length();
    size_t width = std::ceil(std::log10(size + 1)) + 1;

    switch (opcode) {
      case Opcode::push: {
        READ_INT(bytecode, value);
        WRITE(5, "push 0x" << std::setbase(16) << value << std::setbase(10));
        break;
      }
      case Opcode::call: {
        READ_INT(bytecode, nargs);
        WRITE(5, "call (" << nargs << ")");
        break;
      }
      case Opcode::load_string: {
        READ_INT(bytecode, stringID);
        WRITE(5, "load_string $" << stringID);
        break;
      }
      case Opcode::lookup: {
        READ_INT(bytecode, id);
        WRITE(5, "lookup $" << id << "(" << strings[id] << ")");
        break;
      }
      case Opcode::create_closure: {
        READ_INT(bytecode, fnID);
        WRITE(5, "create_closure " << functions[fnID]);
        break;
      }
      case Opcode::jmp:  {
        READ_INT(bytecode, target);
        WRITE(5, "jmp [" << ((int)bytecode.tellg() + target) << "]");
        break;
      }
      case Opcode::jz: {
        READ_INT(bytecode, target);
        WRITE(5, "jz [" << ((int)bytecode.tellg() + target) << "]");
        break;
      }
      case Opcode::push_arg: {
        READ_INT(bytecode, arg);
        WRITE(5, "push_arg $" << arg);
        break;
      }
      case Opcode::ret: {
        WRITE(1, "ret");
        break;
      }
      case Opcode::bind:
        WRITE(1, "bind");
        break;
      case Opcode::exit:
        WRITE(1, "exit");
        break;
      default:
        std::cerr << "Unhandled opcode: " << Opcode::typeName(static_cast<Opcode::Type>(opcode)) << "\n";
        throw;
    }
  }
#undef WRITE
}
<commit_msg>Fix jmp offset disassembly<commit_after>#include "generator.h"
#include "opcodes.h"
#include "sections.h"

#include <iostream>
#include <iomanip>

namespace ceos {
  std::stringstream &Generator::generate() {
    generateProgram(m_ast);
    emitOpcode(Opcode::exit);
    m_output.seekg(0);
    return m_output;
  }

  void Generator::generateNode(std::shared_ptr<AST> node) {
    switch (node->type) {
      case AST::Type::Call:
        generateCall(std::static_pointer_cast<AST::Call>(node));
        break;
      case AST::Type::Number:
        generateNumber(std::static_pointer_cast<AST::Number>(node));
        break;
      case AST::Type::ID:
        generateID(std::static_pointer_cast<AST::ID>(node));
        break;
      case AST::Type::String:
        generateString(std::static_pointer_cast<AST::String>(node));
        break;
      case AST::Type::FunctionArgument:
        generateFunctionArgument(std::static_pointer_cast<AST::FunctionArgument>(node));
        break;
      case AST::Type::Function:
        generateFunctionDefinition(AST::asFunction(node));
        break;
      case AST::Type::If:
        generateIf(AST::asIf(node));
        break;
      case AST::Type::TypeInfo:
        // TODO: use type info
        break;
      default:
        std::cerr <<  "Unhandled node: `" << AST::typeName(node->type) << "`\n";
        throw;
    }
  }

  void Generator::write(int data) {
    m_output.write(reinterpret_cast<char *>(&data), sizeof(data));
  }

  void Generator::write(const std::string &data) {
    m_output << data;
    m_output.put('\0');
  }

  void Generator::emitOpcode(Opcode::Type opcode) {
    m_output.put(opcode);
  }

  void Generator::emitJmp(Opcode::Type jmpType, std::vector<std::shared_ptr<AST>> &body)  {
    emitJmp(jmpType, body, false);
  }

  void Generator::emitJmp(Opcode::Type jmpType, std::vector<std::shared_ptr<AST>> &body, bool skipNextJump)  {
    emitOpcode(jmpType);
    unsigned beforePos = m_output.tellp();
    write(0); // placeholder

    for (auto node : body) {
      generateNode(node);
    }

    unsigned afterPos = m_output.tellp();
    m_output.seekp(beforePos);
    write((afterPos - beforePos)
        + (skipNextJump ? 6 : 1) // special case for if with else
    );
    m_output.seekp(afterPos);
  }

  void Generator::generateCall(std::shared_ptr<AST::Call> call) {
    for (unsigned i = call->arguments.size(); i > 0;) {
      generateNode(call->arguments[--i]);
    }

    generateNode(call->callee);

    emitOpcode(Opcode::call);
    write(call->arguments.size());
  }

  void Generator::generateNumber(std::shared_ptr<AST::Number> number) {
    emitOpcode(Opcode::push);
    write(number->value);
  }

  void Generator::generateID(std::shared_ptr<AST::ID> id) {
    auto v = m_scope->get(id->name);
    if (v.get()) {
      generateNode(v);
    } else {
      emitOpcode(Opcode::lookup);
      write(id->uid);
    }
  }

  void Generator::generateString(std::shared_ptr<AST::String> str) {
    emitOpcode(Opcode::load_string);
    write(str->uid);
  }

  void Generator::generateFunctionArgument(std::shared_ptr<AST::FunctionArgument> arg) {
    emitOpcode(Opcode::push_arg);
    write(arg->index);
  }

  void Generator::generateFunctionDefinition(std::shared_ptr<AST::Function> fn) {
    emitOpcode(Opcode::create_closure);
    write(m_ast->functions.size());
    if (fn->name->name != "_") {
      emitOpcode(Opcode::bind);
    }
    m_ast->functions.push_back(fn);
  }

  void Generator::generateFunctionSource(std::shared_ptr<AST::Function> fn) {
    std::string fnName = fn->name->name;
    if (fnName == "_") {
      static unsigned id = 0;
      fnName = "_" + std::to_string(id++);
      m_ast->strings.push_back(fnName);
    }
    write(INDEX_OF(m_ast->strings, fnName));
    write(fn->arguments.size());

    m_scope = m_scope->create();

    int i = 0;
    for (auto arg : fn->arguments) {
      std::string &name = AST::asID(arg)->name;
      m_scope->set(name, std::make_shared<AST::FunctionArgument>(i++));
      write(INDEX_OF(m_ast->strings, name));
    }

    for (auto node : fn->body) {
      generateNode(node);
    }

    m_scope = m_scope->restore();

    emitOpcode(Opcode::ret);
  }

  void Generator::generateIf(std::shared_ptr<AST::If> iff) {
    generateNode(iff->condition);

    emitJmp(Opcode::jz, iff->ifBody, iff->elseBody.size() > 0);

    if (iff->elseBody.size()) {
      emitJmp(Opcode::jmp, iff->elseBody);
    }
  }

  void Generator::generateProgram(std::shared_ptr<AST::Program> program) {
    for (auto node : program->nodes()) {
      generateNode(node);
    }

    auto text = m_output.str();
    m_output = std::stringstream();

    if (program->functions.size()) {
      for (unsigned i = 0; i < program->functions.size(); i++) {
        write(Section::FunctionHeader);
        generateFunctionSource(program->functions[i]);
      }
    }

    auto functions = m_output.str();
    m_output = std::stringstream();

    if (program->strings.size()) {
      write(Section::Header);
      write(Section::Strings);

      for (auto string : program->strings) {
        write(string);
      }
    }

    if (functions.length()) {
      write(Section::Header);
      write(Section::Functions);
      m_output << functions;
    }

    write(Section::Header);
    write(Section::Text);
    m_output << text;
  }

  static std::vector<std::string> strings;
  static std::vector<std::string> functions;
  static size_t width;
  static std::string padding("  ");
  void Generator::disassemble(std::stringstream &bytecode) {
    size_t size = bytecode.str().length();
    width = std::ceil(std::log10(size + 1)) + 1;

#define WRITE(OFFSET, ...) \
    std::cout << "[" \
    <<  std::setfill(' ') << std::setw(width) << ((int)bytecode.tellg() - (OFFSET)) \
    << "] " << padding << __VA_ARGS__ << "\n"

read_section:
    READ_INT(bytecode, ceos);
    assert(ceos == 0xCE05);

    READ_INT(bytecode, section);

    switch (section) {
      case Section::Strings:
        padding = "";
        WRITE(8, "STRINGS:");
        padding = "  ";
        goto section_strings;
        break;
      case Section::Functions: {
        padding = "";
        WRITE(8, "FUNCTIONS:");
        padding = "  ";
        auto offset = bytecode.tellg();
        while (true) {
          READ_INT(bytecode, header);
          if (header == Section::FunctionHeader) {
            READ_INT(bytecode, fnID);
            functions.push_back(strings[fnID]);
            continue;
          } else if (header == Section::Header) {
            break;
          }
          bytecode.seekg(-3, bytecode.cur);
        }
        bytecode.seekg(offset);
        goto section_functions;
        break;
      }
      case Section::Text:
        padding = "";
        WRITE(8, "TEXT:");
        padding = "  ";
        goto section_code;
        break;
    }

section_strings:
    while (true) {
      READ_INT(bytecode, ceos);
      bytecode.seekg(-sizeof(ceos), bytecode.cur);
      if (ceos == Section::Header)  {
        goto read_section;
      }
      static unsigned str_index = 0;
      READ_STR(bytecode, str);
      strings.push_back(str);
      WRITE(str.length() + 1, "$" << str_index++ << ": " << str);
    }

section_functions: {
      READ_INT(bytecode, fn_header);
      assert(fn_header == Section::FunctionHeader);

      READ_INT(bytecode, fn_id);
      READ_INT(bytecode, arg_count);

      std::stringstream args;
      for (int i = 0; i < arg_count; i++) {
        READ_INT(bytecode, argID);
        args << "$" << i << ": " << strings[argID];
        if (i < arg_count - 1) args << ", ";
      }

      padding = "";
      WRITE(8, strings[fn_id] << "(" << args.str() << "):");
      padding = "  ";

      while (true) {
        READ_INT(bytecode, header);
        bytecode.seekg(-sizeof(header), bytecode.cur);
        if (header == Section::FunctionHeader) {
          goto section_functions;
        } else if (header == Section::Header) {
          goto read_section;
        }

        char opcode = bytecode.get();
        printOpcode(bytecode, static_cast<Opcode::Type>(opcode));
      }
    }

section_code:
    while (true) {
      char opcode = bytecode.get();
      if (bytecode.eof() || bytecode.fail()) {
        return;
      }
      printOpcode(bytecode, static_cast<Opcode::Type>(opcode));
    }
    goto read_section;
  }

  void Generator::printOpcode(std::stringstream &bytecode, Opcode::Type opcode) {
    size_t size = bytecode.str().length();
    size_t width = std::ceil(std::log10(size + 1)) + 1;

    switch (opcode) {
      case Opcode::push: {
        READ_INT(bytecode, value);
        WRITE(5, "push 0x" << std::setbase(16) << value << std::setbase(10));
        break;
      }
      case Opcode::call: {
        READ_INT(bytecode, nargs);
        WRITE(5, "call (" << nargs << ")");
        break;
      }
      case Opcode::load_string: {
        READ_INT(bytecode, stringID);
        WRITE(5, "load_string $" << stringID);
        break;
      }
      case Opcode::lookup: {
        READ_INT(bytecode, id);
        WRITE(5, "lookup $" << id << "(" << strings[id] << ")");
        break;
      }
      case Opcode::create_closure: {
        READ_INT(bytecode, fnID);
        WRITE(5, "create_closure " << functions[fnID]);
        break;
      }
      case Opcode::jmp:  {
        READ_INT(bytecode, target);
        WRITE(5, "jmp [" << ((int)bytecode.tellg() - 5 + target) << "]");
        break;
      }
      case Opcode::jz: {
        READ_INT(bytecode, target);
        WRITE(5, "jz [" << ((int)bytecode.tellg() - 5 + target) << "]");
        break;
      }
      case Opcode::push_arg: {
        READ_INT(bytecode, arg);
        WRITE(5, "push_arg $" << arg);
        break;
      }
      case Opcode::ret: {
        WRITE(1, "ret");
        break;
      }
      case Opcode::bind:
        WRITE(1, "bind");
        break;
      case Opcode::exit:
        WRITE(1, "exit");
        break;
      default:
        std::cerr << "Unhandled opcode: " << Opcode::typeName(static_cast<Opcode::Type>(opcode)) << "\n";
        throw;
    }
  }
#undef WRITE
}
<|endoftext|>