<commit_before>#include "logger.h"
#include "text/table.h"
#include "text/config.h"
#include "math/numeric.h"
#include "text/cmdline.h"
#include "chrono/measure.h"
#include "layers/affine3d.h"
#include "layers/affine4d.h"
#include <iostream>

using namespace nano;

namespace nano
{
        template <typename tvalue>
        string_t serialize_to_string(const tvalue value)
        {
                std::stringstream s;
                s << value;
                return s.str();
        }

        template <> string_t to_string<tensor2d_dims_t>(const tensor2d_dims_t dims) { return serialize_to_string(dims); }
        template <> string_t to_string<tensor3d_dims_t>(const tensor3d_dims_t dims) { return serialize_to_string(dims); }
        template <> string_t to_string<tensor4d_dims_t>(const tensor4d_dims_t dims) { return serialize_to_string(dims); }
}

namespace
{
        const auto trials = size_t(16);

        template <typename top, typename tidata, typename twdata, typename tbdata, typename todata>
        auto measure_output(top& op, const tidata& idata, const twdata& wdata, const tbdata& bdata, todata& odata)
        {
                const auto duration = measure<nanoseconds_t>([&] () { op.output(idata, wdata, bdata, odata); }, trials);
                return nano::gflops(op.params().flops_output(), duration);
        }

        template <typename top, typename tidata, typename twdata, typename tbdata, typename todata>
        auto measure_ginput(top& op, tidata& idata, const twdata& wdata, const tbdata& bdata, const todata& odata)
        {
                const auto duration = measure<nanoseconds_t>([&] () { op.ginput(idata, wdata, bdata, odata); }, trials);
                return nano::gflops(op.params().flops_ginput(), duration);
        }

        template <typename top, typename tidata, typename twdata, typename tbdata, typename todata>
        auto measure_gparam(top& op, const tidata& idata, twdata& wdata, tbdata& bdata, const todata& odata)
        {
                const auto duration = measure<nanoseconds_t>([&] () { op.gparam(idata, wdata, bdata, odata); }, trials);
                return nano::gflops(op.params().flops_gparam(), duration);
        }
}

int main(int argc, const char *argv[])
{
        // parse the command line
        cmdline_t cmdline("benchmark affine operators");
        cmdline.add("", "min-isize",    "minimum input size [32, 1024]", "1024");
        cmdline.add("", "max-isize",    "maximum input size [32, 4096]", "4096");
        cmdline.add("", "min-osize",    "minimum output size [32, 1024]", "1024");
        cmdline.add("", "max-osize",    "maximum output size [32, 4096]", "4096");
        cmdline.add("", "min-count",    "minimum number of samples in minibatch [1, 16]", "1");
        cmdline.add("", "max-count",    "maximum number of samples in minibatch [1, 32]", "16");

        cmdline.process(argc, argv);

        // check arguments and options
        const auto cmd_min_isize = clamp(cmdline.get<int>("min-isize"), 32, 1024);
        const auto cmd_max_isize = clamp(cmdline.get<int>("max-isize"), cmd_min_isize, 4096);
        const auto cmd_min_osize = clamp(cmdline.get<int>("min-osize"), 32, 1024);
        const auto cmd_max_osize = clamp(cmdline.get<int>("max-osize"), cmd_min_osize, 4096);
        const auto cmd_min_count = clamp(cmdline.get<int>("min-count"), 1, 16);
        const auto cmd_max_count = clamp(cmdline.get<int>("max-count"), cmd_min_count, 32);

        table_t table;
        table.header()
                << "" << "" << "" << ""
                << "output" << "ginput" << "gparam"
                << "+naive" << "ginput" << "gparam"
                << "+dmaps" << "ginput" << "gparam"
                << "+dense" << "ginput" << "gparam";

        table.append()
                << "isize" << "config" << "osize" << "#params"
                << "#kflops" << "#kflops" << "#kflops"
                << "gflop/s" << "gflop/s" << "gflop/s"
                << "gflop/s" << "gflop/s" << "gflop/s"
                << "gflop/s" << "gflop/s" << "gflop/s";

        table.append(table_row_t::storage::delim);

        // benchmark for different input-output sizes and number of samples in a minibatch
        for (auto isize = cmd_min_isize; isize <= cmd_max_isize; isize *= 2)
        {
                for (auto osize = cmd_min_osize; osize <= cmd_max_osize; osize *= 2)
                {
                        for (auto count = cmd_min_count; count <= cmd_max_count; count *= 2)
                        {
                                const auto params = affine_params_t{isize, 1, 1, osize, 1, 1};
                                const auto kflops_output = params.flops_output() / 1024;
                                const auto kflops_ginput = params.flops_ginput() / 1024;
                                const auto kflops_gparam = params.flops_gparam() / 1024;

                                const auto config = to_params("dims", osize);

                                auto wdata = params.make_wdata(); wdata.setRandom();
                                auto bdata = params.make_bdata(); bdata.setRandom();
                                auto idata = params.make_idata(count); idata.vector().setRandom();
                                auto odata = params.make_odata(count); odata.vector().setRandom();

                                // 3D implementation
                                auto op3d = affine3d_t{params};
                                const auto gf3d_output = measure_output(op3d, idata, wdata, bdata, odata);
                                const auto gf3d_ginput = measure_ginput(op3d, idata, wdata, bdata, odata);
                                const auto gf3d_gparam = measure_gparam(op3d, idata, wdata, bdata, odata);

                                // 4D implementation
                                auto op4d = affine4d_t{params};
                                const auto gf4d_output = measure_output(op4d, idata, wdata, bdata, odata);
                                const auto gf4d_ginput = measure_ginput(op4d, idata, wdata, bdata, odata);
                                const auto gf4d_gparam = measure_gparam(op4d, idata, wdata, bdata, odata);

                                table.append()
                                        << tensor3d_dims_t{params.imaps(), params.irows(), params.icols()}
                                        << config
                                        << tensor3d_dims_t{params.omaps(), params.orows(), params.ocols()}
                                        << params.psize()
                                        << kflops_output << kflops_ginput << kflops_gparam
                                        << gf3d_output << gf3d_ginput << gf3d_gparam
                                        << gf4d_output << gf4d_ginput << gf4d_gparam;
                        }
                }
        }

        // print results
        std::cout << table;

        // OK
        return EXIT_SUCCESS;
}
<commit_msg>polish benchmark<commit_after>#include "logger.h"
#include "text/table.h"
#include "text/config.h"
#include "math/numeric.h"
#include "text/cmdline.h"
#include "chrono/measure.h"
#include "layers/affine3d.h"
#include "layers/affine4d.h"
#include <iostream>

using namespace nano;

namespace nano
{
        template <typename tvalue>
        string_t serialize_to_string(const tvalue value)
        {
                std::stringstream s;
                s << value;
                return s.str();
        }

        template <> string_t to_string<tensor2d_dims_t>(const tensor2d_dims_t dims) { return serialize_to_string(dims); }
        template <> string_t to_string<tensor3d_dims_t>(const tensor3d_dims_t dims) { return serialize_to_string(dims); }
        template <> string_t to_string<tensor4d_dims_t>(const tensor4d_dims_t dims) { return serialize_to_string(dims); }
}

namespace
{
        const auto trials = size_t(16);

        template <typename top, typename tidata, typename twdata, typename tbdata, typename todata>
        auto measure_output(top& op, const tidata& idata, const twdata& wdata, const tbdata& bdata, todata& odata)
        {
                const auto count = idata.template size<0>();
                const auto duration = measure<nanoseconds_t>([&] () { op.output(idata, wdata, bdata, odata); }, trials);
                return nano::gflops(op.params().flops_output() * count, duration);
        }

        template <typename top, typename tidata, typename twdata, typename tbdata, typename todata>
        auto measure_ginput(top& op, tidata& idata, const twdata& wdata, const tbdata& bdata, const todata& odata)
        {
                const auto count = idata.template size<0>();
                const auto duration = measure<nanoseconds_t>([&] () { op.ginput(idata, wdata, bdata, odata); }, trials);
                return nano::gflops(op.params().flops_ginput() * count, duration);
        }

        template <typename top, typename tidata, typename twdata, typename tbdata, typename todata>
        auto measure_gparam(top& op, const tidata& idata, twdata& wdata, tbdata& bdata, const todata& odata)
        {
                const auto count = idata.template size<0>();
                const auto duration = measure<nanoseconds_t>([&] () { op.gparam(idata, wdata, bdata, odata); }, trials);
                return nano::gflops(op.params().flops_gparam() * count, duration);
        }
}

