<commit_before>//=============================================================================================================
/**
 * @file     main.cpp
 * @author   Juan Garcia-Prieto <juangpc@gmail.com>;
 *           Lorenz Esch <lesch@mgh.harvard.edu>;
 *           Wayne Mead <wayne.mead@uth.tmc.edu>;
 *           John C. Mosher <John.C.Mosher@uth.tmc.edu>;
 *           Matti Hamalainen <msh@nmr.mgh.harvard.edu>;
 * @date     May, 2020
 * @since    0.1.0
 *
 * @section  LICENSE
 *
 * Copyright (C) 2019, Juan Garcia-Prieto, Lorenz Esch, Matti Hamalainen, Wayne Mead, John C. Mosher. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *       the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
 *       to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * @brief     Application for anonymizing patient and personal health information from a fiff file.
 *
 */

//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "apphandler.h"
#include <utils/generics/applicationlogger.h>

//=============================================================================================================
// EIGEN INCLUDES
//=============================================================================================================

//=============================================================================================================
// QT INCLUDES
//=============================================================================================================
#include <QDebug>
//=============================================================================================================
// FORWARD DECLARATIONS
//=============================================================================================================

namespace MNEANONYMIZE {
    class SettingsControllerCl;
}

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

//=============================================================================================================
// MAIN
//=============================================================================================================

/**
 * The function main marks the entry point of the program.
 * By default, main has the storage class extern.
 *
 * @param[in] argc (argument count) is an integer that indicates how many arguments were entered on the.
 * command line when the program was started.
 * @param[in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects.
 * are null-terminated strings, representing the arguments that were entered on the command line when the
 * program was started.
 *
 * @return the value that was set to exit() (which is 0 if exit() is called via quit()).
 */
int main(int argc, char* argv[])
{
    qInstallMessageHandler(UTILSLIB::ApplicationLogger::customLogWriter);

    QScopedPointer<MNEANONYMIZE::AppHandler> h(new MNEANONYMIZE::AppHandler);
    QScopedPointer<QCoreApplication> qtApp(h->createApplication(argc, argv));

    qtApp->setOrganizationName("MNE-CPP Project");
    qtApp->setApplicationName("MNE Anonymize");

    qDebug() << "date: " << __DATE__;

    QScopedPointer<MNEANONYMIZE::SettingsControllerCl> controller(h->createController(qtApp->arguments()));

    return qtApp->exec();
}
<commit_msg>delete data print in main fcn<commit_after>//=============================================================================================================
/**
 * @file     main.cpp
 * @author   Juan Garcia-Prieto <juangpc@gmail.com>;
 *           Lorenz Esch <lesch@mgh.harvard.edu>;
 *           Wayne Mead <wayne.mead@uth.tmc.edu>;
 *           John C. Mosher <John.C.Mosher@uth.tmc.edu>;
 *           Matti Hamalainen <msh@nmr.mgh.harvard.edu>;
 * @date     May, 2020
 * @since    0.1.0
 *
 * @section  LICENSE
 *
 * Copyright (C) 2019, Juan Garcia-Prieto, Lorenz Esch, Matti Hamalainen, Wayne Mead, John C. Mosher. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 * the following conditions are met:
 *     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *       the following disclaimer in the documentation and/or other materials provided with the distribution.
 *     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
 *       to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 * @brief     Application for anonymizing patient and personal health information from a fiff file.
 *
 */

//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "apphandler.h"
#include <utils/generics/applicationlogger.h>

//=============================================================================================================
// EIGEN INCLUDES
//=============================================================================================================

//=============================================================================================================
// QT INCLUDES
//=============================================================================================================
#include <QDebug>
//=============================================================================================================
// FORWARD DECLARATIONS
//=============================================================================================================

namespace MNEANONYMIZE {
    class SettingsControllerCl;
}

//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

//=============================================================================================================
// MAIN
//=============================================================================================================

/**
 * The function main marks the entry point of the program.
 * By default, main has the storage class extern.
 *
 * @param[in] argc (argument count) is an integer that indicates how many arguments were entered on the.
 * command line when the program was started.
 * @param[in] argv (argument vector) is an array of pointers to arrays of character objects. The array objects.
 * are null-terminated strings, representing the arguments that were entered on the command line when the
 * program was started.
 *
 * @return the value that was set to exit() (which is 0 if exit() is called via quit()).
 */
int main(int argc, char* argv[])
{
    qInstallMessageHandler(UTILSLIB::ApplicationLogger::customLogWriter);

    QScopedPointer<MNEANONYMIZE::AppHandler> h(new MNEANONYMIZE::AppHandler);
    QScopedPointer<QCoreApplication> qtApp(h->createApplication(argc, argv));

    qtApp->setOrganizationName("MNE-CPP Project");
    qtApp->setApplicationName("MNE Anonymize");

    QScopedPointer<MNEANONYMIZE::SettingsControllerCl> controller(h->createController(qtApp->arguments()));

    return qtApp->exec();
}
<|endoftext|>


<commit_before>
#include "spmv_mult.hpp"

// Grappa
#include "Grappa.hpp"
#include "Cache.hpp"
#include "GlobalTaskJoiner.hpp"
#include "ForkJoin.hpp"
#include "Delegate.hpp"

#define XOFF(xoff, index) (xoff)+2*(index)
#define XENDOFF(matrix, index) (xoff)+2*(index)+1

namespace spmv {
  // global: local per Node
  weighted_csr_graph m;
  vector v;
  vector y;
}

void inner_loop( int64_t start, int64_t iters, GlobalAddress<int64_t> targetIndex_h ) {
  // TODO don't use hack
  int64_t targetIndex = reinterpret_cast<int64_t>(targetIndex_h.pointer());

  double yaccum = 0;
  int64_t j[iters];
  double weights[iters];
  Incoherent<int64_t>::RO cj( spmv::m.xadj + start, iters, j ); cj.start_acquire();
  Incoherent<double>::RO cw( spmv::m.adjweight + start, iters, weights ); cw.start_acquire();
  for( int64_t k = 0; k<iters; k++ ) {
    double vj;

    Grappa_delegate_read(spmv::v.a + cj[k], &vj);
    yaccum += cw[k] * vj;
    DVLOG(5) << "yaccum += w["<<start+k<<"]("<<cw[k] <<") * val["<<cj[k]<<"("<<vj<<")";
  }

  DVLOG(4) << "y[" << targetIndex << "] += " << yaccum;
  ff_delegate_add<double>( spmv::y.a+targetIndex, yaccum );
}

void row_loop( int64_t start, int64_t iters ) {
  //VLOG(1) << "rows [" << start << ", " << start+iters << ")";

  for ( int64_t i=start; i<start+iters; i++ ) {
    // kstart = row_ptr[i], kend = row_ptr[i+1]
    int64_t kbounds[2];
    Incoherent<int64_t>::RO cxoff( XOFF(spmv::m.xoff, i), 2, kbounds );
    int64_t kstart = cxoff[0];
    int64_t kend = cxoff[1];

    // TODO: don't use hack to wrap i
    async_parallel_for<int64_t,inner_loop, joinerSpawn_hack<int64_t,inner_loop,ASYNC_PAR_FOR_DEFAULT>,ASYNC_PAR_FOR_DEFAULT>(kstart, kend-kstart, make_global(reinterpret_cast<int64_t*>(i)));

                               // TODO: if yi.start_release() could guarentee the storage is no longer used
                               //       then this would be nice for no block until all y[start,start+iters) need to be written, although that pressures the network side
                               // Y could actually be like a feed forward delegate that syncs at global join end
  }
}
// In general, destination arrays that are either associatively accumulated into or written once into can often get by with very weak consistency: sync at very end once value of vector needs to be known valid result.

// With current low level programming model, the choice to parallelize a loop involves different code