int main(int argc, const char *argv[])
{
        // parse the command line
        cmdline_t cmdline("benchmark affine operators");
        cmdline.add("", "min-isize",    "minimum input size [32, 1024]", "512");
        cmdline.add("", "max-isize",    "maximum input size [32, 4096]", "1024");
        cmdline.add("", "min-osize",    "minimum output size [32, 1024]", "512");
        cmdline.add("", "max-osize",    "maximum output size [32, 4096]", "1024");
        cmdline.add("", "min-count",    "minimum number of samples in minibatch [1, 16]", "1");
        cmdline.add("", "max-count",    "maximum number of samples in minibatch [1, 64]", "32");

        cmdline.process(argc, argv);

        // check arguments and options
        const auto cmd_min_isize = clamp(cmdline.get<int>("min-isize"), 32, 1024);
        const auto cmd_max_isize = clamp(cmdline.get<int>("max-isize"), cmd_min_isize, 4096);
        const auto cmd_min_osize = clamp(cmdline.get<int>("min-osize"), 32, 1024);
        const auto cmd_max_osize = clamp(cmdline.get<int>("max-osize"), cmd_min_osize, 4096);
        const auto cmd_min_count = clamp(cmdline.get<int>("min-count"), 1, 16);
        const auto cmd_max_count = clamp(cmdline.get<int>("max-count"), cmd_min_count, 64);

        table_t table;
        table.header()
                << "" << "" << "" << ""
                << "output" << "ginput" << "gparam"
                << "+3d" << "ginput" << "gparam"
                << "+4d" << "ginput" << "gparam";

        table.append()
                << "isize" << "config" << "osize" << "#params"
                << "#kflops" << "#kflops" << "#kflops"
                << "gflop/s" << "gflop/s" << "gflop/s"
                << "gflop/s" << "gflop/s" << "gflop/s";

        table.append(table_row_t::storage::delim);

        // benchmark for different input-output sizes and number of samples in a minibatch
        for (auto isize = cmd_min_isize; isize <= cmd_max_isize; isize *= 2)
        {
                for (auto osize = cmd_min_osize; osize <= cmd_max_osize; osize *= 2)
                {
                        for (auto count = cmd_min_count; count <= cmd_max_count; count *= 2)
                        {
                                const auto params = affine_params_t{isize, 1, 1, osize, 1, 1};
                                const auto kflops_output = params.flops_output() / 1024;
                                const auto kflops_ginput = params.flops_ginput() / 1024;
                                const auto kflops_gparam = params.flops_gparam() / 1024;

                                const auto config = to_params("isize", isize, "osize", osize, "count", count);

                                auto wdata = params.make_wdata(); wdata.setRandom();
                                auto bdata = params.make_bdata(); bdata.setRandom();
                                auto idata = params.make_idata(count); idata.vector().setRandom();
                                auto odata = params.make_odata(count); odata.vector().setRandom();

                                // 3D implementation
                                auto op3d = affine3d_t{params};
                                const auto gf3d_output = measure_output(op3d, idata, wdata, bdata, odata);
                                const auto gf3d_ginput = measure_ginput(op3d, idata, wdata, bdata, odata);
                                const auto gf3d_gparam = measure_gparam(op3d, idata, wdata, bdata, odata);

                                // 4D implementation
                                auto op4d = affine4d_t{params};
                                const auto gf4d_output = measure_output(op4d, idata, wdata, bdata, odata);
                                const auto gf4d_ginput = measure_ginput(op4d, idata, wdata, bdata, odata);
                                const auto gf4d_gparam = measure_gparam(op4d, idata, wdata, bdata, odata);

                                table.append()
                                        << tensor3d_dims_t{params.imaps(), params.irows(), params.icols()}
                                        << config
                                        << tensor3d_dims_t{params.omaps(), params.orows(), params.ocols()}
                                        << params.psize()
                                        << kflops_output << kflops_ginput << kflops_gparam
                                        << gf3d_output << gf3d_ginput << gf3d_gparam
                                        << gf4d_output << gf4d_ginput << gf4d_gparam;
                        }

                        if (osize * 2 <= cmd_max_osize)
                        {
                                table.append(table_row_t::storage::delim);
                        }
                }

                if (isize * 2 <= cmd_max_isize)
                {
                        table.append(table_row_t::storage::delim);
                }
        }

        // print results
        std::cout << table;

        // OK
        return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//   Copyright (c) 2003 Stanislav Shwartsman
//          Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
//  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 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; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////

#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR

#if BX_SUPPORT_FPU

#include "softfloatx80.h"

const floatx80 Const_QNaN = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
const floatx80 Const_Z    = packFloatx80(0, 0x0000, 0);
const floatx80 Const_1    = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000));
const floatx80 Const_L2T  = packFloatx80(0, 0x4000, BX_CONST64(0xd49a784bcd1b8afe));
const floatx80 Const_L2E  = packFloatx80(0, 0x3fff, BX_CONST64(0xb8aa3b295c17f0bc));
const floatx80 Const_PI   = packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235));
const floatx80 Const_LG2  = packFloatx80(0, 0x3ffd, BX_CONST64(0x9a209a84fbcff799));
const floatx80 Const_LN2  = packFloatx80(0, 0x3ffe, BX_CONST64(0xb17217f7d1cf79ac));
const floatx80 Const_INF  = packFloatx80(0, 0x7fff, BX_CONST64(0x8000000000000000));

/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP
   (and not one of RC_RND or RC_UP).
   */
#define DOWN_OR_CHOP()  (FPU_CONTROL_WORD & FPU_CW_RC & FPU_RC_DOWN)

BX_CPP_INLINE floatx80 FPU_round_const(const floatx80 &a, int adj)
{
  floatx80 result = a;
  result.fraction += adj;
  return result;
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDL2T(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_L2T, (FPU_CONTROL_WORD == FPU_RC_UP) ? 1 : 0), 0);
  }
#else
  BX_INFO(("FLDL2T: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDL2E(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_L2E, DOWN_OR_CHOP() ? -1 : 0), 0);
  }
#else
  BX_INFO(("FLDL2E: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDPI(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_PI, DOWN_OR_CHOP() ? -1 : 0), 0);
  }
#else
  BX_INFO(("FLDPI: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDLG2(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_LG2, DOWN_OR_CHOP() ? -1 : 0), 0);
  }
#else
  BX_INFO(("FLDLG2: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDLN2(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_LN2, DOWN_OR_CHOP() ? -1 : 0), 0);
  }
#else
  BX_INFO(("FLDLN2: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD1(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(Const_1, 0);
  }
#else
  BX_INFO(("FLD1: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDZ(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(Const_Z, 0);
  }
#else
  BX_INFO(("FLDZ: required FPU, configure --enable-fpu"));
#endif
}

#endif
<commit_msg>Fixed FLDL2T instruction<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//   Copyright (c) 2003 Stanislav Shwartsman
//          Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
//  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 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; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////

#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR

#if BX_SUPPORT_FPU

#include "softfloatx80.h"

const floatx80 Const_QNaN = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
const floatx80 Const_Z    = packFloatx80(0, 0x0000, 0);
const floatx80 Const_1    = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000));
const floatx80 Const_L2T  = packFloatx80(0, 0x4000, BX_CONST64(0xd49a784bcd1b8afe));
const floatx80 Const_L2E  = packFloatx80(0, 0x3fff, BX_CONST64(0xb8aa3b295c17f0bc));
const floatx80 Const_PI   = packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235));
const floatx80 Const_LG2  = packFloatx80(0, 0x3ffd, BX_CONST64(0x9a209a84fbcff799));
const floatx80 Const_LN2  = packFloatx80(0, 0x3ffe, BX_CONST64(0xb17217f7d1cf79ac));
const floatx80 Const_INF  = packFloatx80(0, 0x7fff, BX_CONST64(0x8000000000000000));

/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP
   (and not one of RC_RND or RC_UP).
   */
#define DOWN_OR_CHOP()  (FPU_CONTROL_WORD & FPU_CW_RC & FPU_RC_DOWN)

BX_CPP_INLINE floatx80 FPU_round_const(const floatx80 &a, int adj)
{
  floatx80 result = a;
  result.fraction += adj;
  return result;
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDL2T(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_L2T, (FPU_CONTROL_WORD & FPU_CW_RC) == FPU_RC_UP), 0);
  }
#else
  BX_INFO(("FLDL2T: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDL2E(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_L2E, DOWN_OR_CHOP() ? -1 : 0), 0);
  }
#else
  BX_INFO(("FLDL2E: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDPI(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_PI, DOWN_OR_CHOP() ? -1 : 0), 0);
  }
#else
  BX_INFO(("FLDPI: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDLG2(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_LG2, DOWN_OR_CHOP() ? -1 : 0), 0);
  }
#else
  BX_INFO(("FLDLG2: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDLN2(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(FPU_round_const(Const_LN2, DOWN_OR_CHOP() ? -1 : 0), 0);
  }
#else
  BX_INFO(("FLDLN2: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD1(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(Const_1, 0);
  }
#else
  BX_INFO(("FLD1: required FPU, configure --enable-fpu"));
#endif
}

void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDZ(bxInstruction_c *i)
{
#if BX_SUPPORT_FPU
  BX_CPU_THIS_PTR prepareFPU(i);

  clear_C1();

  if (! IS_TAG_EMPTY(-1))
  {
    BX_CPU_THIS_PTR FPU_stack_overflow();
  }
  else {
    BX_CPU_THIS_PTR the_i387.FPU_push();
    BX_WRITE_FPU_REG(Const_Z, 0);
  }
#else
  BX_INFO(("FLDZ: required FPU, configure --enable-fpu"));
#endif
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_PFR_DETAIL_IO_HPP
#define BOOST_PFR_DETAIL_IO_HPP
#pragma once

#include <boost/pfr/detail/config.hpp>

#include <boost/pfr/detail/sequence_tuple.hpp>
#include <iosfwd>       // stream operators
#include <iomanip>

// Forward declaration
namespace std {
    template <class CharT, class Traits> class basic_string_view;
}

namespace boost { namespace pfr { namespace detail {

inline auto quoted_helper(const std::string& s) noexcept {
    return std::quoted(s);
}

template <class CharT, class Traits>
inline auto quoted_helper(const std::basic_string_view<CharT, Traits>& s) noexcept {
    return std::quoted(s);
}

inline auto quoted_helper(std::string& s) noexcept {
    return std::quoted(s);
}

template <class T>
inline decltype(auto) quoted_helper(T&& v) noexcept {
    return std::forward<T>(v);
}

template <std::size_t I, std::size_t N>
struct print_impl {
    template <class Stream, class T>
    static void print (Stream& out, const T& value) {
        if (!!I) out << ", ";
        out << quoted_helper(boost::pfr::detail::sequence_tuple::get<I>(value));
        print_impl<I + 1, N>::print(out, value);
    }

    template <class Stream, class T>
    static void print (Stream& out, const std::string& value) {
        if (!!I) out << ", ";
        out << std::quoted( boost::pfr::detail::sequence_tuple::get<I>(value) );
        print_impl<I + 1, N>::print(out, value);
    }
};

template <std::size_t I>
struct print_impl<I, I> {
    template <class Stream, class T> static void print (Stream&, const T&) noexcept {}
};

template <std::size_t I, std::size_t N>
struct read_impl {
    template <class Stream, class T>
    static void read (Stream& in, const T& value) {
        char ignore = {};
        if (!!I) {
            in >> ignore;
            if (ignore != ',') in.setstate(Stream::failbit);
            in >> ignore;
            if (ignore != ' ')  in.setstate(Stream::failbit);
        }
        in >> quoted_helper( boost::pfr::detail::sequence_tuple::get<I>(value) );
        read_impl<I + 1, N>::read(in, value);
    }
};

template <std::size_t I>
struct read_impl<I, I> {
    template <class Stream, class T> static void read (Stream&, const T&) {}
};

}}} // namespace boost::pfr::detail

#endif // BOOST_PFR_DETAIL_IO_HPP
<commit_msg>fixed magic_get fuckup (forward declaration of std::string_view)<commit_after>// Copyright (c) 2016-2017 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_PFR_DETAIL_IO_HPP
#define BOOST_PFR_DETAIL_IO_HPP
#pragma once

#include <boost/pfr/detail/config.hpp>

#include <boost/pfr/detail/sequence_tuple.hpp>
#include <iosfwd>       // stream operators
#include <iomanip>
#include <string_view>

// Forward declaration
// namespace std {
//      template <class CharT, class Traits> class basic_string_view;
// }

namespace boost { namespace pfr { namespace detail {

inline auto quoted_helper(const std::string& s) noexcept {
    return std::quoted(s);
}

template <class CharT, class Traits>
inline auto quoted_helper(const std::basic_string_view<CharT, Traits>& s) noexcept {
    return std::quoted(s);
}

inline auto quoted_helper(std::string& s) noexcept {
    return std::quoted(s);
}

template <class T>
inline decltype(auto) quoted_helper(T&& v) noexcept {
    return std::forward<T>(v);
}

template <std::size_t I, std::size_t N>
struct print_impl {
    template <class Stream, class T>
    static void print (Stream& out, const T& value) {
        if (!!I) out << ", ";
        out << quoted_helper(boost::pfr::detail::sequence_tuple::get<I>(value));
        print_impl<I + 1, N>::print(out, value);
    }

    template <class Stream, class T>
    static void print (Stream& out, const std::string& value) {
        if (!!I) out << ", ";
        out << std::quoted( boost::pfr::detail::sequence_tuple::get<I>(value) );
        print_impl<I + 1, N>::print(out, value);
    }
};

template <std::size_t I>
struct print_impl<I, I> {
    template <class Stream, class T> static void print (Stream&, const T&) noexcept {}
};

template <std::size_t I, std::size_t N>
struct read_impl {
    template <class Stream, class T>
    static void read (Stream& in, const T& value) {
        char ignore = {};
        if (!!I) {
            in >> ignore;
            if (ignore != ',') in.setstate(Stream::failbit);
            in >> ignore;
            if (ignore != ' ')  in.setstate(Stream::failbit);
        }
        in >> quoted_helper( boost::pfr::detail::sequence_tuple::get<I>(value) );
        read_impl<I + 1, N>::read(in, value);
    }
};

template <std::size_t I>
struct read_impl<I, I> {
    template <class Stream, class T> static void read (Stream&, const T&) {}
};

}}} // namespace boost::pfr::detail

#endif // BOOST_PFR_DETAIL_IO_HPP
<|endoftext|>


<commit_before>#include "binary_codec.h"

#include "memcache_client.h"

namespace evmc {

static const size_t kHeaderLen = sizeof(protocol_binary_response_header);

void BinaryCodec::OnCodecMessage(const evpp::TCPConnPtr& conn,
                                 evpp::Buffer* buf) {
    while (buf->size() >= kHeaderLen) { // kHeaderLen == 24
        const void* data = buf->data();
        protocol_binary_response_header resp =
            *static_cast<const protocol_binary_response_header*>(data);
        resp.response.bodylen = ntohl(resp.response.bodylen);
        resp.response.status  = ntohs(resp.response.status);
        resp.response.keylen  = ntohs(resp.response.keylen);

        if (buf->size() >= resp.response.bodylen + kHeaderLen) {
            OnResponsePacket(resp, buf);
        } else {
            LOG_TRACE << "need recv more data";
            break;
        }
    }
}

void BinaryCodec::DecodePrefixGetPacket(const protocol_binary_response_header& resp,
                                        evpp::Buffer* buf, PrefixGetResultPtr& ptr) {
    const char* pv = buf->data() + sizeof(resp) + resp.response.extlen;
    uint32_t pos = resp.response.keylen;
    uint32_t klen = 0;
    uint32_t vlen = 0;
    const uint32_t size = resp.response.bodylen - resp.response.keylen - resp.response.extlen;
    const uint32_t buf_size = buf->size();
    int ret = resp.response.status;
    ptr->code = ret;
    while (pos < size) {
        if (pos >= buf_size || pos + 4 >= buf_size) {
            break;
        }
        klen = ntohl((*(const uint32_t*)(pv + pos)));
        pos += 4;
        if ((pos + klen) >= buf_size) {
            break;
        }
        std::string rkey(pv + pos, klen);
        pos += klen;
        if (pos >= buf_size || pos + 4 >= buf_size) {
            break;
        }
        vlen = ntohl(*(const uint32_t*)(pv + pos));
        pos += 4;
        if ((pos + vlen) >= buf_size) {
            break;
        }

        std::string rval(pv + pos, vlen);
        ptr->result_map_.emplace(rkey, rval);
        pos += vlen;
    }
}

void BinaryCodec::OnResponsePacket(const protocol_binary_response_header& resp,
                                   evpp::Buffer* buf) {
    uint32_t id  = resp.response.opaque;  // no need to call ntohl
    int opcode = resp.response.opcode;
    CommandPtr cmd = memc_client_->PeekRunningCommand();
    if (!cmd || id != cmd->id()) {
        // TODO : id 不一致时候，如何处理?
        buf->Retrieve(kHeaderLen + resp.response.bodylen);
        LOG_WARN << "OnResponsePacket cmd/message mismatch." << id;
        return;
    }

    switch (opcode) {
    case PROTOCOL_BINARY_CMD_SET:
        cmd = memc_client_->PopRunningCommand();
        cmd->OnSetCommandDone(resp.response.status);
        LOG_DEBUG << "OnResponsePacket SET, opaque=" << id;
        break;

    case PROTOCOL_BINARY_CMD_DELETE:
        cmd = memc_client_->PopRunningCommand();
        cmd->OnRemoveCommandDone(resp.response.status);
        LOG_DEBUG << "OnResponsePacket DELETE, opaque=" << id;
        break;

    case PROTOCOL_BINARY_CMD_GET: {
        cmd = memc_client_->PopRunningCommand();
        const char* pv = buf->data() + sizeof(resp) + resp.response.extlen;
        std::string value(pv, resp.response.bodylen - resp.response.extlen);
        cmd->OnGetCommandDone(resp.response.status, value);
        LOG_DEBUG << "OnResponsePacket GET, opaque=" << id;
    }
    break;

    case PROTOCOL_BINARY_CMD_GETK: {
        cmd = memc_client_->PopRunningCommand();
        const int extlen_getk = resp.response.extlen;
        const int keylen_getk = resp.response.keylen;
        const char* pv = buf->data() + sizeof(resp) + extlen_getk;
        std::string key(pv, keylen_getk);
        std::string value(pv + keylen_getk, resp.response.bodylen - keylen_getk - extlen_getk);

        cmd->OnMultiGetCommandDone(resp.response.status, key, value);
        LOG_DEBUG << "OnResponsePacket MULTIGETK, opaque=" << id;
    }
    break;

    case PROTOCOL_BINARY_CMD_GETKQ: {
        const int extlen = resp.response.extlen;
        const int keylen = resp.response.keylen;
        const char* pv = buf->data() + sizeof(resp) + extlen;
        std::string key(pv, keylen);
        std::string value(pv + keylen, resp.response.bodylen - keylen - extlen);

        cmd->OnMultiGetCommandOneResponse(resp.response.status, key, value);
        LOG_DEBUG << "OnResponsePacket MULTIGETQ, opaque=" << id;
    }
    break;

    case PROTOCOL_BINARY_CMD_PGETK: {
        cmd = memc_client_->PopRunningCommand();
        const char* pv = buf->data() + sizeof(resp) + resp.response.extlen;
        std::string key(pv, resp.response.keylen);
        if (!key.empty()) {
            auto result_ptr = cmd->GetResultContainerByKey(key);
            DecodePrefixGetPacket(resp, buf, result_ptr);
            cmd->OnPrefixGetCommandDone();
            LOG_DEBUG << "OnResponsePacket PGETK, opaque=" << id;
        } else {
            cmd->OnError(resp.response.status);
        }
    }
    break;

    case PROTOCOL_BINARY_CMD_PGETKQ: {
        const char* pv = buf->data() + sizeof(resp) + resp.response.extlen;
        std::string key(pv, resp.response.keylen);
        if (!key.empty()) {
            auto result_ptr = cmd->GetResultContainerByKey(key);
            DecodePrefixGetPacket(resp, buf, result_ptr);
            LOG_DEBUG << "OnResponsePacket PGETKQ" << id;
        } else {
            cmd->OnError(resp.response.status);
        }
    }
    break;

    case PROTOCOL_BINARY_CMD_NOOP:
        LOG_DEBUG << "GETQ, NOOP opaque=" << id;
        //memc_client_->onMultiGetCommandDone(id, resp.response.status);
        break;
    default:
        break;
    }
    buf->Retrieve(kHeaderLen + resp.response.bodylen);
}

}
<commit_msg>if recv prefix multiget error, quick return;<commit_after>#include "binary_codec.h"

#include "memcache_client.h"

namespace evmc {

static const size_t kHeaderLen = sizeof(protocol_binary_response_header);

void BinaryCodec::OnCodecMessage(const evpp::TCPConnPtr& conn,
                                 evpp::Buffer* buf) {
    while (buf->size() >= kHeaderLen) { // kHeaderLen == 24
        const void* data = buf->data();
        protocol_binary_response_header resp =
            *static_cast<const protocol_binary_response_header*>(data);
        resp.response.bodylen = ntohl(resp.response.bodylen);
        resp.response.status  = ntohs(resp.response.status);
        resp.response.keylen  = ntohs(resp.response.keylen);

        if (buf->size() >= resp.response.bodylen + kHeaderLen) {
            OnResponsePacket(resp, buf);
        } else {
            LOG_TRACE << "need recv more data";
            break;
        }
    }
}

void BinaryCodec::DecodePrefixGetPacket(const protocol_binary_response_header& resp,
                                        evpp::Buffer* buf, PrefixGetResultPtr& ptr) {
    const char* pv = buf->data() + sizeof(resp) + resp.response.extlen;
    uint32_t pos = resp.response.keylen;
    uint32_t klen = 0;
    uint32_t vlen = 0;
    const uint32_t size = resp.response.bodylen - resp.response.keylen - resp.response.extlen;
    const uint32_t buf_size = buf->size();
    int ret = resp.response.status;
    ptr->code = ret;
    if (ret != (int)PROTOCOL_BINARY_RESPONSE_SUCCESS) {
        return;
    }
    while (pos < size) {
        if (pos >= buf_size || pos + 4 >= buf_size) {
            break;
        }
        klen = ntohl((*(const uint32_t*)(pv + pos)));
        pos += 4;
        if ((pos + klen) >= buf_size) {
            break;
        }
        std::string rkey(pv + pos, klen);
        pos += klen;
        if (pos >= buf_size || pos + 4 >= buf_size) {
            break;
        }
        vlen = ntohl(*(const uint32_t*)(pv + pos));
        pos += 4;
        if ((pos + vlen) >= buf_size) {
            break;
        }

        std::string rval(pv + pos, vlen);
        ptr->result_map_.emplace(rkey, rval);
        pos += vlen;
    }
}

void BinaryCodec::OnResponsePacket(const protocol_binary_response_header& resp,
                                   evpp::Buffer* buf) {
    uint32_t id  = resp.response.opaque;  // no need to call ntohl
    int opcode = resp.response.opcode;
    CommandPtr cmd = memc_client_->PeekRunningCommand();
    if (!cmd || id != cmd->id()) {
        // TODO : id 不一致时候，如何处理?
        buf->Retrieve(kHeaderLen + resp.response.bodylen);
        LOG_WARN << "OnResponsePacket cmd/message mismatch." << id;
        return;
    }

    switch (opcode) {
    case PROTOCOL_BINARY_CMD_SET:
        cmd = memc_client_->PopRunningCommand();
        cmd->OnSetCommandDone(resp.response.status);
        LOG_DEBUG << "OnResponsePacket SET, opaque=" << id;
        break;

    case PROTOCOL_BINARY_CMD_DELETE:
        cmd = memc_client_->PopRunningCommand();
        cmd->OnRemoveCommandDone(resp.response.status);
        LOG_DEBUG << "OnResponsePacket DELETE, opaque=" << id;
        break;

    case PROTOCOL_BINARY_CMD_GET: {
        cmd = memc_client_->PopRunningCommand();
        const char* pv = buf->data() + sizeof(resp) + resp.response.extlen;
        std::string value(pv, resp.response.bodylen - resp.response.extlen);
        cmd->OnGetCommandDone(resp.response.status, value);
        LOG_DEBUG << "OnResponsePacket GET, opaque=" << id;
    }
    break;

    case PROTOCOL_BINARY_CMD_GETK: {
        cmd = memc_client_->PopRunningCommand();
        const int extlen_getk = resp.response.extlen;
        const int keylen_getk = resp.response.keylen;
        const char* pv = buf->data() + sizeof(resp) + extlen_getk;
        std::string key(pv, keylen_getk);
        std::string value(pv + keylen_getk, resp.response.bodylen - keylen_getk - extlen_getk);

        cmd->OnMultiGetCommandDone(resp.response.status, key, value);
        LOG_DEBUG << "OnResponsePacket MULTIGETK, opaque=" << id;
    }
    break;

    case PROTOCOL_BINARY_CMD_GETKQ: {
        const int extlen = resp.response.extlen;
        const int keylen = resp.response.keylen;
        const char* pv = buf->data() + sizeof(resp) + extlen;
        std::string key(pv, keylen);
        std::string value(pv + keylen, resp.response.bodylen - keylen - extlen);

        cmd->OnMultiGetCommandOneResponse(resp.response.status, key, value);
        LOG_DEBUG << "OnResponsePacket MULTIGETQ, opaque=" << id;
    }
    break;

    case PROTOCOL_BINARY_CMD_PGETK: {
        cmd = memc_client_->PopRunningCommand();
        const char* pv = buf->data() + sizeof(resp) + resp.response.extlen;
        std::string key(pv, resp.response.keylen);
        if (!key.empty()) {
            auto result_ptr = cmd->GetResultContainerByKey(key);
            DecodePrefixGetPacket(resp, buf, result_ptr);
            cmd->OnPrefixGetCommandDone();
            LOG_DEBUG << "OnResponsePacket PGETK, opaque=" << id;
        } else {
            cmd->OnError(resp.response.status);
        }
    }
    break;

    case PROTOCOL_BINARY_CMD_PGETKQ: {
        const char* pv = buf->data() + sizeof(resp) + resp.response.extlen;
        std::string key(pv, resp.response.keylen);
        if (!key.empty()) {
            auto result_ptr = cmd->GetResultContainerByKey(key);
            DecodePrefixGetPacket(resp, buf, result_ptr);
            LOG_DEBUG << "OnResponsePacket PGETKQ" << id;
        } else {
            cmd->OnError(resp.response.status);
        }
    }
    break;

    case PROTOCOL_BINARY_CMD_NOOP:
        LOG_DEBUG << "GETQ, NOOP opaque=" << id;
        //memc_client_->onMultiGetCommandDone(id, resp.response.status);
        break;
    default:
        break;
    }
    buf->Retrieve(kHeaderLen + resp.response.bodylen);
}

}
<|endoftext|>


<commit_before>/*
 * Ascent MMORPG Server
 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "StdAfx.h"

void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{
	if(!_player->IsInWorld()) return;
	typedef std::list<Aura*> AuraList;

	Player* p_User = GetPlayer();
	sLog.outDetail("WORLD: got use Item packet, data length = %i",recvPacket.size());
	int8 tmp1,slot,tmp3;
	uint8 cn;
	uint32 spellId = 0;

	recvPacket >> tmp1 >> slot >> tmp3 >> cn;
	Item* tmpItem = NULL;
	tmpItem = p_User->GetItemInterface()->GetInventoryItem(tmp1,slot);
	if (!tmpItem)
		tmpItem = p_User->GetItemInterface()->GetInventoryItem(slot);
	if (!tmpItem)
		return;
	ItemPrototype *itemProto = tmpItem->GetProto();
	if(!itemProto)
		return;

	if(!_player->isDead())
		return;

	if(itemProto->Bonding == ITEM_BIND_ON_USE)
		tmpItem->SoulBind();

	if(sScriptMgr.CallScriptedItem(tmpItem,_player))
		return;

	if(itemProto->QuestId)
	{
		// Item Starter
		Quest *qst = QuestStorage.LookupEntry(itemProto->QuestId);
		if(!qst)
			return;

        WorldPacket data;
        sQuestMgr.BuildQuestDetails(&data, qst, tmpItem, 0, language);
		SendPacket(&data);
	}

	SpellCastTargets targets(recvPacket, _player->GetGUID());
	uint32 x;
	for(x = 0; x < 5; x++)
	{
		if(itemProto->Spells[x].Trigger == USE)
		{
			if(itemProto->Spells[x].Id)
			{
				spellId = itemProto->Spells[x].Id;
				break;
			}
		}
	}
	if(!spellId)
		return;
	// check for spell id
	SpellEntry *spellInfo = dbcSpell.LookupEntryForced( spellId );

	if(!spellInfo)
	{
		sLog.outError("WORLD: unknown spell id %i\n", spellId);
		return;
	}

	if (spellInfo->AuraInterruptFlags & AURA_INTERRUPT_ON_STAND_UP)
	{
		if (p_User->CombatStatus.IsInCombat())
		{
			_player->GetItemInterface()->BuildInventoryChangeError(tmpItem,NULL,INV_ERR_CANT_DO_IN_COMBAT);
			return;
		}
		if(p_User->GetStandState()!=1)
		p_User->SetStandState(STANDSTATE_SIT);
		// loop through the auras and removing existing eating spells
	}

	if(itemProto->RequiredSkill)
	{
		if(!_player->_HasSkillLine(itemProto->RequiredSkill))
		{
			_player->GetItemInterface()->BuildInventoryChangeError(tmpItem,NULL,INV_ERR_ITEM_RANK_NOT_ENOUGH);
			return;
		}

		if(itemProto->RequiredSkillRank)
		{
			if(_player->_GetSkillLineCurrent(itemProto->RequiredSkill, false) < itemProto->RequiredSkillRank)
			{
				_player->GetItemInterface()->BuildInventoryChangeError(tmpItem,NULL,INV_ERR_ITEM_RANK_NOT_ENOUGH);
				return;
			}
		}
	}

	if(!_player->CanCastItemDueToCooldown(itemProto, x))	// damn cheaters
		return;

	if(itemProto->Spells[x].Cooldown || itemProto->Spells[x].CategoryCooldown)
	{
		ItemCooldown * item = new ItemCooldown;
	   	if(itemProto->Spells[x].Id)
		{
			if(itemProto->Spells[x].Trigger == USE)
			{
				item->ItemEntry = itemProto->ItemId;
				item->SpellID = spellId;
				item->SpellCategory = itemProto->Spells[x].Category;
				if(itemProto->Spells[x].Category)
				{
					item->Cooldown = itemProto->Spells[x].CategoryCooldown;
					item->CooldownTimeStamp = now() + itemProto->Spells[x].CategoryCooldown;
				}
				else
				{
					item->Cooldown = itemProto->Spells[x].Cooldown;
					item->CooldownTimeStamp = now() + itemProto->Spells[x].Cooldown;
				}
			}
		}
		_player->m_itemcooldown.insert(item);
	}

	Spell *spell = new Spell(_player, spellInfo, false, NULL);
	spell->extra_cast_number=cn;
	spell->i_caster = tmpItem;
	//GetPlayer()->setCurrentSpell(spell);
	spell->prepare(&targets);
}

void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
{
	if(!_player->IsInWorld()) return;
	if(!_player->isDead())
		return;

	uint32 spellId;
	uint8 cn;

	recvPacket >> spellId >> cn;

	sLog.outDetail("WORLD: got cast spell packet, spellId - %i, data length = %i",
		spellId, recvPacket.size());

	// Cheat Detection only if player and not from an item
	// this could fuck up things but meh it's needed ALOT of the newbs are using WPE now
	// WPE allows them to mod the outgoing packet and basicly choose what ever spell they want :(

	if( !GetPlayer()->HasSpell(spellId) )
	{
		sLog.outDetail("WORLD: Spell isn't casted because player \"%s\" is cheating", GetPlayer()->GetName());
		return;
	}

	if (GetPlayer()->GetOnMeleeSpell() != spellId)
	{
		// check for spell id
		SpellEntry *spellInfo = dbcSpell.LookupEntryForced(spellId );

		if(!spellInfo || !sHookInterface.OnCastSpell(_player, spellInfo))
		{
			sLog.outError("WORLD: unknown spell id %i\n", spellId);
			return;
		}
		//autoshot 75
		if((spellInfo->Flags3 & FLAGS3_ACTIVATE_AUTO_SHOT) /*spellInfo->Attributes == 327698*/)	// auto shot..
		{
			Item *weapon = GetPlayer()->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED);
			if(!weapon)
				return;
			uint32 spellid;
			switch(weapon->GetProto()->SubClass)
			{
			case 2:			 // bows
			case 3:			 // guns
            case 18:		 // crossbow
				spellid = SPELL_RANGED_GENERAL;
				break;
			case 16:			// thrown
				spellid = SPELL_RANGED_THROW;
				break;
			case 19:			// wands
				spellid = SPELL_RANGED_WAND;
				break;
			default:
				spellid = 0;
				break;
			}

			if(!spellid)
				spellid = spellInfo->Id;

			if(!_player->m_onAutoShot)
			{
				if(_player->IsMounted())
				{
                    _player->SendCastResult(spellInfo->Id, SPELL_FAILED_NOT_MOUNTED, 0);
					return;
				}
				_player->m_AutoShotStartX = _player->GetPositionX();
				_player->m_AutoShotStartY = _player->GetPositionY();
				_player->m_AutoShotStartZ = _player->GetPositionZ();
				_player->m_AutoShotTarget = _player->GetSelection();
				uint32 duration = _player->GetUInt32Value(UNIT_FIELD_RANGEDATTACKTIME);
				SpellCastTargets targets(recvPacket,GetPlayer()->GetGUID());
				if(!targets.m_unitTarget)
					return;
				SpellEntry *sp = dbcSpell.LookupEntry(spellid);

				_player->m_AutoShotSpell = sp;
				_player->m_AutoShotDuration = duration;
				//This will fix fast clicks
				if(_player->m_AutoShotAttackTimer < 500)
					_player->m_AutoShotAttackTimer = 500;
				_player->m_onAutoShot = true;
			}

			return;
		}
		/*const char * name = sSpellStore.LookupString(spellInfo->Name);
		if(name)
			sChatHandler.SystemMessageToPlr(_player, "%sSpell Cast:%s %s %s[Group %u, family %u]", MSG_COLOR_LIGHTBLUE,
			MSG_COLOR_SUBWHITE, name, MSG_COLOR_YELLOW, spellInfo->SpellGroupType, spellInfo->SpellFamilyName);*/

        if(GetPlayer()->m_currentSpell && GetCastTime(dbcSpellCastTime.LookupEntry(spellInfo->CastingTimeIndex)))
        {
            _player->SendCastResult(spellInfo->Id, SPELL_FAILED_SPELL_IN_PROGRESS, 0);
            return;
        }
		Spell *spell = new Spell(GetPlayer(), spellInfo, false, NULL);
		spell->extra_cast_number=cn;

		SpellCastTargets targets(recvPacket,GetPlayer()->GetGUID());
		spell->prepare(&targets);
	}
}

void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket)
{
	uint32 spellId;
	recvPacket >> spellId;

	if(GetPlayer()->m_currentSpell)
		GetPlayer()->m_currentSpell->cancel();
}