GlobalCompletionEvent mmjoiner;
void spmv_mult( weighted_csr_graph A, vector x, vector y ) {
  // forall rows
  forall_global_public<&mmjoiner>( 0, A.nv, [A, x, y]( int64_t start, int64_t iters ) {
    // serialized chunk of rows
    DVLOG(5) << "rows [" << start << ", " << start+iters << ")";
    for (int64_t i=start; i<start+iters; i++ ) {
      // kstart = row_ptr[i], kend = row_ptr[i+1]
      int64_t kbounds[2];
      Incoherent<int64_t>::RO cxoff( XOFF(A.xoff, i), 2, kbounds );
      int64_t kstart = cxoff[0];
      int64_t kend = cxoff[1];

      // forall non-zero columns (parallel dot product)
      forall_here_async_public<&mmjoiner>( kstart, kend-kstart, [i]( int64_t start, int64_t iters ) {
        double yaccum = 0;

        // serialized chunk of columns
        int64_t j[iters];
        double weights[iters];
        Incoherent<int64_t>::RO cj( A.xadj + start, iters, j ); cj.start_acquire();
        Incoherent<double>::RO cw( A.adjweight + start, iters, weights ); cw.start_acquire();
        for( int64_t k = 0; k<iters; k++ ) {
          double vj = Grappa::delegate::read(x.a + cj[k]);
          yaccum += cw[k] * vj;
          DVLOG(5) << "yaccum += w["<<start+k<<"]("<<cw[k] <<") * val["<<cj[k]<<"("<<vj<<")";
        }

        DVLOG(4) << "y[" << i << "] += " << yaccum;

        // TODO: trait on call_async not to use pool
        MessagePool pool( ##sizeof del## );
        //FIXME async write
        call_async<&mmjoiner>( pool, ..., {});
        ff_delegate_add<double>( y.a+i, yaccum );
        // could force local updates and bulk communication
        // here instead of relying on aggregation
        // since we have to pay the cost of many increments and replies
      });
    }
  });
}

// only good for small matrices; write out in dense format
void matrix_out( weighted_csr_graph * g, std::ostream& o, bool dense ) {
  for ( int64_t i = 0; i<g->nv; i++ ) {
    int64_t kbounds[2];
    Incoherent<int64_t>::RO cxoff( XOFF(g->xoff, i), 2, kbounds );
    const int64_t kstart = cxoff[0];
    const int64_t kend = cxoff[1];

    int64_t row[kend-kstart];
    Incoherent<int64_t>::RO crow( g->xadj + kstart, kend-kstart, row );

    double weights[kend-kstart];
    Incoherent<double>::RO cweights( g->adjweight + kstart, kend-kstart, weights );

    if (dense) {
      int64_t next_col = 0;
      for ( int64_t j = 0; j<g->nv; j++ ) {
        if ( next_col < (kend-kstart) && crow[next_col] == j ) {
          o << cweights[next_col] << ", ";
          next_col++;
        } else {
          o << "0, ";
        }
      }
      o << "\n";
      CHECK (next_col==kend-kstart) << "mismatch, did not print all entries; next_col="<<next_col<<" kend-kstart=" <<kend-kstart;
    } else {
      o << "v=" << i << ";; ";
      for ( int64_t ri=0; ri<kend-kstart; ri++ ) {
        o << crow[ri] << ",";
      }
      o << "\n";
    }
  }
}

void R_matrix_out( weighted_csr_graph * g, std::ostream& o) {
  o << "matrix(data=c(";

  for ( int64_t i = 0; i<g->nv; i++ ) {
    int64_t kbounds[2];
    Incoherent<int64_t>::RO cxoff( XOFF(g->xoff, i), 2, kbounds );
    const int64_t kstart = cxoff[0];
    const int64_t kend = cxoff[1];

    int64_t row[kend-kstart];
    double weights[kend-kstart];
    Incoherent<int64_t>::RO crow( g->xadj + kstart, kend-kstart, row );
    Incoherent<double>::RO cw( g->adjweight + kstart, kend-kstart, weights );

    int64_t next_col = 0;
    for ( int64_t j = 0; j<g->nv; j++ ) {
      if ( next_col < (kend-kstart) && crow[next_col] == j ) {
        o << cw[next_col];
        next_col++;
      } else {
        o << "0";
      }
      if (!(j==g->nv-1 && i==g->nv-1)) o <<", ";
    }
    CHECK (next_col==kend-kstart) << "mismatch, did not print all entries; next_col="<<next_col<<" kend-kstart=" <<kend-kstart;
  }
  o << ")";
  o << ", nrow=" << g->nv;
  o << ", ncol=" << g->nv;
  o << ")";
}

void vector_out( vector * v, std::ostream& o ) {
  Incoherent<double>::RO cv( v->a, v->length );
  for ( uint64_t i=0; i<v->length; i++ ) {
    o << cv[i] << ", ";
  }
}

void R_vector_out( vector * v, std::ostream& o ) {
  o << "c(";
  Incoherent<double>::RO cv( v->a, v->length );
  for ( uint64_t i=0; i<v->length-1; i++ ) {
    o << cv[i] << ", ";
  }
  o << cv[v->length-1];
  o << ")";
}
<commit_msg>port matrix multiply to new api<commit_after>
#include "spmv_mult.hpp"

// Grappa
#include <Grappa.hpp>
#include <Cache.hpp>
#include <GlobalCompletionEvent.hpp>
#include <ParallelLoop.hpp>
#include <Delegate.hpp>
#include <AsyncDelegate.hpp>
#include <MessagePool.hpp>

#define XOFF(xoff, index) (xoff)+2*(index)
#define XENDOFF(matrix, index) (xoff)+2*(index)+1

namespace spmv {
  // global: local per Node
  weighted_csr_graph m;
  vector x;
  vector y;
}

using namespace Grappa;

// With current low level programming model, the choice to parallelize a loop involves different code

GlobalCompletionEvent mmjoiner;
void spmv_mult( weighted_csr_graph A, vector x, vector y ) {
  // cannot capture in all for loops, so just set on all cores
  on_all_cores( [A,x,y] {
    spmv::m = A;
    spmv::x = x;
    spmv::y = y;
  });

  // forall rows
  forall_global_public<&mmjoiner>( 0, A.nv, []( int64_t start, int64_t iters ) {
    // serialized chunk of rows
    DVLOG(5) << "rows [" << start << ", " << start+iters << ")";
    for (int64_t i=start; i<start+iters; i++ ) {
      // kstart = row_ptr[i], kend = row_ptr[i+1]
      int64_t kbounds[2];
      Incoherent<int64_t>::RO cxoff( XOFF(spmv::m.xoff, i), 2, kbounds );
      int64_t kstart = cxoff[0];
      int64_t kend = cxoff[1];

      // forall non-zero columns (parallel dot product)
      forall_here_async_public<&mmjoiner>( kstart, kend-kstart, [i]( int64_t start, int64_t iters ) {
        double yaccum = 0;

        // serialized chunk of columns
        int64_t j[iters];
        double weights[iters];
        Incoherent<int64_t>::RO cj( spmv::m.xadj + start, iters, j ); cj.start_acquire();
        Incoherent<double>::RO cw( spmv::m.adjweight + start, iters, weights ); cw.start_acquire();
        for( int64_t k = 0; k<iters; k++ ) {
          double vj = Grappa::delegate::read(spmv::x.a + cj[k]);
          yaccum += cw[k] * vj;
          DVLOG(5) << "yaccum += w["<<start+k<<"]("<<cw[k] <<") * val["<<cj[k]<<"("<<vj<<")";
        }

        DVLOG(4) << "y[" << i << "] += " << yaccum;

        char pool_storage[sizeof(delegate::write_msg_proxy<double>)];  // TODO: trait on call_async not to use pool
        MessagePool pool( pool_storage, sizeof(pool_storage) );
        delegate::increment_async<&mmjoiner>(pool, spmv::y.a+i, yaccum);
        // could force local updates and bulk communication
        // here instead of relying on aggregation
        // since we have to pay the cost of many increments and replies
      });
    }
  });
}
                               // TODO: if yi.start_release() could guarentee the storage is no longer used
                               //       then this would be nice for no block until all y[start,start+iters) need to be written, although that pressures the network side
                               // Y could actually be like a feed forward delegate that syncs at global join end
// In general, destination arrays that are either associatively accumulated into or written once into can often get by with very weak consistency: sync at very end once value of vector needs to be known valid result.

// only good for small matrices; write out in dense format
void matrix_out( weighted_csr_graph * g, std::ostream& o, bool dense ) {
  for ( int64_t i = 0; i<g->nv; i++ ) {
    int64_t kbounds[2];
    Incoherent<int64_t>::RO cxoff( XOFF(g->xoff, i), 2, kbounds );
    const int64_t kstart = cxoff[0];
    const int64_t kend = cxoff[1];

    int64_t row[kend-kstart];
    Incoherent<int64_t>::RO crow( g->xadj + kstart, kend-kstart, row );

    double weights[kend-kstart];
    Incoherent<double>::RO cweights( g->adjweight + kstart, kend-kstart, weights );

    if (dense) {
      int64_t next_col = 0;
      for ( int64_t j = 0; j<g->nv; j++ ) {
        if ( next_col < (kend-kstart) && crow[next_col] == j ) {
          o << cweights[next_col] << ", ";
          next_col++;
        } else {
          o << "0, ";
        }
      }
      o << "\n";
      CHECK (next_col==kend-kstart) << "mismatch, did not print all entries; next_col="<<next_col<<" kend-kstart=" <<kend-kstart;
    } else {
      o << "v=" << i << ";; ";
      for ( int64_t ri=0; ri<kend-kstart; ri++ ) {
        o << crow[ri] << ",";
      }
      o << "\n";
    }
  }
}

void R_matrix_out( weighted_csr_graph * g, std::ostream& o) {
  o << "matrix(data=c(";

  for ( int64_t i = 0; i<g->nv; i++ ) {
    int64_t kbounds[2];
    Incoherent<int64_t>::RO cxoff( XOFF(g->xoff, i), 2, kbounds );
    const int64_t kstart = cxoff[0];
    const int64_t kend = cxoff[1];

    int64_t row[kend-kstart];
    double weights[kend-kstart];
    Incoherent<int64_t>::RO crow( g->xadj + kstart, kend-kstart, row );
    Incoherent<double>::RO cw( g->adjweight + kstart, kend-kstart, weights );

    int64_t next_col = 0;
    for ( int64_t j = 0; j<g->nv; j++ ) {
      if ( next_col < (kend-kstart) && crow[next_col] == j ) {
        o << cw[next_col];
        next_col++;
      } else {
        o << "0";
      }
      if (!(j==g->nv-1 && i==g->nv-1)) o <<", ";
    }
    CHECK (next_col==kend-kstart) << "mismatch, did not print all entries; next_col="<<next_col<<" kend-kstart=" <<kend-kstart;
  }
  o << ")";
  o << ", nrow=" << g->nv;
  o << ", ncol=" << g->nv;
  o << ")";
}

void vector_out( vector * v, std::ostream& o ) {
  Incoherent<double>::RO cv( v->a, v->length );
  for ( uint64_t i=0; i<v->length; i++ ) {
    o << cv[i] << ", ";
  }
}

void R_vector_out( vector * v, std::ostream& o ) {
  o << "c(";
  Incoherent<double>::RO cv( v->a, v->length );
  for ( uint64_t i=0; i<v->length-1; i++ ) {
    o << cv[i] << ", ";
  }
  o << cv[v->length-1];
  o << ")";
}
<|endoftext|>


<commit_before>/*
 * TinyJS
 *
 * A single-file Javascript-alike engine
 *
 * Authored By Gordon Williams <gw@pur3.co.uk>
 *
 * Copyright (C) 2009 Pur3 Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * This is a program to run all the tests in the tests folder...
 */

#include "OS_support.h"
#include "utils.h"
#include "scriptMain.h"
#include "mvmCodegen.h"
#include "jsParser.h"
#include "semanticCheck.h"
#include "TinyJS_Functions.h"
#include "actorRuntime.h"

#include <assert.h>
#include <sys/stat.h>
#include <string>
#include <sstream>
#include <stdio.h>

using namespace std;

/**
 * Generic JSON format logger.
 * It is used to generate call log.
 */
class JsonLogger
{
public:
    JsonLogger (const string& filePath) : m_path (filePath)
    {
        FILE*   pf = fopen (m_path.c_str(), "w");
        if (pf)
        {
            fclose(pf);
            log ("[", false);
            m_first = true;
        }
    }

    ~JsonLogger()
    {
        log ("]", false);
    }

    void log (const string& text, bool comma = true)
    {
        FILE*   pf = fopen (m_path.c_str(), "a+");

        if (pf)
        {
            if (comma && !m_first)
                fprintf (pf, ",%s\n", text.c_str());
            else
                fprintf (pf, "%s\n", text.c_str());
            m_first = false;
            fclose(pf);
        }
    }

private:
    string  m_path;
    bool    m_first;
};

JsonLogger*  s_curFunctionLogger = NULL;

/**
 * Assertion function exported to tests
 * @param pScope
 * @return
 */
Ref<JSValue> assertFunction(FunctionScope* pScope)
{
    auto    value =  pScope->getParam("value");

    if (!value->toBoolean())
    {
        auto    text =  pScope->getParam("text")->toString();

        error("Assertion failed: %s", text.c_str());
    }

    return undefined();
}

/**
 * Executes some code using eval, and expects that it throws a 'CScriptException'.
 * It catches the exception, and returns 'true'. If no exception is throw, it
 * throws an exception to indicate a test failure.
 * @param pScope
 * @return
 */
Ref<JSValue> expectError(FunctionScope* pScope)
{
    string  code =  pScope->getParam("code")->toString();

    try
    {
        evaluate (code.c_str(), createDefaultGlobals());
    }
    catch (CScriptException& error)
    {
        return jsTrue();
    }

    error ("No exception thrown: %s", code.c_str());

    return jsFalse();
}

/**
 * Function to write on standard output
 * @param pScope
 * @return
 */
Ref<JSValue> printLn(FunctionScope* pScope)
{
    auto    text =  pScope->getParam("text");

    printf ("%s\n", text->toString().c_str());

    return undefined();
}

/**
 * Gives access to the parser to the tested code.
 * Useful for tests which target the parser.
 * @param pScope
 * @return
 */
Ref<JSValue> asParse(FunctionScope* pScope)
{
    string          code =  pScope->getParam("code")->toString();
    CScriptToken    token (code.c_str());
    auto            result = JSArray::create();

    //Parsing loop
    token = token.next();
    while (!token.eof())
    {
        const ParseResult   parseRes = parseStatement (token);

        result->push(parseRes.ast->toJS());
        token = parseRes.nextToken;
    }

    return result;
}

/**
 * Funs a test script loaded from a file.
 * @param szFile        Path to the test script.
 * @param testDir       Directory in which the test script is located.
 * @param resultsDir    Directory in which tests results are written
 * @return
 */
bool run_test(const std::string& szFile, const string &testDir, const string& resultsDir)
{
    printf("TEST %s ", szFile.c_str());

    string script = readTextFile(szFile);
    if (script.empty())
    {
        printf("Cannot read file: '%s'\n", szFile.c_str());
        return false;
    }

    const string relPath = szFile.substr (testDir.size());
    const string testName = removeExt( fileFromPath(relPath));
    string testResultsDir = resultsDir + removeExt(relPath) + '/';

    auto globals = createDefaultGlobals();

    globals->newVar("result", jsInt(0));
    addNative("function assert(value, text)", assertFunction, globals);
    addNative("function printLn(text)", printLn, globals);
    addNative("function expectError(code)", expectError, globals);
    addNative("function asParse(code)", asParse, globals);
    try
    {
        //This code is copied from 'evaluate', to log the intermediate results
        //generated from each state
        CScriptToken    token (script.c_str());
        AstNodeList   statements;

        //Parsing loop
        token = token.next();
        while (!token.eof())
        {
            const ParseResult   parseRes = parseStatement (token);

            statements.push_back(parseRes.ast);
            token = parseRes.nextToken;
        }

        //Write Abstract Syntax Tree
        const string astJSON = toJSON (statements);
        writeTextFile(testResultsDir + testName + ".ast.json", astJSON);

        //Semantic analysis
        semanticCheck(statements);

        //Code generation.
        const Ref<MvmRoutine>    code = scriptCodegen(statements);

        //Write disassembly
        writeTextFile(testResultsDir + testName + ".asm.json", mvmDisassembly(code));

        //Call logger setup
        JsonLogger  callLogger (testResultsDir + testName + ".calls.json");
        s_curFunctionLogger = &callLogger;
        auto logFn = [](FunctionScope* pScope) -> Ref<JSValue>
        {
            auto entry = pScope->getParam("x");

            s_curFunctionLogger->log(entry->getJSON(0));
            return undefined();
        };
        //addNative("function callLogger(x)", logFn, globals);

        //Execution
        //mvmExecute(code, globals);
        asBlockingExec(code, globals);
    }
    catch (const CScriptException &e)
    {
        printf("ERROR: %s\n", e.what());
    }

    //Write globals
    writeTextFile(testResultsDir + testName + ".globals.json", globals->toObject()->getJSON(0));

    bool pass = null2undef( globals->get("result") )->toBoolean();

    if (pass)
        printf("PASS\n");
    else
        printf("FAIL\n");

    return pass;
}

int main(int argc, char **argv)
{
    const string testsDir = "./tests/";
    const string resultsDir = "./tests/results/";

    printf("TinyJS test runner\n");
    printf("USAGE:\n");
    printf("   ./run_tests test.js       : run just one test\n");
    printf("   ./run_tests               : run all tests\n");
    if (argc == 2)
    {
        printf("Running test: %s\n", argv[1]);

        return !run_test(testsDir + argv[1], testsDir, resultsDir);
    }
    else
        printf("Running all tests!\n");

    int test_num = 1;
    int count = 0;
    int passed = 0;

    //TODO: Run all tests in the directory (or even in subdirectories). Do not depend
    //on test numbers.

    while (test_num < 1000)
    {
        char name[32];
        sprintf_s(name, "test%03d.js", test_num);

        const string    szPath = testsDir + name;
        // check if the file exists - if not, assume we're at the end of our tests
        FILE *f = fopen(szPath.c_str(), "r");
        if (!f) break;
        fclose(f);

        if (run_test(szPath, testsDir, resultsDir))
            passed++;
        count++;
        test_num++;
    }

    printf("Done. %d tests, %d pass, %d fail\n", count, passed, count - passed);

#ifdef _DEBUG
#ifdef _WIN32
    _CrtDumpMemoryLeaks();
#endif
#endif

    return 0;
}
<commit_msg>Added comment<commit_after>/*
 * TinyJS
 *
 * A single-file Javascript-alike engine
 *
 * Authored By Gordon Williams <gw@pur3.co.uk>
 *
 * Copyright (C) 2009 Pur3 Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * This is a program to run all the tests in the tests folder...
 */

#include "OS_support.h"
#include "utils.h"
#include "scriptMain.h"
#include "mvmCodegen.h"
#include "jsParser.h"
#include "semanticCheck.h"
#include "TinyJS_Functions.h"
#include "actorRuntime.h"

#include <assert.h>
#include <sys/stat.h>
#include <string>
#include <sstream>
#include <stdio.h>

using namespace std;

/**
 * Generic JSON format logger.
 * It is used to generate call log.
 */
class JsonLogger
{
public:
    JsonLogger (const string& filePath) : m_path (filePath)
    {
        FILE*   pf = fopen (m_path.c_str(), "w");
        if (pf)
        {
            fclose(pf);
            log ("[", false);
            m_first = true;
        }
    }

    ~JsonLogger()
    {
        log ("]", false);
    }

    void log (const string& text, bool comma = true)
    {
        FILE*   pf = fopen (m_path.c_str(), "a+");

        if (pf)
        {
            if (comma && !m_first)
                fprintf (pf, ",%s\n", text.c_str());
            else
                fprintf (pf, "%s\n", text.c_str());
            m_first = false;
            fclose(pf);
        }
    }

private:
    string  m_path;
    bool    m_first;
};

JsonLogger*  s_curFunctionLogger = NULL;

/**
 * Assertion function exported to tests
 * @param pScope
 * @return
 */
Ref<JSValue> assertFunction(FunctionScope* pScope)
{
    auto    value =  pScope->getParam("value");

    if (!value->toBoolean())
    {
        auto    text =  pScope->getParam("text")->toString();

        error("Assertion failed: %s", text.c_str());
    }

    return undefined();
}

/**
 * Executes some code using eval, and expects that it throws a 'CScriptException'.
 * It catches the exception, and returns 'true'. If no exception is throw, it
 * throws an exception to indicate a test failure.
 * @param pScope
 * @return
 */
Ref<JSValue> expectError(FunctionScope* pScope)
{
    string  code =  pScope->getParam("code")->toString();

    try
    {
        evaluate (code.c_str(), createDefaultGlobals());
    }
    catch (CScriptException& error)
    {
        return jsTrue();
    }

    error ("No exception thrown: %s", code.c_str());

    return jsFalse();
}

/**
 * Function to write on standard output
 * @param pScope
 * @return
 */
Ref<JSValue> printLn(FunctionScope* pScope)
{
    auto    text =  pScope->getParam("text");

    printf ("%s\n", text->toString().c_str());

    return undefined();
}

/**
 * Gives access to the parser to the tested code.
 * Useful for tests which target the parser.
 * @param pScope
 * @return
 */
Ref<JSValue> asParse(FunctionScope* pScope)
{
    string          code =  pScope->getParam("code")->toString();
    CScriptToken    token (code.c_str());
    auto            result = JSArray::create();

    //Parsing loop
    token = token.next();
    while (!token.eof())
    {
        const ParseResult   parseRes = parseStatement (token);

        result->push(parseRes.ast->toJS());
        token = parseRes.nextToken;
    }

    return result;
}

/**
 * Funs a test script loaded from a file.
 * @param szFile        Path to the test script.
 * @param testDir       Directory in which the test script is located.
 * @param resultsDir    Directory in which tests results are written
 * @return
 */
bool run_test(const std::string& szFile, const string &testDir, const string& resultsDir)
{
    printf("TEST %s ", szFile.c_str());

    string script = readTextFile(szFile);
    if (script.empty())
    {
        printf("Cannot read file: '%s'\n", szFile.c_str());
        return false;
    }

    const string relPath = szFile.substr (testDir.size());
    const string testName = removeExt( fileFromPath(relPath));
    string testResultsDir = resultsDir + removeExt(relPath) + '/';

    auto globals = createDefaultGlobals();

    globals->newVar("result", jsInt(0));
    addNative("function assert(value, text)", assertFunction, globals);
    addNative("function printLn(text)", printLn, globals);
    addNative("function expectError(code)", expectError, globals);
    addNative("function asParse(code)", asParse, globals);
    try
    {
        //This code is copied from 'evaluate', to log the intermediate results
        //generated from each state
        CScriptToken    token (script.c_str());
        AstNodeList   statements;

        //Parsing loop
        token = token.next();
        while (!token.eof())
        {
            const ParseResult   parseRes = parseStatement (token);

            statements.push_back(parseRes.ast);
            token = parseRes.nextToken;
        }

        //Write Abstract Syntax Tree
        const string astJSON = toJSON (statements);
        writeTextFile(testResultsDir + testName + ".ast.json", astJSON);

        //Semantic analysis
        semanticCheck(statements);

        //Code generation.
        const Ref<MvmRoutine>    code = scriptCodegen(statements);

        //Write disassembly
        writeTextFile(testResultsDir + testName + ".asm.json", mvmDisassembly(code));

        //Call logger setup
        JsonLogger  callLogger (testResultsDir + testName + ".calls.json");
        s_curFunctionLogger = &callLogger;
        auto logFn = [](FunctionScope* pScope) -> Ref<JSValue>
        {
            auto entry = pScope->getParam("x");

            s_curFunctionLogger->log(entry->getJSON(0));
            return undefined();
        };
        //addNative("function callLogger(x)", logFn, globals);

        //Execution
        //mvmExecute(code, globals);
        asBlockingExec(code, globals);
    }
    catch (const CScriptException &e)
    {
        printf("ERROR: %s\n", e.what());
    }

    //Write globals
    writeTextFile(testResultsDir + testName + ".globals.json", globals->toObject()->getJSON(0));

    bool pass = null2undef( globals->get("result") )->toBoolean();

    if (pass)
        printf("PASS\n");
    else
        printf("FAIL\n");

    return pass;
}

/**
 * Test program entry point.
 * @param argc
 * @param argv
 * @return
 */
int main(int argc, char **argv)
{
    const string testsDir = "./tests/";
    const string resultsDir = "./tests/results/";

    printf("TinyJS test runner\n");
    printf("USAGE:\n");
    printf("   ./run_tests test.js       : run just one test\n");
    printf("   ./run_tests               : run all tests\n");
    if (argc == 2)
    {
        printf("Running test: %s\n", argv[1]);

        return !run_test(testsDir + argv[1], testsDir, resultsDir);
    }
    else
        printf("Running all tests!\n");

    int test_num = 1;
    int count = 0;
    int passed = 0;

    //TODO: Run all tests in the directory (or even in subdirectories). Do not depend
    //on test numbers.

    while (test_num < 1000)
    {
        char name[32];
        sprintf_s(name, "test%03d.js", test_num);

        const string    szPath = testsDir + name;
        // check if the file exists - if not, assume we're at the end of our tests
        FILE *f = fopen(szPath.c_str(), "r");
        if (!f) break;
        fclose(f);

        if (run_test(szPath, testsDir, resultsDir))
            passed++;
        count++;
        test_num++;
    }

    printf("Done. %d tests, %d pass, %d fail\n", count, passed, count - passed);

#ifdef _DEBUG
#ifdef _WIN32
    _CrtDumpMemoryLeaks();
#endif
#endif

    return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * Copyright (c) 2010 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#ifndef __SEGMENTTREE_HPP__
#define __SEGMENTTREE_HPP__

#include "node.hpp"

#include <vector>
#include <list>
#include <iostream>
#include <boost/ptr_container/ptr_vector.hpp>

namespace mdds {

template<typename _Key, typename _Data>
class segment_tree
{
public:
    typedef _Key        key_type;
    typedef _Data       data_type;
    typedef ::std::list<data_type*> data_chain_type;

    struct nonleaf_value_type
    {
    };

    struct leaf_value_type
    {
        key_type key;
        data_chain_type* data_chain;
    };

    struct node : public node_base
    {
        union {
            nonleaf_value_type  value_nonleaf;
            leaf_value_type     value_leaf;
        };

        node(bool _is_leaf) :
            node_base(_is_leaf)
        {
            if (_is_leaf)
                value_leaf.data_chain = NULL;
        }

        node(const node& r) :
            node_base(r)
        {
        }

        virtual ~node()
        {
            if (is_leaf)
                delete value_leaf.data_chain;
        }

        bool equals(const node& r) const
        {
            if (is_leaf != r.is_leaf)
                return false;

            return true;
        }

        virtual void fill_nonleaf_value(const node_base_ptr& left_node, const node_base_ptr& right_node)
        {
        }

        virtual void dump_value() const
        {
        }

        virtual node_base* create_new(bool leaf) const
        {
            return new node(leaf);
        }

        virtual node_base* clone() const
        {
            return new node(*this);
        }
    };

    segment_tree();
    ~segment_tree();

    bool is_tree_valid() const { return m_valid_tree; }

    void build_tree();

    void insert(key_type begin_key, key_type end_key, data_type* pdata);

private:
    static node* get_node(const node_base_ptr& base_node)
    {
        return static_cast<node*>(base_node.get());
    }

    static void build_leaf_node(const ::std::vector<key_type>& keys, node_base_ptr& left, node_base_ptr& right);

private:
    struct segment_data
    {
        key_type    begin_key;
        key_type    end_key;
        data_type*  pdata;

        segment_data(key_type _beg, key_type _end, data_type* p) :
            begin_key(_beg), end_key(_end), pdata(p) {}
    };

    typedef ::boost::ptr_vector<segment_data> data_array_type;
    data_array_type m_segment_data;

    node_base_ptr   m_root_node;
    node_base_ptr   m_left_leaf;
    node_base_ptr   m_right_leaf;
    bool m_valid_tree:1;
};

template<typename _Key, typename _Data>
segment_tree<_Key, _Data>::segment_tree() :
    m_valid_tree(false)
{
}

template<typename _Key, typename _Data>
segment_tree<_Key, _Data>::~segment_tree()
{
    // Go through all leaf nodes, and disconnect their links.
    node_base* cur_node = m_left_leaf.get();
    do
    {
        node_base* next_node = cur_node->right.get();
        disconnect_node(cur_node);
        cur_node = next_node;
    }
    while (cur_node != m_right_leaf.get());

    disconnect_node(m_right_leaf.get());
}

template<typename _Key, typename _Data>
void segment_tree<_Key, _Data>::build_tree()
{
    using namespace std;

    // In 1st pass, collect unique end-point values and sort them.
    vector<key_type> keys_uniq;
    keys_uniq.reserve(m_segment_data.size()*2);
    typename data_array_type::const_iterator itr, itr_beg = m_segment_data.begin(), itr_end = m_segment_data.end();
    for (itr = itr_beg; itr != itr_end; ++itr)
    {
        cout << itr->begin_key << "," << itr->end_key << ": " << itr->pdata << endl;
        keys_uniq.push_back(itr->begin_key);
        keys_uniq.push_back(itr->end_key);
    }

    // sort and remove duplicates.
    sort(keys_uniq.begin(), keys_uniq.end());
    keys_uniq.erase(unique(keys_uniq.begin(), keys_uniq.end()), keys_uniq.end());

    // debug output.
    cout << "unique keys: ";
    copy(keys_uniq.begin(), keys_uniq.end(), ostream_iterator<key_type>(cout, " "));
    cout << endl;

    // Create leaf nodes with the unique end-point values.
    build_leaf_node(keys_uniq, m_left_leaf, m_right_leaf);

    // debug output.
    {
        cout << "forward: ";
        node* p = get_node(m_left_leaf);
        while (p)
        {
            cout << p->value_leaf.key << " ";
            p = get_node(p->right);
        }
        cout << endl;

        cout << "backward: ";
        p = get_node(m_right_leaf);
        while (p)
        {
            cout << p->value_leaf.key << " ";
            p = get_node(p->left);
        }
        cout << endl;
    }

    // In 2nd pass, "insert" each segment.
    for (itr = itr_beg; itr != itr_end; ++itr)
    {
        key_type key_beg = itr->begin_key;
        key_type key_end = itr->end_key;
        data_type* pdata = itr->pdata;

        node* p = get_node(m_left_leaf);
        while (p)
        {
            if (p->value_leaf.key == key_beg)
            {
                leaf_value_type& v = p->value_leaf;
                if (!v.data_chain)
                    v.data_chain = new data_chain_type;
                v.data_chain->push_back(pdata);
            }
            else if (p->value_leaf.key == key_end)
            {
                // Insert data pointer to the previous node _only when_ the
                // value of the previous node doesn't equal the begin point
                // value.
                node* pprev = get_node(p->left);
                if (pprev && pprev->value_leaf.key != key_beg)
                {
                    leaf_value_type& v = pprev->value_leaf;
                    if (!v.data_chain)
                        v.data_chain = new data_chain_type;
                    v.data_chain->push_back(pdata);
                }
            }
            p = get_node(p->right);
        }
    }
}

template<typename _Key, typename _Data>
void segment_tree<_Key, _Data>::build_leaf_node(const ::std::vector<key_type>& keys, node_base_ptr& left, node_base_ptr& right)
{
    if (keys.empty() || keys.size() < 2)
        // We need at least two keys in order to build tree.
        return;

    typename ::std::vector<key_type>::const_iterator itr = keys.begin(), itr_end = keys.end();

    // left-most node
    left.reset(new node(true));
    get_node(left)->value_leaf.key = *itr;

    // move on to next.
    left->right.reset(new node(true));
    node_base_ptr prev_node = left;
    node_base_ptr cur_node = left->right;
    cur_node->left = prev_node;

    for (++itr; itr != itr_end; ++itr)
    {
        get_node(cur_node)->value_leaf.key = *itr;

        // move on to next
        cur_node->right.reset(new node(true));
        prev_node = cur_node;
        cur_node = cur_node->right;
        cur_node->left = prev_node;
    }

    // Remove the excess node.
    prev_node->right.reset();
    right = prev_node;
}

template<typename _Key, typename _Data>
void segment_tree<_Key, _Data>::insert(key_type begin_key, key_type end_key, data_type* pdata)
{
    if (begin_key >= end_key)
        return;

    m_segment_data.push_back(new segment_data(begin_key, end_key, pdata));
}

}

#endif
<commit_msg>Print out attached data pointers for each leaf node.<commit_after>/*************************************************************************
 *
 * Copyright (c) 2010 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#ifndef __SEGMENTTREE_HPP__
#define __SEGMENTTREE_HPP__

#include "node.hpp"

#include <vector>
#include <list>
#include <iostream>
#include <boost/ptr_container/ptr_vector.hpp>

namespace mdds {

template<typename _Key, typename _Data>
class segment_tree
{
public:
    typedef _Key        key_type;
    typedef _Data       data_type;
    typedef ::std::list<data_type*> data_chain_type;

    struct nonleaf_value_type
    {
    };

    struct leaf_value_type
    {
        key_type key;
        data_chain_type* data_chain;
    };

    struct node : public node_base
    {
        union {
            nonleaf_value_type  value_nonleaf;
            leaf_value_type     value_leaf;
        };

        node(bool _is_leaf) :
            node_base(_is_leaf)
        {
            if (_is_leaf)
                value_leaf.data_chain = NULL;
        }

        node(const node& r) :
            node_base(r)
        {
        }

        virtual ~node()
        {
            if (is_leaf)
                delete value_leaf.data_chain;
        }

        bool equals(const node& r) const
        {
            if (is_leaf != r.is_leaf)
                return false;

            return true;
        }

        virtual void fill_nonleaf_value(const node_base_ptr& left_node, const node_base_ptr& right_node)
        {
        }

        virtual void dump_value() const
        {
        }

        virtual node_base* create_new(bool leaf) const
        {
            return new node(leaf);
        }

        virtual node_base* clone() const
        {
            return new node(*this);
        }
    };

    segment_tree();
    ~segment_tree();

    bool is_tree_valid() const { return m_valid_tree; }

    void build_tree();

    void insert(key_type begin_key, key_type end_key, data_type* pdata);

private:
    static node* get_node(const node_base_ptr& base_node)
    {
        return static_cast<node*>(base_node.get());
    }

    static void build_leaf_node(const ::std::vector<key_type>& keys, node_base_ptr& left, node_base_ptr& right);

private:
    struct segment_data
    {
        key_type    begin_key;
        key_type    end_key;
        data_type*  pdata;

        segment_data(key_type _beg, key_type _end, data_type* p) :
            begin_key(_beg), end_key(_end), pdata(p) {}
    };

    typedef ::boost::ptr_vector<segment_data> data_array_type;
    data_array_type m_segment_data;

    node_base_ptr   m_root_node;
    node_base_ptr   m_left_leaf;
    node_base_ptr   m_right_leaf;
    bool m_valid_tree:1;
};

template<typename _Key, typename _Data>
segment_tree<_Key, _Data>::segment_tree() :
    m_valid_tree(false)
{
}

template<typename _Key, typename _Data>
segment_tree<_Key, _Data>::~segment_tree()
{
    // Go through all leaf nodes, and disconnect their links.
    node_base* cur_node = m_left_leaf.get();
    do
    {
        node_base* next_node = cur_node->right.get();
        disconnect_node(cur_node);
        cur_node = next_node;
    }
    while (cur_node != m_right_leaf.get());

    disconnect_node(m_right_leaf.get());
}

template<typename _Key, typename _Data>
void segment_tree<_Key, _Data>::build_tree()
{
    using namespace std;

    // In 1st pass, collect unique end-point values and sort them.
    vector<key_type> keys_uniq;
    keys_uniq.reserve(m_segment_data.size()*2);
    typename data_array_type::const_iterator itr, itr_beg = m_segment_data.begin(), itr_end = m_segment_data.end();
    for (itr = itr_beg; itr != itr_end; ++itr)
    {
        cout << itr->begin_key << "," << itr->end_key << ": " << itr->pdata << endl;
        keys_uniq.push_back(itr->begin_key);
        keys_uniq.push_back(itr->end_key);
    }

    // sort and remove duplicates.
    sort(keys_uniq.begin(), keys_uniq.end());
    keys_uniq.erase(unique(keys_uniq.begin(), keys_uniq.end()), keys_uniq.end());

    // debug output.
    cout << "unique keys: ";
    copy(keys_uniq.begin(), keys_uniq.end(), ostream_iterator<key_type>(cout, " "));
    cout << endl;

    // Create leaf nodes with the unique end-point values.
    build_leaf_node(keys_uniq, m_left_leaf, m_right_leaf);

    // debug output.
    {
        cout << "forward: ";
        node* p = get_node(m_left_leaf);
        while (p)
        {
            cout << p->value_leaf.key << " ";
            p = get_node(p->right);
        }
        cout << endl;

        cout << "backward: ";
        p = get_node(m_right_leaf);
        while (p)
        {
            cout << p->value_leaf.key << " ";
            p = get_node(p->left);
        }
        cout << endl;
    }

    // In 2nd pass, "insert" each segment.
    for (itr = itr_beg; itr != itr_end; ++itr)
    {
        key_type key_beg = itr->begin_key;
        key_type key_end = itr->end_key;
        data_type* pdata = itr->pdata;

        node* p = get_node(m_left_leaf);
        while (p)
        {
            if (p->value_leaf.key == key_beg)
            {
                leaf_value_type& v = p->value_leaf;
                if (!v.data_chain)
                    v.data_chain = new data_chain_type;
                v.data_chain->push_back(pdata);
            }
            else if (p->value_leaf.key == key_end)
            {
                // Insert data pointer to the previous node _only when_ the
                // value of the previous node doesn't equal the begin point
                // value.
                node* pprev = get_node(p->left);
                if (pprev && pprev->value_leaf.key != key_beg)
                {
                    leaf_value_type& v = pprev->value_leaf;
                    if (!v.data_chain)
                        v.data_chain = new data_chain_type;
                    v.data_chain->push_back(pdata);
                }
            }
            p = get_node(p->right);
        }
    }

    // debug output
    {
        node* p = get_node(m_left_leaf);
        while (p)
        {
            cout << p->value_leaf.key << ":{ ";
            if (p->value_leaf.data_chain)
            {
                const data_chain_type* pchain = p->value_leaf.data_chain;
                copy(pchain->begin(), pchain->end(), ostream_iterator<data_type*>(cout, " "));
            }
            cout << "}" << endl;
            p = get_node(p->right);
        }
    }
}

template<typename _Key, typename _Data>
void segment_tree<_Key, _Data>::build_leaf_node(const ::std::vector<key_type>& keys, node_base_ptr& left, node_base_ptr& right)
{
    if (keys.empty() || keys.size() < 2)
        // We need at least two keys in order to build tree.
        return;

    typename ::std::vector<key_type>::const_iterator itr = keys.begin(), itr_end = keys.end();

    // left-most node
    left.reset(new node(true));
    get_node(left)->value_leaf.key = *itr;

    // move on to next.
    left->right.reset(new node(true));
    node_base_ptr prev_node = left;
    node_base_ptr cur_node = left->right;
    cur_node->left = prev_node;

    for (++itr; itr != itr_end; ++itr)
    {
        get_node(cur_node)->value_leaf.key = *itr;

        // move on to next
        cur_node->right.reset(new node(true));
        prev_node = cur_node;
        cur_node = cur_node->right;
        cur_node->left = prev_node;
    }

    // Remove the excess node.
    prev_node->right.reset();
    right = prev_node;
}

template<typename _Key, typename _Data>
void segment_tree<_Key, _Data>::insert(key_type begin_key, key_type end_key, data_type* pdata)
{
    if (begin_key >= end_key)
        return;

    m_segment_data.push_back(new segment_data(begin_key, end_key, pdata));
}

}

#endif
<|endoftext|>


<commit_before>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Win32/HardwareInfoImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <windows.h>

#ifdef NAZARA_COMPILER_MSVC
	#include <intrin.h>
#endif

#include <Nazara/Core/Debug.hpp>

void NzHardwareInfoImpl::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4])
{
#if defined(NAZARA_COMPILER_MSVC)
	static_assert(sizeof(nzUInt32) == sizeof(int), "Assertion failed");

	// Visual propose une fonction intrinsèque pour le cpuid
	__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
	// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
	asm volatile ("cpuid" // Besoin d'être volatile ?
	              : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
	              : "a" (functionId), "c" (subFunctionId));                                // input
#else
	NazaraInternalError("Cpuid has been called although it is not supported");
#endif
}

unsigned int NzHardwareInfoImpl::GetProcessorCount()
{
	// Plus simple (et plus portable) que de passer par le CPUID
	SYSTEM_INFO infos;
	GetSystemInfo(&infos);

	return infos.dwNumberOfProcessors;
}

bool NzHardwareInfoImpl::IsCpuidSupported()
{
#ifdef NAZARA_PLATFORM_x64
	return true; // Toujours supporté sur un processeur 64 bits
#else
	#if defined(NAZARA_COMPILER_MSVC)
	int supported;
	__asm
	{
		pushfd
		pop  eax
		mov  ecx, eax
		xor  eax, 0x200000
		push eax
		popfd
		pushfd
		pop  eax
		xor  eax, ecx
		mov  supported, eax
		push ecx
		popfd
	};

	return supported != 0;
	#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
	int supported;
	asm volatile (" pushfl\n"
	              " pop %%eax\n"
	              " mov %%eax, %%ecx\n"
	              " xor $0x200000, %%eax\n"
	              " push %%eax\n"
	              " popfl\n"
	              " pushfl\n"
	              " pop %%eax\n"
	              " xor %%ecx, %%eax\n"
	              " mov %%eax, %0\n"
	              " push %%ecx\n"
	              " popfl"
	              : "=m" (supported)         // output
	              :                          // input
	              : "eax", "ecx", "memory"); // clobbered register

	return supported != 0;
	#else
	return false;
	#endif
#endif
}
<commit_msg>Core/HardwareInfo: Improve accuracy under Windows<commit_after>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Win32/HardwareInfoImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <windows.h>

#ifdef NAZARA_COMPILER_MSVC
	#include <intrin.h>
#endif

#include <Nazara/Core/Debug.hpp>

void NzHardwareInfoImpl::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4])
{
#if defined(NAZARA_COMPILER_MSVC)
	static_assert(sizeof(nzUInt32) == sizeof(int), "Assertion failed");

	// Visual propose une fonction intrinsèque pour le cpuid
	__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
	// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
	asm volatile ("cpuid" // Besoin d'être volatile ?
	              : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
	              : "a" (functionId), "c" (subFunctionId));                                // input
#else
	NazaraInternalError("Cpuid has been called although it is not supported");
#endif
}

unsigned int NzHardwareInfoImpl::GetProcessorCount()
{
	// Plus simple (et plus portable) que de passer par le CPUID
	SYSTEM_INFO infos;
	GetNativeSystemInfo(&infos);

	return infos.dwNumberOfProcessors;
}

bool NzHardwareInfoImpl::IsCpuidSupported()
{
#ifdef NAZARA_PLATFORM_x64
	return true; // Toujours supporté sur un processeur 64 bits
#else
	#if defined(NAZARA_COMPILER_MSVC)
	int supported;
	__asm
	{
		pushfd
		pop  eax
		mov  ecx, eax
		xor  eax, 0x200000
		push eax
		popfd
		pushfd
		pop  eax
		xor  eax, ecx
		mov  supported, eax
		push ecx
		popfd
	};

	return supported != 0;
	#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
	int supported;
	asm volatile (" pushfl\n"
	              " pop %%eax\n"
	              " mov %%eax, %%ecx\n"
	              " xor $0x200000, %%eax\n"
	              " push %%eax\n"
	              " popfl\n"
	              " pushfl\n"
	              " pop %%eax\n"
	              " xor %%ecx, %%eax\n"
	              " mov %%eax, %0\n"
	              " push %%ecx\n"
	              " popfl"
	              : "=m" (supported)         // output
	              :                          // input
	              : "eax", "ecx", "memory"); // clobbered register

	return supported != 0;
	#else
	return false;
	#endif
#endif
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// 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 CONTEXT_H
#define CONTEXT_H

#include <string>
#include <map>
#include <vector>

#include "Types.hpp"

#include "AssemblyFileWriter.hpp"

namespace eddic {

enum PositionType {
    STACK,
    GLOBAL
};

class Position {
    private:
        const PositionType m_type;
        const int m_offset;
        const std::string m_name;

    public:
        Position() : m_type(STACK), m_offset(0), m_name("") {} //TODO Delete that later, just here for compilation
        Position(PositionType type, int offset) : m_type(type), m_offset(offset), m_name("") {}
        Position(PositionType type, std::string name) : m_type(type), m_offset(0), m_name(name) {}

        bool isStack(){
            return m_type == STACK;
        }

        bool isGlobal(){
            return m_type == GLOBAL;
        }

        int offset(){
            return m_offset;
        }

        std::string name(){
            return m_name;
        }
};

class Variable {
    private:
        const std::string m_name;
        const Type m_type;
        const int m_index;
        Position position;

    public:
        Variable(const std::string& name, Type type, int index) : m_name(name), m_type(type), m_index(index) {}
        std::string name() const  {
            return m_name;
        }
        int index() const {
            return m_index;
        }
        Type type() const {
            return m_type;
        }
};

class Context {
    private:
        static std::vector<Context*> contexts;
        static unsigned int currentVariable;

        std::map<std::string, Variable*> variables;
        Context* m_parent;

    public:
        Context() : m_parent(NULL) {
            contexts.push_back(this);
        }
        Context(Context* parent) : m_parent(parent) {
            contexts.push_back(this);
        }
        ~Context();

        bool exists(const std::string& variable) const;
        unsigned int index(const std::string& variable) const;
        Variable* create(const std::string& variable, Type type);
        Variable* find(const std::string& variable);
        void write(AssemblyFileWriter& writer);

        Context* parent() {
            return m_parent;
        }

        static void writeAll(AssemblyFileWriter& writer);
        static void cleanup();
};

class FunctionContext : public Context {

};

class GlobalContext : public Context {

};

class BlockContext : public Context {

};

} //end of eddic

#endif
<commit_msg>Define the interface of the Context<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// 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 CONTEXT_H
#define CONTEXT_H

#include <string>
#include <map>
#include <vector>

#include "Types.hpp"

#include "AssemblyFileWriter.hpp"

namespace eddic {

enum PositionType {
    STACK,
    GLOBAL
};

class Position {
    private:
        const PositionType m_type;
        const int m_offset;
        const std::string m_name;

    public:
        Position() : m_type(STACK), m_offset(0), m_name("") {} //TODO Delete that later, just here for compilation
        Position(PositionType type, int offset) : m_type(type), m_offset(offset), m_name("") {}
        Position(PositionType type, std::string name) : m_type(type), m_offset(0), m_name(name) {}

        bool isStack(){
            return m_type == STACK;
        }

        bool isGlobal(){
            return m_type == GLOBAL;
        }

        int offset(){
            return m_offset;
        }

        std::string name(){
            return m_name;
        }
};

class Variable {
    private:
        const std::string m_name;
        const Type m_type;
        const int m_index;
        Position position;

    public:
        Variable(const std::string& name, Type type, int index) : m_name(name), m_type(type), m_index(index) {}
        std::string name() const  {
            return m_name;
        }
        int index() const {
            return m_index;
        }
        Type type() const {
            return m_type;
        }
};

class Context {
    private:
        static std::vector<Context*> contexts;
        static unsigned int currentVariable;

        std::map<std::string, Variable*> variables;
        Context* m_parent;

    public:
        Context() : m_parent(NULL) {
            contexts.push_back(this);
        }
        Context(Context* parent) : m_parent(parent) {
            contexts.push_back(this);
        }
        ~Context();

        bool exists(const std::string& variable) const;
        unsigned int index(const std::string& variable) const;
        Variable* create(const std::string& variable, Type type);
        Variable* find(const std::string& variable);
        void write(AssemblyFileWriter& writer);

        Context* parent() {
            return m_parent;
        }

        static void writeAll(AssemblyFileWriter& writer);
        static void cleanup();
};

//TODO Rename to Context when finished the implementation
class TempContext {
    private:
        static std::vector<TempContext*> contexts;

        std::map<std::string, Variable*> variables;
        TempContext* m_parent;

    public:
       virtual void addVariable(const std::string a, Type type);
       virtual bool exists(const std::string& a) const;
       virtual Variable* getVariable(std::string& variable) const;

        TempContext* parent() const  {
            return m_parent;
        }
};

class FunctionContext : public TempContext {

};

class GlobalContext : public TempContext {

};

class BlockContext : public TempContext {

};

} //end of eddic

#endif
<|endoftext|>


<commit_before>//
//  GPTimer.h
//  Bedrock
//
//  Created by Eric Yanush on 2016-01-17.
//  Copyright © 2016 EricYanush. All rights reserved.
//

#ifndef GPTimer_h
#define GPTimer_h

#include "types.hpp"

namespace Bedrock {
    template <typename width_t>
    class GPTimer {
    public:

        void setPrescaler(uint16_t prescaler) {
            PSC = prescaler;
        }

        uint16_t getPrescaler() {
            return (uint16_t)PSC;
        }

        void setReload(width_t reloadVal) {
            ARR = reloadVal;
        }

        width_t getReload() {
            return ARR;
        }

        width_t getCount() {
            return (width_t)CNT;
        }

        void enable() {
            CR1 |= 0x1;
        }

        void disable() {
            CR1 &= ~(0x1);
        }

        bool isEnabled() {
            return (CR1 & ENABLE) == ENABLE;
        }

        void enableUpdateInterrupt() {
            DIER |= (ENABLE << 0);
        }

        void disableUpdateInterrupt() {
            DIER &= ~(ENABLE << 0);
        }

        bool isUpdateInterruptEnabled() {
            return (DIER & ENABLE) == ENABLE;
        }

        bool isUpdateInterruptPending() {
            return (SR & 0x1) == 0x1;
        }

        void ackUpdate() {
            SR &= ~(1 << 0);
        }

        void ackTrigger() {
            SR &= ~(1 << 6);
        }

        dev_reg32_t CR1;
        dev_reg32_t CR2;
        dev_reg32_t SMCR;
        dev_reg32_t DIER;
        dev_reg32_t SR;
        dev_reg32_t EGR;
        dev_reg32_t CCMR[2];
        dev_reg32_t CCER;
        dev_reg32_t CNT;
        dev_reg32_t PSC;
        dev_reg32_t ARR;
        uint32_t _pad1;
        dev_reg32_t CCR[4];
        uint32_t _pad2;
        dev_reg32_t DCR;
        dev_reg32_t DMAR;
    };

    template <typename width_t>
    using GPTimerProvider = GPTimer<width_t>& (*)(void);
}

#endif /* GPTimer_h */
<commit_msg>Add input capture handling methods to GPTimer class<commit_after>//
//  GPTimer.h
//  Bedrock
//
//  Created by Eric Yanush on 2016-01-17.
//  Copyright © 2016 EricYanush. All rights reserved.
//

#ifndef GPTimer_h
#define GPTimer_h

#include "types.hpp"

namespace Bedrock {
    template <typename width_t>
    class GPTimer {
    public:

        void setPrescaler(uint16_t prescaler) {
            PSC = prescaler;
        }

        uint16_t getPrescaler() {
            return (uint16_t)PSC;
        }

        void setReload(width_t reloadVal) {
            ARR = reloadVal;
        }

        width_t getReload() {
            return ARR;
        }

        width_t getCount() {
            return (width_t)CNT;
        }

        void enable() {
            CR1 |= 0x1;
        }

        void disable() {
            CR1 &= ~(0x1);
        }

        bool isEnabled() {
            return (CR1 & ENABLE) == ENABLE;
        }

        void enableUpdateInterrupt() {
            DIER |= (ENABLE << 0);
        }

        void disableUpdateInterrupt() {
            DIER &= ~(ENABLE << 0);
        }

        bool isUpdateInterruptEnabled() {
            return (DIER & ENABLE) == ENABLE;
        }

        bool isUpdateInterruptPending() {
            return (SR & 0x1) == 0x1;
        }

        void ackUpdate() {
            SR &= ~(1 << 0);
        }

        void ackTrigger() {
            SR &= ~(1 << 6);
        }

        enum class CapCompSelection : uint8_t
        {
            OUTPUT = 0b00,
            IN_DEF = 0b01,
            IN_ALT = 0b10,
            IN_TRC = 0b11
        };

        void setCapCompSelection(uint8_t channel, CapCompSelection sel)
        {
            uint8_t regIndex = channel/3;
            uint8_t bitOffset = ((channel - 1) % 2) * 8;

            CCMR[regIndex] &= ~(0b11 << bitOffset);
            CCMR[regIndex] |= static_cast<uint8_t>(sel) << bitOffset;
        }

        void enableCapCompChannel(uint8_t channel)
        {
            uint8_t bitOffset = (channel - 1) * 4;
            CCER |= (ENABLE << bitOffset);
        }

        void disableCapCompChannel(uint8_t channel)
        {
            uint8_t bitOffset = (channel - 1) * 4;
            CCER &= ~(ENABLE << bitOffset);
        }

        width_t readInputCaptureChannel(uint8_t channel)
        {
            return CCR[channel];
        }

        void enableCaptureEvent(uint8_t channel)
        {
            EGR |= ENABLE << channel;
        }

        void disableCaptureEvent(uint8_t channel)
        {
            EGR &= ~(ENABLE << channel);
        }

        bool captureCompleteForChannel(uint8_t channel)
        {
            return (SR >> channel) & 0x1;
        }

        void ackCaptureForChannel(uint8_t channel)
        {
            SR &= ~(0x1 << channel);
        }

        dev_reg32_t CR1;
        dev_reg32_t CR2;
        dev_reg32_t SMCR;
        dev_reg32_t DIER;
        dev_reg32_t SR;
        dev_reg32_t EGR;
        dev_reg32_t CCMR[2];
        dev_reg32_t CCER;
        dev_reg32_t CNT;
        dev_reg32_t PSC;
        dev_reg32_t ARR;
        uint32_t _pad1;
        dev_reg32_t CCR[4];
        uint32_t _pad2;
        dev_reg32_t DCR;
        dev_reg32_t DMAR;
    };

    template <typename width_t>
    using GPTimerProvider = GPTimer<width_t>& (*)(void);
}

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


<commit_before><commit_msg>vea_unittest: Remove vector reserve<commit_after><|endoftext|>