void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
{
	uint32 spellId;
	recvPacket >> spellId;

	for(uint32 x = 0; x < MAX_AURAS+MAX_POSITIVE_AURAS; ++x)
	{
		if(_player->m_auras[x] && _player->m_auras[x]->IsPositive() && _player->m_auras[x]->GetSpellId() == spellId)
			_player->m_auras[x]->Remove();
	}
	sLog.outDebug("removing aura %u",spellId);
}

void WorldSession::HandleCancelChannellingOpcode( WorldPacket& recvPacket)
{
	uint32 spellId;
	recvPacket >> spellId;

	Player *plyr = GetPlayer();
	if(!plyr)
		return;
	if(plyr->m_currentSpell)
	{
		plyr->m_currentSpell->cancel();
	}
}

void WorldSession::HandleCancelAutoRepeatSpellOpcode(WorldPacket& recv_data)
{
	//sLog.outString("Received CMSG_CANCEL_AUTO_REPEAT_SPELL message.");
	//on original we automatically enter combat when creature got close to us
//	GetPlayer()->GetSession()->OutPacket(SMSG_CANCEL_COMBAT);
	GetPlayer()->m_onAutoShot = false;
}

void WorldSession::HandleAddDynamicTargetOpcode(WorldPacket & recvPacket)
{
	uint64 guid;
	uint32 spellid;
	uint8 flags;
	recvPacket >> guid >> spellid >> flags;

	SpellEntry * sp = dbcSpell.LookupEntry(spellid);
	// Summoned Elemental's Freeze
    if (spellid == 33395)
    {
        if (!_player->m_Summon)
            return;
    }
    else if (!_player->m_CurrentCharm || guid != _player->m_CurrentCharm->GetGUID())
    {
        return;
    }

	/* burlex: this is.. strange */
	SpellCastTargets targets;
	targets.m_targetMask = flags;

	if(flags == 0)
		targets.m_unitTarget = guid;
	else if(flags == 0x02)
	{
		WoWGuid guid;
		recvPacket >> flags;		// skip one byte
		recvPacket >> guid;
		targets.m_unitTarget = guid.GetOldGuid();
	}
	else if(flags == 0x40)
	{
		recvPacket >> flags;		// skip one byte
		recvPacket >> targets.m_destX >> targets.m_destY >> targets.m_destZ;
	}
	if(spellid == 33395)	// Summoned Water Elemental's freeze
	{
		Spell * pSpell = new Spell(_player->m_Summon, sp, false, 0);
		pSpell->prepare(&targets);
	}
	else			// trinket?
	{
		Spell * pSpell = new Spell(_player->m_CurrentCharm, sp, false, 0);
		pSpell->prepare(&targets);
	}
}
<commit_msg>* urgh, logic errors<commit_after>/*
 * Ascent MMORPG Server
 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "StdAfx.h"

void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{
	if(!_player->IsInWorld()) return;
	typedef std::list<Aura*> AuraList;

	Player* p_User = GetPlayer();
	sLog.outDetail("WORLD: got use Item packet, data length = %i",recvPacket.size());
	int8 tmp1,slot,tmp3;
	uint8 cn;
	uint32 spellId = 0;

	recvPacket >> tmp1 >> slot >> tmp3 >> cn;
	Item* tmpItem = NULL;
	tmpItem = p_User->GetItemInterface()->GetInventoryItem(tmp1,slot);
	if (!tmpItem)
		tmpItem = p_User->GetItemInterface()->GetInventoryItem(slot);
	if (!tmpItem)
		return;
	ItemPrototype *itemProto = tmpItem->GetProto();
	if(!itemProto)
		return;

	if(_player->isDead())
		return;

	if(itemProto->Bonding == ITEM_BIND_ON_USE)
		tmpItem->SoulBind();

	if(sScriptMgr.CallScriptedItem(tmpItem,_player))
		return;

	if(itemProto->QuestId)
	{
		// Item Starter
		Quest *qst = QuestStorage.LookupEntry(itemProto->QuestId);
		if(!qst)
			return;

        WorldPacket data;
        sQuestMgr.BuildQuestDetails(&data, qst, tmpItem, 0, language);
		SendPacket(&data);
	}

	SpellCastTargets targets(recvPacket, _player->GetGUID());
	uint32 x;
	for(x = 0; x < 5; x++)
	{
		if(itemProto->Spells[x].Trigger == USE)
		{
			if(itemProto->Spells[x].Id)
			{
				spellId = itemProto->Spells[x].Id;
				break;
			}
		}
	}
	if(!spellId)
		return;
	// check for spell id
	SpellEntry *spellInfo = dbcSpell.LookupEntryForced( spellId );

	if(!spellInfo)
	{
		sLog.outError("WORLD: unknown spell id %i\n", spellId);
		return;
	}

	if (spellInfo->AuraInterruptFlags & AURA_INTERRUPT_ON_STAND_UP)
	{
		if (p_User->CombatStatus.IsInCombat())
		{
			_player->GetItemInterface()->BuildInventoryChangeError(tmpItem,NULL,INV_ERR_CANT_DO_IN_COMBAT);
			return;
		}
		if(p_User->GetStandState()!=1)
		p_User->SetStandState(STANDSTATE_SIT);
		// loop through the auras and removing existing eating spells
	}

	if(itemProto->RequiredSkill)
	{
		if(!_player->_HasSkillLine(itemProto->RequiredSkill))
		{
			_player->GetItemInterface()->BuildInventoryChangeError(tmpItem,NULL,INV_ERR_ITEM_RANK_NOT_ENOUGH);
			return;
		}

		if(itemProto->RequiredSkillRank)
		{
			if(_player->_GetSkillLineCurrent(itemProto->RequiredSkill, false) < itemProto->RequiredSkillRank)
			{
				_player->GetItemInterface()->BuildInventoryChangeError(tmpItem,NULL,INV_ERR_ITEM_RANK_NOT_ENOUGH);
				return;
			}
		}
	}

	if(!_player->CanCastItemDueToCooldown(itemProto, x))	// damn cheaters
		return;

	if(itemProto->Spells[x].Cooldown || itemProto->Spells[x].CategoryCooldown)
	{
		ItemCooldown * item = new ItemCooldown;
	   	if(itemProto->Spells[x].Id)
		{
			if(itemProto->Spells[x].Trigger == USE)
			{
				item->ItemEntry = itemProto->ItemId;
				item->SpellID = spellId;
				item->SpellCategory = itemProto->Spells[x].Category;
				if(itemProto->Spells[x].Category)
				{
					item->Cooldown = itemProto->Spells[x].CategoryCooldown;
					item->CooldownTimeStamp = now() + itemProto->Spells[x].CategoryCooldown;
				}
				else
				{
					item->Cooldown = itemProto->Spells[x].Cooldown;
					item->CooldownTimeStamp = now() + itemProto->Spells[x].Cooldown;
				}
			}
		}
		_player->m_itemcooldown.insert(item);
	}

	Spell *spell = new Spell(_player, spellInfo, false, NULL);
	spell->extra_cast_number=cn;
	spell->i_caster = tmpItem;
	//GetPlayer()->setCurrentSpell(spell);
	spell->prepare(&targets);
}

void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
{
	if(!_player->IsInWorld()) return;
	if(_player->isDead())
		return;

	uint32 spellId;
	uint8 cn;

	recvPacket >> spellId >> cn;

	sLog.outDetail("WORLD: got cast spell packet, spellId - %i, data length = %i",
		spellId, recvPacket.size());

	// Cheat Detection only if player and not from an item
	// this could fuck up things but meh it's needed ALOT of the newbs are using WPE now
	// WPE allows them to mod the outgoing packet and basicly choose what ever spell they want :(

	if( !GetPlayer()->HasSpell(spellId) )
	{
		sLog.outDetail("WORLD: Spell isn't casted because player \"%s\" is cheating", GetPlayer()->GetName());
		return;
	}

	if (GetPlayer()->GetOnMeleeSpell() != spellId)
	{
		// check for spell id
		SpellEntry *spellInfo = dbcSpell.LookupEntryForced(spellId );

		if(!spellInfo || !sHookInterface.OnCastSpell(_player, spellInfo))
		{
			sLog.outError("WORLD: unknown spell id %i\n", spellId);
			return;
		}
		//autoshot 75
		if((spellInfo->Flags3 & FLAGS3_ACTIVATE_AUTO_SHOT) /*spellInfo->Attributes == 327698*/)	// auto shot..
		{
			Item *weapon = GetPlayer()->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED);
			if(!weapon)
				return;
			uint32 spellid;
			switch(weapon->GetProto()->SubClass)
			{
			case 2:			 // bows
			case 3:			 // guns
            case 18:		 // crossbow
				spellid = SPELL_RANGED_GENERAL;
				break;
			case 16:			// thrown
				spellid = SPELL_RANGED_THROW;
				break;
			case 19:			// wands
				spellid = SPELL_RANGED_WAND;
				break;
			default:
				spellid = 0;
				break;
			}

			if(!spellid)
				spellid = spellInfo->Id;

			if(!_player->m_onAutoShot)
			{
				if(_player->IsMounted())
				{
                    _player->SendCastResult(spellInfo->Id, SPELL_FAILED_NOT_MOUNTED, 0);
					return;
				}
				_player->m_AutoShotStartX = _player->GetPositionX();
				_player->m_AutoShotStartY = _player->GetPositionY();
				_player->m_AutoShotStartZ = _player->GetPositionZ();
				_player->m_AutoShotTarget = _player->GetSelection();
				uint32 duration = _player->GetUInt32Value(UNIT_FIELD_RANGEDATTACKTIME);
				SpellCastTargets targets(recvPacket,GetPlayer()->GetGUID());
				if(!targets.m_unitTarget)
					return;
				SpellEntry *sp = dbcSpell.LookupEntry(spellid);

				_player->m_AutoShotSpell = sp;
				_player->m_AutoShotDuration = duration;
				//This will fix fast clicks
				if(_player->m_AutoShotAttackTimer < 500)
					_player->m_AutoShotAttackTimer = 500;
				_player->m_onAutoShot = true;
			}

			return;
		}
		/*const char * name = sSpellStore.LookupString(spellInfo->Name);
		if(name)
			sChatHandler.SystemMessageToPlr(_player, "%sSpell Cast:%s %s %s[Group %u, family %u]", MSG_COLOR_LIGHTBLUE,
			MSG_COLOR_SUBWHITE, name, MSG_COLOR_YELLOW, spellInfo->SpellGroupType, spellInfo->SpellFamilyName);*/

        if(GetPlayer()->m_currentSpell && GetCastTime(dbcSpellCastTime.LookupEntry(spellInfo->CastingTimeIndex)))
        {
            _player->SendCastResult(spellInfo->Id, SPELL_FAILED_SPELL_IN_PROGRESS, 0);
            return;
        }
		Spell *spell = new Spell(GetPlayer(), spellInfo, false, NULL);
		spell->extra_cast_number=cn;

		SpellCastTargets targets(recvPacket,GetPlayer()->GetGUID());
		spell->prepare(&targets);
	}
}

void WorldSession::HandleCancelCastOpcode(WorldPacket& recvPacket)
{
	uint32 spellId;
	recvPacket >> spellId;

	if(GetPlayer()->m_currentSpell)
		GetPlayer()->m_currentSpell->cancel();
}

void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
{
	uint32 spellId;
	recvPacket >> spellId;

	for(uint32 x = 0; x < MAX_AURAS+MAX_POSITIVE_AURAS; ++x)
	{
		if(_player->m_auras[x] && _player->m_auras[x]->IsPositive() && _player->m_auras[x]->GetSpellId() == spellId)
			_player->m_auras[x]->Remove();
	}
	sLog.outDebug("removing aura %u",spellId);
}

void WorldSession::HandleCancelChannellingOpcode( WorldPacket& recvPacket)
{
	uint32 spellId;
	recvPacket >> spellId;

	Player *plyr = GetPlayer();
	if(!plyr)
		return;
	if(plyr->m_currentSpell)
	{
		plyr->m_currentSpell->cancel();
	}
}

void WorldSession::HandleCancelAutoRepeatSpellOpcode(WorldPacket& recv_data)
{
	//sLog.outString("Received CMSG_CANCEL_AUTO_REPEAT_SPELL message.");
	//on original we automatically enter combat when creature got close to us
//	GetPlayer()->GetSession()->OutPacket(SMSG_CANCEL_COMBAT);
	GetPlayer()->m_onAutoShot = false;
}

void WorldSession::HandleAddDynamicTargetOpcode(WorldPacket & recvPacket)
{
	uint64 guid;
	uint32 spellid;
	uint8 flags;
	recvPacket >> guid >> spellid >> flags;

	SpellEntry * sp = dbcSpell.LookupEntry(spellid);
	// Summoned Elemental's Freeze
    if (spellid == 33395)
    {
        if (!_player->m_Summon)
            return;
    }
    else if (!_player->m_CurrentCharm || guid != _player->m_CurrentCharm->GetGUID())
    {
        return;
    }

	/* burlex: this is.. strange */
	SpellCastTargets targets;
	targets.m_targetMask = flags;

	if(flags == 0)
		targets.m_unitTarget = guid;
	else if(flags == 0x02)
	{
		WoWGuid guid;
		recvPacket >> flags;		// skip one byte
		recvPacket >> guid;
		targets.m_unitTarget = guid.GetOldGuid();
	}
	else if(flags == 0x40)
	{
		recvPacket >> flags;		// skip one byte
		recvPacket >> targets.m_destX >> targets.m_destY >> targets.m_destZ;
	}
	if(spellid == 33395)	// Summoned Water Elemental's freeze
	{
		Spell * pSpell = new Spell(_player->m_Summon, sp, false, 0);
		pSpell->prepare(&targets);
	}
	else			// trinket?
	{
		Spell * pSpell = new Spell(_player->m_CurrentCharm, sp, false, 0);
		pSpell->prepare(&targets);
	}
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2013 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/node.h"
#include "libmesh/elem.h"
#include "libmesh/reference_elem.h"
#include "libmesh/libmesh_singleton.h"
#include "libmesh/threads.h"

// C++ includes
#include <map>

//-----------------------------------------------
// anonymous namespace for implementation details
namespace
{
  using namespace libMesh;

  namespace ElemDataStrings
  {
#include "reference_elem.data"
  }

  typedef Threads::spin_mutex InitMutex;

  // Mutex for thread safety.
  InitMutex init_mtx;

  // map from ElemType to reference element file system object name
  typedef std::map<ElemType, const char*> FileMapType;
  FileMapType ref_elem_file;
  Elem* ref_elem_map[INVALID_ELEM];

  class SingletonCache : public libMesh::Singleton
  {
  public:
    ~SingletonCache()
    {
      for (unsigned int e=0; e<elem_list.size(); e++)
	if (elem_list[e])
	  {
	    delete elem_list[e];
	    elem_list[e] = NULL;
	  }

      elem_list.clear();

      for (unsigned int n=0; n<node_list.size(); n++)
	if (node_list[n])
	  {
	    delete node_list[n];
	    node_list[n] = NULL;
	  }

      node_list.clear();
    }

    std::vector<Node*> node_list;
    std::vector<Elem*> elem_list;
  };

  // singleton object, dynamically created and then
  // removed at program exit
  SingletonCache *singleton_cache = NULL;

  Elem* read_ref_elem (const ElemType Type,
		       std::istream &in)
  {
    libmesh_assert (singleton_cache != NULL);

    static const unsigned int comm_len = 1024;
    char comm[comm_len];

    std::string foo;
    unsigned int n_elem, n_nodes, elem_type, nn;
    double x, y, z;

    in >> foo;
    in >> n_elem;  /**/ in.getline (comm, comm_len); libmesh_assert_equal_to (n_elem, 1);
    in >> n_nodes; /**/ in.getline (comm, comm_len);
    in >> foo;     /**/ in.getline (comm, comm_len);
    in >> foo;     /**/ in.getline (comm, comm_len);
    in >> foo;     /**/ in.getline (comm, comm_len);
    in >> foo;     /**/ in.getline (comm, comm_len);
    in >> n_elem;  /**/ in.getline (comm, comm_len); libmesh_assert_equal_to (n_elem, 1);

    in >> elem_type;

    libmesh_assert_less (elem_type, INVALID_ELEM);
    libmesh_assert_equal_to (elem_type, Type);
    libmesh_assert_equal_to (n_nodes, Elem::type_to_n_nodes_map[elem_type]);

    // Construct the elem
    Elem *elem = Elem::build(static_cast<ElemType>(elem_type)).release();

    // We are expecing an identity map, so assert it!
    for (unsigned int n=0; n<n_nodes; n++)
      {
	in >> nn;
	libmesh_assert_equal_to (n,nn);
      }

    for (unsigned int n=0; n<n_nodes; n++)
      {
	in >> x >> y >> z;

	Node *node = new Node(x,y,z,n);
	singleton_cache->node_list.push_back(node);

	elem->set_node(n) = node;
      }

    // it is entirely possible we ran out of file or encountered
    // another error.  If so, cleanly abort.
    if (!in)
      {
	delete elem;
	elem = NULL;
	libMesh::err << "ERROR while creating element singleton!\n";
	libmesh_error();
      }

    else
      singleton_cache->elem_list.push_back (elem);

    ref_elem_map[Type] = elem;

    return elem;
  }

  void init_ref_elem_table()
  {
    // ouside mutex - if this flag is set, we can
    // trust it.
    if (singleton_cache != NULL) return;

    // playing with fire here - lock before touching shared
    // data structures
    InitMutex::scoped_lock lock(init_mtx);

    // inside mutex - pointer may have changed while waiting
    // for the lock to acquire, check it again.
    if (singleton_cache != NULL) return;

    // OK, if we get here we have the lock and we are not
    // initialized.  populate singleton.
    singleton_cache = new SingletonCache;

    // initialize the reference file table
    {
      ref_elem_file.clear();

      // // 1D elements
      ref_elem_file[EDGE2]    = ElemDataStrings::one_edge;
      ref_elem_file[EDGE3]    = ElemDataStrings::one_edge3;
      ref_elem_file[EDGE4]    = ElemDataStrings::one_edge4;

      // 2D elements
      ref_elem_file[TRI3]     = ElemDataStrings::one_tri;
      ref_elem_file[TRI6]     = ElemDataStrings::one_tri6;

      ref_elem_file[QUAD4]    = ElemDataStrings::one_quad;
      ref_elem_file[QUAD8]    = ElemDataStrings::one_quad8;
      ref_elem_file[QUAD9]    = ElemDataStrings::one_quad9;

      // 3D elements
      ref_elem_file[HEX8]     = ElemDataStrings::one_hex;
      ref_elem_file[HEX20]    = ElemDataStrings::one_hex20;
      ref_elem_file[HEX27]    = ElemDataStrings::one_hex27;

      ref_elem_file[TET4]     = ElemDataStrings::one_tet;
      ref_elem_file[TET10]    = ElemDataStrings::one_tet10;

      ref_elem_file[PRISM6]   = ElemDataStrings::one_prism;
      ref_elem_file[PRISM15]  = ElemDataStrings::one_prism15;
      ref_elem_file[PRISM18]  = ElemDataStrings::one_prism18;

      ref_elem_file[PYRAMID5] = ElemDataStrings::one_pyramid;
    }

    // Read'em
    for (FileMapType::const_iterator it=ref_elem_file.begin();
	 it != ref_elem_file.end(); ++it)
      {
	std::istringstream stream(it->second);

	read_ref_elem(it->first,
		      stream);
      }
  }

  // Class to setup singleton data
  class ReferenceElemSetup : public Singleton::Setup
  {
    void setup ()
    {
      init_ref_elem_table();
    }
  } reference_elem_setup;

} // anonymous namespace

//----------------------------------------------------------------------------
// external API Implementation
namespace libMesh
{
  namespace ReferenceElem
  {
    const Elem & get (const ElemType Type)
    {
      libmesh_assert_less (Type, INVALID_ELEM);

      init_ref_elem_table();

      libmesh_assert (ref_elem_map[Type] != NULL);

      return *ref_elem_map[Type];
    }
  } // namespace ReferenceElem
} // namespace libMesh
<commit_msg>defer initialization until requested<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2013 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// Local includes
#include "libmesh/node.h"
#include "libmesh/elem.h"
#include "libmesh/reference_elem.h"
#include "libmesh/libmesh_singleton.h"
#include "libmesh/threads.h"

// C++ includes
#include <map>

//-----------------------------------------------
// anonymous namespace for implementation details
namespace
{
  using namespace libMesh;

  namespace ElemDataStrings
  {
#include "reference_elem.data"
  }

  typedef Threads::spin_mutex InitMutex;

  // Mutex for thread safety.
  InitMutex init_mtx;

  // map from ElemType to reference element file system object name
  typedef std::map<ElemType, const char*> FileMapType;
  FileMapType ref_elem_file;
  Elem* ref_elem_map[INVALID_ELEM];

  class SingletonCache : public libMesh::Singleton
  {
  public:
    ~SingletonCache()
    {
      for (unsigned int e=0; e<elem_list.size(); e++)
	if (elem_list[e])
	  {
	    delete elem_list[e];
	    elem_list[e] = NULL;
	  }

      elem_list.clear();

      for (unsigned int n=0; n<node_list.size(); n++)
	if (node_list[n])
	  {
	    delete node_list[n];
	    node_list[n] = NULL;
	  }

      node_list.clear();
    }

    std::vector<Node*> node_list;
    std::vector<Elem*> elem_list;
  };

  // singleton object, dynamically created and then
  // removed at program exit
  SingletonCache *singleton_cache = NULL;

  Elem* read_ref_elem (const ElemType Type,
		       std::istream &in)
  {
    libmesh_assert (singleton_cache != NULL);

    static const unsigned int comm_len = 1024;
    char comm[comm_len];

    std::string foo;
    unsigned int n_elem, n_nodes, elem_type, nn;
    double x, y, z;

    in >> foo;
    in >> n_elem;  /**/ in.getline (comm, comm_len); libmesh_assert_equal_to (n_elem, 1);
    in >> n_nodes; /**/ in.getline (comm, comm_len);
    in >> foo;     /**/ in.getline (comm, comm_len);
    in >> foo;     /**/ in.getline (comm, comm_len);
    in >> foo;     /**/ in.getline (comm, comm_len);
    in >> foo;     /**/ in.getline (comm, comm_len);
    in >> n_elem;  /**/ in.getline (comm, comm_len); libmesh_assert_equal_to (n_elem, 1);

    in >> elem_type;

    libmesh_assert_less (elem_type, INVALID_ELEM);
    libmesh_assert_equal_to (elem_type, Type);
    libmesh_assert_equal_to (n_nodes, Elem::type_to_n_nodes_map[elem_type]);

    // Construct the elem
    Elem *elem = Elem::build(static_cast<ElemType>(elem_type)).release();

    // We are expecing an identity map, so assert it!
    for (unsigned int n=0; n<n_nodes; n++)
      {
	in >> nn;
	libmesh_assert_equal_to (n,nn);
      }

    for (unsigned int n=0; n<n_nodes; n++)
      {
	in >> x >> y >> z;

	Node *node = new Node(x,y,z,n);
	singleton_cache->node_list.push_back(node);

	elem->set_node(n) = node;
      }

    // it is entirely possible we ran out of file or encountered
    // another error.  If so, cleanly abort.
    if (!in)
      {
	delete elem;
	elem = NULL;
	libMesh::err << "ERROR while creating element singleton!\n";
	libmesh_error();
      }

    else
      singleton_cache->elem_list.push_back (elem);

    ref_elem_map[Type] = elem;

    return elem;
  }

  void init_ref_elem_table()
  {
    // ouside mutex - if this flag is set, we can
    // trust it.
    if (singleton_cache != NULL) return;

    // playing with fire here - lock before touching shared
    // data structures
    InitMutex::scoped_lock lock(init_mtx);

    // inside mutex - pointer may have changed while waiting
    // for the lock to acquire, check it again.
    if (singleton_cache != NULL) return;

    // OK, if we get here we have the lock and we are not
    // initialized.  populate singleton.
    singleton_cache = new SingletonCache;

    // initialize the reference file table
    {
      ref_elem_file.clear();

      // // 1D elements
      ref_elem_file[EDGE2]    = ElemDataStrings::one_edge;
      ref_elem_file[EDGE3]    = ElemDataStrings::one_edge3;
      ref_elem_file[EDGE4]    = ElemDataStrings::one_edge4;

      // 2D elements
      ref_elem_file[TRI3]     = ElemDataStrings::one_tri;
      ref_elem_file[TRI6]     = ElemDataStrings::one_tri6;

      ref_elem_file[QUAD4]    = ElemDataStrings::one_quad;
      ref_elem_file[QUAD8]    = ElemDataStrings::one_quad8;
      ref_elem_file[QUAD9]    = ElemDataStrings::one_quad9;

      // 3D elements
      ref_elem_file[HEX8]     = ElemDataStrings::one_hex;
      ref_elem_file[HEX20]    = ElemDataStrings::one_hex20;
      ref_elem_file[HEX27]    = ElemDataStrings::one_hex27;

      ref_elem_file[TET4]     = ElemDataStrings::one_tet;
      ref_elem_file[TET10]    = ElemDataStrings::one_tet10;

      ref_elem_file[PRISM6]   = ElemDataStrings::one_prism;
      ref_elem_file[PRISM15]  = ElemDataStrings::one_prism15;
      ref_elem_file[PRISM18]  = ElemDataStrings::one_prism18;

      ref_elem_file[PYRAMID5] = ElemDataStrings::one_pyramid;
    }

    // Read'em
    for (FileMapType::const_iterator it=ref_elem_file.begin();
	 it != ref_elem_file.end(); ++it)
      {
	std::istringstream stream(it->second);

	read_ref_elem(it->first,
		      stream);
      }
  }

  // no reason to do this at startup -
  // data structures will get initialized *if*
  // ReferenceElem::get() is ever called.
  // // Class to setup singleton data
  // class ReferenceElemSetup : public Singleton::Setup
  // {
  //   void setup ()
  //   {
  //     init_ref_elem_table();
  //   }
  // } reference_elem_setup;

} // anonymous namespace

//----------------------------------------------------------------------------
// external API Implementation
namespace libMesh
{
  namespace ReferenceElem
  {
    const Elem & get (const ElemType Type)
    {
      libmesh_assert_less (Type, INVALID_ELEM);

      init_ref_elem_table();

      libmesh_assert (ref_elem_map[Type] != NULL);

      return *ref_elem_map[Type];
    }
  } // namespace ReferenceElem
} // namespace libMesh
<|endoftext|>


<commit_before>#include "./object_manager.h"
#include <QLoggingCategory>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include "./gl.h"
#include "./buffer_manager.h"
#include "./texture_manager.h"
#include "./shader_manager.h"

namespace Graphics
{

QLoggingCategory omChan("Graphics.ObjectManager");

ObjectManager::ObjectManager(std::shared_ptr<TextureManager> textureManager,
                             std::shared_ptr<ShaderManager> shaderManager)
  : bufferManager(std::make_shared<BufferManager>()),
    textureManager(textureManager), shaderManager(shaderManager),
    transformBuffer(GL_SHADER_STORAGE_BUFFER),
    customBuffer(GL_SHADER_STORAGE_BUFFER),
    commandsBuffer(GL_DRAW_INDIRECT_BUFFER)
{
}

ObjectManager::~ObjectManager()
{
}

void ObjectManager::initialize(Gl *gl, uint maxObjectCount, uint bufferSize)
{
  this->gl = gl;

  bufferManager->initialize(gl, maxObjectCount, bufferSize);

  commandsBuffer.initialize(gl, 3 * maxObjectCount, CREATE_FLAGS, MAP_FLAGS);
  transformBuffer.initialize(gl, 3 * maxObjectCount, CREATE_FLAGS, MAP_FLAGS);
  customBuffer.initialize(gl, 12 * maxObjectCount, CREATE_FLAGS, MAP_FLAGS);
}

ObjectData ObjectManager::addObject(const std::vector<float> &vertices,
                                    const std::vector<float> &normals,
                                    const std::vector<float> &colors,
                                    const std::vector<float> &texCoords,
                                    const std::vector<uint> &indices,
                                    int shaderProgramId, int primitiveType)
{
  auto bufferInformation =
      bufferManager->addObject(vertices, normals, colors, texCoords, indices);

  return ObjectData(nextFreeId++, bufferInformation.vertexBufferOffset,
                    bufferInformation.indexBufferOffset, indices.size(),
                    shaderProgramId, primitiveType);
}

ObjectData ObjectManager::cloneForDifferentShader(const ObjectData &object,
                                   int shaderProgramId)
{
  return ObjectData(nextFreeId++, object.getVertexOffset(), object.getIndexOffset(),
      object.getIndexSize(), shaderProgramId, object.getPrimitiveType());
}

ObjectData ObjectManager::clone(const ObjectData &object)
{
  return ObjectData(nextFreeId++, object.getVertexOffset(), object.getIndexOffset(),
      object.getIndexSize(), object.getShaderProgramId(), object.getPrimitiveType());
}

int ObjectManager::addShader(std::string vertexShaderPath,
                             std::string fragmentShaderPath)
{
  auto id = shaderManager->addShader(vertexShaderPath, fragmentShaderPath);

  qCDebug(omChan) << "Added" << vertexShaderPath.c_str() << "|"
                  << fragmentShaderPath.c_str() << "which got id" << id;

  return id;
}

int ObjectManager::addTexture(std::string path)
{
  return textureManager->addTexture(path);
}

TextureAddress ObjectManager::getAddressFor(int textureId)
{
  return textureManager->getAddressFor(textureId);
}

void ObjectManager::render(const RenderData &renderData)
{
  std::map<int, std::vector<ObjectData>> objectsByShader;
  for (auto &object : objectsForFrame)
  {
    objectsByShader[object.getShaderProgramId()].push_back(object);
  }

  for (auto &shaderObjectPair : objectsByShader)
  {
    qCDebug(omChan) << "Render objects with shader" << shaderObjectPair.first
                    << "with" << shaderObjectPair.second.size() << "objects";

    shaderManager->bind(shaderObjectPair.first, renderData);

    std::map<int, std::vector<ObjectData>> objectsByPrimitiveType;
    for (auto &object : shaderObjectPair.second)
    {
      objectsByPrimitiveType[object.getPrimitiveType()].push_back(object);
    }

    for (auto pair : objectsByPrimitiveType)
    {
      renderObjects(objectsByPrimitiveType[pair.first]);
    }
  }

  objectsForFrame.clear();
}

void ObjectManager::renderImmediately(ObjectData objectData)
{
  std::vector<ObjectData> objs = { objectData };

  renderObjects(objs);
}

void ObjectManager::renderLater(ObjectData object)
{
  objectsForFrame.push_back(object);
}

void ObjectManager::renderObjects(std::vector<ObjectData> objects)
{
  bufferManager->bind();

  // prepare per object buffers
  uint objectCount = objects.size();
  DrawElementsIndirectCommand *commands = commandsBuffer.reserve(objectCount);
  auto *matrices = transformBuffer.reserve(objectCount);
  int customBufferSize = objects[0].getCustomBufferSize() * objectCount;

  void *custom = nullptr;
  if (customBufferSize)
    custom = customBuffer.reserve(customBufferSize);

  qCDebug(omChan) << "customBufferSize" << customBufferSize << "custom"
                  << custom << "matrices" << matrices;

  int counter = 0;
  for (auto &objectData : objects)
  {
    commands[counter] = createDrawCommand(objectData, counter);

    auto *transform = &matrices[counter];
    memcpy(transform, objectData.transform.data(), sizeof(float[16]));

    if (objectData.hasCustomBuffer())
    {
      objectData.fillBufferElement(custom, counter);
    }

    ++counter;
  }

  transformBuffer.bindBufferRange(0, objectCount);
  if (customBufferSize)
    customBuffer.bindBufferRange(1, customBufferSize);

  // We didn't use MAP_COHERENT here - make sure data is on the gpu
  // glAssert(gl->glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT));
  glAssert(gl->glMemoryBarrier(GL_ALL_BARRIER_BITS));

  // draw
  qCDebug(omChan, "head: %ld headoffset %p objectcount: %u",
          commandsBuffer.getHead(), commandsBuffer.headOffset(), objectCount);

  glAssert(gl->glMultiDrawElementsIndirect(
      objects[0].getPrimitiveType(), GL_UNSIGNED_INT, commandsBuffer.headOffset(),
      objectCount, 0));

  bufferManager->unbind();

  commandsBuffer.onUsageComplete(objectCount);
  transformBuffer.onUsageComplete(objectCount);
  if (customBufferSize)
    customBuffer.onUsageComplete(customBufferSize);
}

ObjectManager::DrawElementsIndirectCommand
ObjectManager::createDrawCommand(const ObjectData &objectData, int counter)
{
  DrawElementsIndirectCommand command;

  command.count = objectData.getIndexSize();
  command.instanceCount = 1;
  command.firstIndex = objectData.getIndexOffset();
  command.baseVertex = objectData.getVertexOffset();
  command.baseInstance = counter;

  qCDebug(omChan, "counter: %d count: %u firstIndex: %u baseVertex: %u",
          counter, command.count, command.firstIndex, command.baseVertex);

  return command;
}

}  // namespace Graphics
<commit_msg>Minor: reformatting.<commit_after>#include "./object_manager.h"
#include <QLoggingCategory>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include "./gl.h"
#include "./buffer_manager.h"
#include "./texture_manager.h"
#include "./shader_manager.h"

namespace Graphics
{

QLoggingCategory omChan("Graphics.ObjectManager");

ObjectManager::ObjectManager(std::shared_ptr<TextureManager> textureManager,
                             std::shared_ptr<ShaderManager> shaderManager)
  : bufferManager(std::make_shared<BufferManager>()),
    textureManager(textureManager), shaderManager(shaderManager),
    transformBuffer(GL_SHADER_STORAGE_BUFFER),
    customBuffer(GL_SHADER_STORAGE_BUFFER),
    commandsBuffer(GL_DRAW_INDIRECT_BUFFER)
{
}

ObjectManager::~ObjectManager()
{
}

void ObjectManager::initialize(Gl *gl, uint maxObjectCount, uint bufferSize)
{
  this->gl = gl;

  bufferManager->initialize(gl, maxObjectCount, bufferSize);

  commandsBuffer.initialize(gl, 3 * maxObjectCount, CREATE_FLAGS, MAP_FLAGS);
  transformBuffer.initialize(gl, 3 * maxObjectCount, CREATE_FLAGS, MAP_FLAGS);
  customBuffer.initialize(gl, 12 * maxObjectCount, CREATE_FLAGS, MAP_FLAGS);
}

ObjectData ObjectManager::addObject(const std::vector<float> &vertices,
                                    const std::vector<float> &normals,
                                    const std::vector<float> &colors,
                                    const std::vector<float> &texCoords,
                                    const std::vector<uint> &indices,
                                    int shaderProgramId, int primitiveType)
{
  auto bufferInformation =
      bufferManager->addObject(vertices, normals, colors, texCoords, indices);

  return ObjectData(nextFreeId++, bufferInformation.vertexBufferOffset,
                    bufferInformation.indexBufferOffset, indices.size(),
                    shaderProgramId, primitiveType);
}

ObjectData ObjectManager::cloneForDifferentShader(const ObjectData &object,
                                                  int shaderProgramId)
{
  return ObjectData(nextFreeId++, object.getVertexOffset(),
                    object.getIndexOffset(), object.getIndexSize(),
                    shaderProgramId, object.getPrimitiveType());
}

ObjectData ObjectManager::clone(const ObjectData &object)
{
  return ObjectData(nextFreeId++, object.getVertexOffset(),
                    object.getIndexOffset(), object.getIndexSize(),
                    object.getShaderProgramId(), object.getPrimitiveType());
}

int ObjectManager::addShader(std::string vertexShaderPath,
                             std::string fragmentShaderPath)
{
  auto id = shaderManager->addShader(vertexShaderPath, fragmentShaderPath);

  qCDebug(omChan) << "Added" << vertexShaderPath.c_str() << "|"
                  << fragmentShaderPath.c_str() << "which got id" << id;

  return id;
}

int ObjectManager::addTexture(std::string path)
{
  return textureManager->addTexture(path);
}

TextureAddress ObjectManager::getAddressFor(int textureId)
{
  return textureManager->getAddressFor(textureId);
}

void ObjectManager::render(const RenderData &renderData)
{
  std::map<int, std::vector<ObjectData>> objectsByShader;
  for (auto &object : objectsForFrame)
  {
    objectsByShader[object.getShaderProgramId()].push_back(object);
  }

  for (auto &shaderObjectPair : objectsByShader)
  {
    qCDebug(omChan) << "Render objects with shader" << shaderObjectPair.first
                    << "with" << shaderObjectPair.second.size() << "objects";

    shaderManager->bind(shaderObjectPair.first, renderData);

    std::map<int, std::vector<ObjectData>> objectsByPrimitiveType;
    for (auto &object : shaderObjectPair.second)
    {
      objectsByPrimitiveType[object.getPrimitiveType()].push_back(object);
    }

    for (auto pair : objectsByPrimitiveType)
    {
      renderObjects(objectsByPrimitiveType[pair.first]);
    }
  }

  objectsForFrame.clear();
}

void ObjectManager::renderImmediately(ObjectData objectData)
{
  std::vector<ObjectData> objs = { objectData };

  renderObjects(objs);
}

void ObjectManager::renderLater(ObjectData object)
{
  objectsForFrame.push_back(object);
}

void ObjectManager::renderObjects(std::vector<ObjectData> objects)
{
  bufferManager->bind();

  // prepare per object buffers
  uint objectCount = objects.size();
  DrawElementsIndirectCommand *commands = commandsBuffer.reserve(objectCount);
  auto *matrices = transformBuffer.reserve(objectCount);
  int customBufferSize = objects[0].getCustomBufferSize() * objectCount;

  void *custom = nullptr;
  if (customBufferSize)
    custom = customBuffer.reserve(customBufferSize);

  qCDebug(omChan) << "customBufferSize" << customBufferSize << "custom"
                  << custom << "matrices" << matrices;

  int counter = 0;
  for (auto &objectData : objects)
  {
    commands[counter] = createDrawCommand(objectData, counter);

    auto *transform = &matrices[counter];
    memcpy(transform, objectData.transform.data(), sizeof(float[16]));

    if (objectData.hasCustomBuffer())
    {
      objectData.fillBufferElement(custom, counter);
    }

    ++counter;
  }

  transformBuffer.bindBufferRange(0, objectCount);
  if (customBufferSize)
    customBuffer.bindBufferRange(1, customBufferSize);

  // We didn't use MAP_COHERENT here - make sure data is on the gpu
  // glAssert(gl->glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT));
  glAssert(gl->glMemoryBarrier(GL_ALL_BARRIER_BITS));

  // draw
  qCDebug(omChan, "head: %ld headoffset %p objectcount: %u",
          commandsBuffer.getHead(), commandsBuffer.headOffset(), objectCount);

  glAssert(gl->glMultiDrawElementsIndirect(
      objects[0].getPrimitiveType(), GL_UNSIGNED_INT,
      commandsBuffer.headOffset(), objectCount, 0));

  bufferManager->unbind();

  commandsBuffer.onUsageComplete(objectCount);
  transformBuffer.onUsageComplete(objectCount);
  if (customBufferSize)
    customBuffer.onUsageComplete(customBufferSize);
}

ObjectManager::DrawElementsIndirectCommand
ObjectManager::createDrawCommand(const ObjectData &objectData, int counter)
{
  DrawElementsIndirectCommand command;

  command.count = objectData.getIndexSize();
  command.instanceCount = 1;
  command.firstIndex = objectData.getIndexOffset();
  command.baseVertex = objectData.getVertexOffset();
  command.baseInstance = counter;

  qCDebug(omChan, "counter: %d count: %u firstIndex: %u baseVertex: %u",
          counter, command.count, command.firstIndex, command.baseVertex);

  return command;
}

}  // namespace Graphics
<|endoftext|>